xref: /plan9/sys/src/cmd/db/command.c (revision c93608cc76758b2be624199c6208a0f90bad298d)
1 /*
2  *
3  *	debugger
4  *
5  */
6 
7 #include "defs.h"
8 #include "fns.h"
9 
10 char	BADEQ[] = "unexpected `='";
11 
12 BOOL	executing;
13 extern	Rune	*lp;
14 
15 char	eqformat[ARB] = "z";
16 char	stformat[ARB] = "zMi";
17 
18 ADDR	ditto;
19 
20 ADDR	dot;
21 int	dotinc;
22 WORD	adrval, cntval, loopcnt;
23 int	adrflg, cntflg;
24 
25 /* command decoding */
26 
command(char * buf,int defcom)27 command(char *buf, int defcom)
28 {
29 	char	*reg;
30 	char	savc;
31 	Rune	*savlp=lp;
32 	char	savlc = lastc;
33 	char	savpc = peekc;
34 	static char lastcom = '=', savecom = '=';
35 
36 	if (defcom == 0)
37 		defcom = lastcom;
38 	if (buf) {
39 		if (*buf==EOR)
40 			return(FALSE);
41 		clrinp();
42 		lp=(Rune*)buf;
43 	}
44 	do {
45 		adrflg=expr(0);		/* first address */
46 		if (adrflg){
47 			dot=expv;
48 			ditto=expv;
49 		}
50 		adrval=dot;
51 
52 		if (rdc()==',' && expr(0)) {	/* count */
53 			cntflg=TRUE;
54 			cntval=expv;
55 		} else {
56 			cntflg=FALSE;
57 			cntval=1;
58 			reread();
59 		}
60 
61 		if (!eol(rdc()))
62 			lastcom=lastc;		/* command */
63 		else {
64 			if (adrflg==0)
65 				dot=inkdot(dotinc);
66 			reread();
67 			lastcom=defcom;
68 		}
69 		switch(lastcom) {
70 		case '/':
71 		case '=':
72 		case '?':
73 			savecom = lastcom;
74 			acommand(lastcom);
75 			break;
76 
77 		case '>':
78 			lastcom = savecom;
79 			savc=rdc();
80 			if (reg=regname(savc))
81 				rput(cormap, reg, dot);
82 			else
83 				error("bad variable");
84 			break;
85 
86 		case '!':
87 			lastcom=savecom;
88 			shell();
89 			break;
90 
91 		case '$':
92 			lastcom=savecom;
93 			printtrace(nextchar());
94 			break;
95 
96 		case ':':
97 			if (!executing) {
98 				executing=TRUE;
99 				subpcs(nextchar());
100 				executing=FALSE;
101 				lastcom=savecom;
102 			}
103 			break;
104 
105 		case 0:
106 			prints(DBNAME);
107 			break;
108 
109 		default:
110 			error("bad command");
111 		}
112 		flushbuf();
113 	} while (rdc()==';');
114 	if (buf == 0)
115 		reread();
116 	else {
117 		clrinp();
118 		lp=savlp;
119 		lastc = savlc;
120 		peekc = savpc;
121 	}
122 
123 	if(adrflg)
124 		return dot;
125 	return 1;
126 }
127 
128 /*
129  * [/?][wml]
130  */
131 
132 void
acommand(int pc)133 acommand(int pc)
134 {
135 	int eqcom;
136 	Map *map;
137 	char *fmt;
138 	char buf[512];
139 
140 	if (pc == '=') {
141 		eqcom = 1;
142 		fmt = eqformat;
143 		map = dotmap;
144 	} else {
145 		eqcom = 0;
146 		fmt = stformat;
147 		if (pc == '/')
148 			map = cormap;
149 		else
150 			map = symmap;
151 	}
152 	if (!map) {
153 		snprint(buf, sizeof(buf), "no map for %c", pc);
154 		error(buf);
155 	}
156 
157 	switch (rdc())
158 	{
159 	case 'm':
160 		if (eqcom)
161 			error(BADEQ);
162 		cmdmap(map);
163 		break;
164 
165 	case 'L':
166 	case 'l':
167 		if (eqcom)
168 			error(BADEQ);
169 		cmdsrc(lastc, map);
170 		break;
171 
172 	case 'W':
173 	case 'w':
174 		if (eqcom)
175 			error(BADEQ);
176 		cmdwrite(lastc, map);
177 		break;
178 
179 	default:
180 		reread();
181 		getformat(fmt);
182 		scanform(cntval, !eqcom, fmt, map, eqcom);
183 	}
184 }
185 
186 void
cmdsrc(int c,Map * map)187 cmdsrc(int c, Map *map)
188 {
189 	ulong w;
190 	long locval, locmsk;
191 	ADDR savdot;
192 	ushort sh;
193 	char buf[512];
194 	int ret;
195 
196 	if (c == 'L')
197 		dotinc = 4;
198 	else
199 		dotinc = 2;
200 	savdot=dot;
201 	expr(1);
202 	locval=expv;
203 	if (expr(0))
204 		locmsk=expv;
205 	else
206 		locmsk = ~0;
207 	if (c == 'L')
208 		while ((ret = get4(map, dot, &w)) > 0 &&  (w&locmsk) != locval)
209 			dot = inkdot(dotinc);
210 	else
211 		while ((ret = get2(map, dot, &sh)) > 0 && (sh&locmsk) != locval)
212 			dot = inkdot(dotinc);
213 	if (ret < 0) {
214 		dot=savdot;
215 		error("%r");
216 	}
217 	symoff(buf, 512, dot, CANY);
218 	dprint(buf);
219 }
220 
221 static char badwrite[] = "can't write process memory or text image";
222 
223 void
cmdwrite(int wcom,Map * map)224 cmdwrite(int wcom, Map *map)
225 {
226 	ADDR savdot;
227 	char *format;
228 	int pass;
229 
230 	if (wcom == 'w')
231 		format = "x";
232 	else
233 		format = "X";
234 	expr(1);
235 	pass = 0;
236 	do {
237 		pass++;
238 		savdot=dot;
239 		exform(1, 1, format, map, 0, pass);
240 		dot=savdot;
241 		if (wcom == 'W') {
242 			if (put4(map, dot, expv) <= 0)
243 				error(badwrite);
244 		} else {
245 			if (put2(map, dot, expv) <= 0)
246 				error(badwrite);
247 		}
248 		savdot=dot;
249 		dprint("=%8t");
250 		exform(1, 0, format, map, 0, pass);
251 		newline();
252 	} while (expr(0));
253 	dot=savdot;
254 }
255 
256 /*
257  * collect a register name; return register offset
258  * this is not what i'd call a good division of labour
259  */
260 
261 char *
regname(int regnam)262 regname(int regnam)
263 {
264 	static char buf[64];
265 	char *p;
266 	int c;
267 
268 	p = buf;
269 	*p++ = regnam;
270 	while (isalnum(c = readchar())) {
271 		if (p >= buf+sizeof(buf)-1)
272 			error("register name too long");
273 		*p++ = c;
274 	}
275 	*p = 0;
276 	reread();
277 	return (buf);
278 }
279 
280 /*
281  * shell escape
282  */
283 
284 void
shell(void)285 shell(void)
286 {
287 	int	rc, unixpid;
288 	char *argp = (char*)lp;
289 
290 	while (lastc!=EOR)
291 		rdc();
292 	if ((unixpid=fork())==0) {
293 		*lp=0;
294 		execl("/bin/rc", "rc", "-c", argp, nil);
295 		exits("execl");				/* botch */
296 	} else if (unixpid == -1) {
297 		error("cannot fork");
298 	} else {
299 		mkfault = 0;
300 		while ((rc = waitpid()) != unixpid){
301 			if(rc == -1 && mkfault){
302 				mkfault = 0;
303 				continue;
304 			}
305 			break;
306 		}
307 		prints("!");
308 		reread();
309 	}
310 }
311