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