Annotation of src/usr.bin/pmdb/pmdb.c, Revision 1.4
1.4 ! art 1: /* $OpenBSD: pmdb.c,v 1.3 2002/03/15 18:04:41 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 },
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:
77: int
78: main(int argc, char **argv)
79: {
80: extern const char *__progname;
81: struct pstate ps;
82: int i, ncmds;
83: int status;
84: void *cm;
85: char *pmenv;
86: int level;
87:
88: if (argc < 2) {
89: fprintf(stderr, "Usage: %s <program> args\n", __progname);
90: exit(1);
91: }
92:
93: if ((pmenv = getenv("IN_PMDB")) != NULL) {
94: level = atoi(pmenv);
95: level++;
96: } else
97: level = 0;
98:
99: if (level > 0)
100: asprintf(&prompt_add, "(%d)", level);
101: asprintf(&pmenv, "%d", level);
102: setenv("IN_PMDB", pmenv, 1);
103:
104: ps.ps_pid = 0;
105: ps.ps_state = NONE;
106: ps.ps_argc = --argc;
107: ps.ps_argv = ++argv;
108: ps.ps_flags = 0;
109: ps.ps_signum = 0;
110: ps.ps_npc = 1;
111: TAILQ_INIT(&ps.ps_bkpts);
112: TAILQ_INIT(&ps.ps_sstep_cbs);
113:
114: signal(SIGINT, SIG_IGN);
115:
116: ncmds = sizeof(cmds)/sizeof(cmds[0]);
117:
118: for (i = 0; i < ncmds; i++)
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:
127: cm = cmdinit(cmds, ncmds);
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;
256: }
257:
258: printf("%s(", name);
259: for (j = 0; j < mfr.nargs; j++) {
260: printf("0x%lx", mfr.args[j]);
261: if (j < mfr.nargs - 1)
262: printf(", ");
263: }
264: printf(")+0x%lx\n", offs);
265: }
266: return 0;
267: }
268:
269: static int
270: cmd_quit(int argc, char **argv, void *arg)
271: {
272: struct pstate *ps = arg;
273:
274: ps->ps_flags |= PSF_KILL;
275:
276: if (process_kill(ps))
277: return 1;
278:
279: ps->ps_state = TERMINATED;
280: return 1;
281: }
282:
283: /*
284: * Perform command completion.
285: * Pretty simple. if there are spaces in "buf", the last string is a symbol
286: * otherwise it's a command.
287: */
288: int
289: cmd_complt(char *buf, size_t buflen)
290: {
291: struct clit *match;
292: char *start;
293: int command;
294: int i, j, len;
295: int onlymatch;
296:
297: command = (strchr(buf, ' ') == NULL);
298:
299: if (!command) {
300: /* XXX - can't handle symbols yet. */
301: return -1;
302: }
303:
304: start = buf;
305: len = strlen(buf);
306:
307: match = NULL;
308: for (i = 0; i < sizeof(cmds) / sizeof(cmds[i]); i++) {
309: if (strncmp(start, cmds[i].cmd, len) == 0) {
310: struct clit *cmdp;
311:
312: cmdp = &cmds[i];
313: if (match == NULL) {
314: onlymatch = 1;
315: match = cmdp;
316: strlcpy(buf, match->cmd, buflen);
317: continue;
318: }
319: onlymatch = 0;
320: for (j = len; j < buflen; j++) {
321: if (buf[j] != cmdp->cmd[j]) {
322: buf[j] = '\0';
323: break;
324: }
325: if (cmdp->cmd[j] == '\0')
326: break;
327: }
328: }
329: }
330:
331: /*
332: * Be nice. If there could be arguments for this command and it's
333: * the only match append a space.
334: */
335: if (match && onlymatch /*&& match->maxargc > 0*/)
336: strlcat(buf, " ", buflen);
337:
338: return (match && onlymatch) ? 0 : -1;
339: }
340:
341: /*
342: * The "stadard" wrapper
343: */
344: void *
345: emalloc(size_t sz)
346: {
347: void *ret;
348: if ((ret = malloc(sz)) == NULL)
349: err(1, "malloc");
350: return (ret);
351: }