xref: /freebsd/sys/ddb/db_expr.c (revision f5463265955b829775bbb32e1fd0bc11dafc36ce)
1 /*-
2  * SPDX-License-Identifier: MIT-CMU
3  *
4  * Mach Operating System
5  * Copyright (c) 1991,1990 Carnegie Mellon University
6  * All Rights Reserved.
7  *
8  * Permission to use, copy, modify and distribute this software and its
9  * documentation is hereby granted, provided that both the copyright
10  * notice and this permission notice appear in all copies of the
11  * software, derivative works or modified versions, and any portions
12  * thereof, and that both notices appear in supporting documentation.
13  *
14  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS
15  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
16  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
17  *
18  * Carnegie Mellon requests users of this software to return to
19  *
20  *  Software Distribution Coordinator  or  Software.Distribution@CS.CMU.EDU
21  *  School of Computer Science
22  *  Carnegie Mellon University
23  *  Pittsburgh PA 15213-3890
24  *
25  * any improvements or extensions that they make and grant Carnegie the
26  * rights to redistribute these changes.
27  */
28 /*
29  *	Author: David B. Golub, Carnegie Mellon University
30  *	Date:	7/90
31  */
32 
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 
36 #include <ddb/ddb.h>
37 #include <ddb/db_lex.h>
38 #include <ddb/db_access.h>
39 #include <ddb/db_command.h>
40 
41 static bool	db_add_expr(db_expr_t *valuep);
42 static bool	db_mult_expr(db_expr_t *valuep);
43 static bool	db_shift_expr(db_expr_t *valuep);
44 static bool	db_term(db_expr_t *valuep);
45 static bool	db_unary(db_expr_t *valuep);
46 static bool	db_logical_or_expr(db_expr_t *valuep);
47 static bool	db_logical_and_expr(db_expr_t *valuep);
48 static bool	db_logical_relation_expr(db_expr_t *valuep);
49 
50 static bool
51 db_term(db_expr_t *valuep)
52 {
53 	int	t;
54 
55 	t = db_read_token();
56 	if (t == tIDENT) {
57 	    if (!db_value_of_name(db_tok_string, valuep) &&
58 		!db_value_of_name_pcpu(db_tok_string, valuep) &&
59 		!db_value_of_name_vnet(db_tok_string, valuep)) {
60 		db_printf("Symbol '%s' not found\n", db_tok_string);
61 		db_error(NULL);
62 		/*NOTREACHED*/
63 	    }
64 	    return (true);
65 	}
66 	if (t == tNUMBER) {
67 	    *valuep = (db_expr_t)db_tok_number;
68 	    return (true);
69 	}
70 	if (t == tDOT) {
71 	    *valuep = (db_expr_t)db_dot;
72 	    return (true);
73 	}
74 	if (t == tDOTDOT) {
75 	    *valuep = (db_expr_t)db_prev;
76 	    return (true);
77 	}
78 	if (t == tPLUS) {
79 	    *valuep = (db_expr_t) db_next;
80 	    return (true);
81 	}
82 	if (t == tDITTO) {
83 	    *valuep = (db_expr_t)db_last_addr;
84 	    return (true);
85 	}
86 	if (t == tDOLLAR) {
87 	    if (!db_get_variable(valuep))
88 		return (false);
89 	    return (true);
90 	}
91 	if (t == tLPAREN) {
92 	    if (!db_expression(valuep)) {
93 		db_printf("Expression syntax error after '%c'\n", '(');
94 		db_error(NULL);
95 		/*NOTREACHED*/
96 	    }
97 	    t = db_read_token();
98 	    if (t != tRPAREN) {
99 		db_printf("Expression syntax error -- expected '%c'\n", ')');
100 		db_error(NULL);
101 		/*NOTREACHED*/
102 	    }
103 	    return (true);
104 	}
105 	db_unread_token(t);
106 	return (false);
107 }
108 
109 static bool
110 db_unary(db_expr_t *valuep)
111 {
112 	int	t;
113 
114 	t = db_read_token();
115 	if (t == tMINUS) {
116 	    if (!db_unary(valuep)) {
117 		db_printf("Expression syntax error after '%c'\n", '-');
118 		db_error(NULL);
119 		/*NOTREACHED*/
120 	    }
121 	    *valuep = -*valuep;
122 	    return (true);
123 	}
124 	if (t == tEXCL) {
125 	    if (!db_unary(valuep)) {
126 		db_printf("Expression syntax error after '%c'\n", '!');
127 		db_error(NULL);
128 		/* NOTREACHED  */
129 	    }
130 	    *valuep = (!(*valuep));
131 	    return (true);
132 	}
133 	if (t == tBIT_NOT) {
134 	    if (!db_unary(valuep)) {
135 		db_printf("Expression syntax error after '%c'\n", '~');
136 		db_error(NULL);
137 		/* NOTREACHED */
138 	    }
139 	    *valuep = (~(*valuep));
140 	    return (true);
141 	}
142 	if (t == tSTAR) {
143 	    /* indirection */
144 	    if (!db_unary(valuep)) {
145 		db_printf("Expression syntax error after '%c'\n", '*');
146 		db_error(NULL);
147 		/*NOTREACHED*/
148 	    }
149 	    *valuep = db_get_value((db_addr_t)*valuep, sizeof(void *),
150 		false);
151 	    return (true);
152 	}
153 	db_unread_token(t);
154 	return (db_term(valuep));
155 }
156 
157 static bool
158 db_mult_expr(db_expr_t *valuep)
159 {
160 	db_expr_t	lhs, rhs;
161 	int		t;
162 
163 	if (!db_unary(&lhs))
164 	    return (false);
165 
166 	t = db_read_token();
167 	while (t == tSTAR || t == tSLASH || t == tPCT || t == tHASH ||
168 	    t == tBIT_AND ) {
169 	    if (!db_term(&rhs)) {
170 		db_printf("Expression syntax error after '%c'\n",
171 		    t == tSTAR ? '*' : t == tSLASH ? '/' : t == tPCT ? '%' :
172 		    t == tHASH ? '#' : '&');
173 		db_error(NULL);
174 		/*NOTREACHED*/
175 	    }
176 	    switch(t)  {
177 		case tSTAR:
178 		    lhs *= rhs;
179 		    break;
180 		case tBIT_AND:
181 		    lhs &= rhs;
182 		    break;
183 		default:
184 		    if (rhs == 0) {
185 			db_error("Division by 0\n");
186 			/*NOTREACHED*/
187 		    }
188 		    if (t == tSLASH)
189 			lhs /= rhs;
190 		    else if (t == tPCT)
191 			lhs %= rhs;
192 		    else
193 			lhs = roundup(lhs, rhs);
194 	    }
195 	    t = db_read_token();
196 	}
197 	db_unread_token(t);
198 	*valuep = lhs;
199 	return (true);
200 }
201 
202 static bool
203 db_add_expr(db_expr_t *valuep)
204 {
205 	db_expr_t	lhs, rhs;
206 	int		t;
207 
208 	if (!db_mult_expr(&lhs))
209 	    return (false);
210 
211 	t = db_read_token();
212 	while (t == tPLUS || t == tMINUS || t == tBIT_OR) {
213 	    if (!db_mult_expr(&rhs)) {
214 		db_printf("Expression syntax error after '%c'\n",
215 		    t == tPLUS ? '+' : t == tMINUS ? '-' : '|');
216 		db_error(NULL);
217 		/*NOTREACHED*/
218 	    }
219 	    switch (t) {
220 	    case tPLUS:
221 		lhs += rhs;
222 		break;
223 	    case tMINUS:
224 		lhs -= rhs;
225 		break;
226 	    case tBIT_OR:
227 		lhs |= rhs;
228 		break;
229 	    default:
230 		__assert_unreachable();
231 	    }
232 	    t = db_read_token();
233 	}
234 	db_unread_token(t);
235 	*valuep = lhs;
236 	return (true);
237 }
238 
239 static bool
240 db_shift_expr(db_expr_t *valuep)
241 {
242 	db_expr_t	lhs, rhs;
243 	int		t;
244 
245 	if (!db_add_expr(&lhs))
246 		return (false);
247 	t = db_read_token();
248 	while (t == tSHIFT_L || t == tSHIFT_R) {
249 	    if (!db_add_expr(&rhs)) {
250 		db_printf("Expression syntax error after '%s'\n",
251 		    t == tSHIFT_L ? "<<" : ">>");
252 		db_error(NULL);
253 		/*NOTREACHED*/
254 	    }
255 	    if (rhs < 0) {
256 		db_printf("Negative shift amount %jd\n", (intmax_t)rhs);
257 		db_error(NULL);
258 		/*NOTREACHED*/
259 	    }
260 	    if (t == tSHIFT_L)
261 		lhs <<= rhs;
262 	    else {
263 		/* Shift right is unsigned */
264 		lhs = (db_addr_t)lhs >> rhs;
265 	    }
266 	    t = db_read_token();
267 	}
268 	db_unread_token(t);
269 	*valuep = lhs;
270 	return (true);
271 }
272 
273 static bool
274 db_logical_relation_expr(
275 	db_expr_t *valuep)
276 {
277 	db_expr_t	lhs, rhs;
278 	int		t;
279 
280 	if (!db_shift_expr(&lhs))
281 	    return (false);
282 
283 	t = db_read_token();
284 	while (t == tLOG_EQ || t == tLOG_NOT_EQ || t == tGREATER ||
285 	    t == tGREATER_EQ || t == tLESS || t == tLESS_EQ) {
286 	    if (!db_shift_expr(&rhs)) {
287 		db_printf("Expression syntax error after '%s'\n",
288 		    t == tLOG_EQ ? "==" : t == tLOG_NOT_EQ ? "!=" :
289 		    t == tGREATER ? ">" : t == tGREATER_EQ ? ">=" :
290 		    t == tLESS ? "<" : "<=");
291 		db_error(NULL);
292 		/*NOTREACHED*/
293 	    }
294 	    switch(t) {
295 		case tLOG_EQ:
296 		    lhs = (lhs == rhs);
297 		    break;
298 		case tLOG_NOT_EQ:
299 		    lhs = (lhs != rhs);
300 		    break;
301 		case tGREATER:
302 		    lhs = (lhs > rhs);
303 		    break;
304 		case tGREATER_EQ:
305 		    lhs = (lhs >= rhs);
306 		    break;
307 		case tLESS:
308 		    lhs = (lhs < rhs);
309 		    break;
310 		case tLESS_EQ:
311 		    lhs = (lhs <= rhs);
312 		    break;
313 		default:
314 		    __assert_unreachable();
315 	    }
316 	    t = db_read_token();
317 	}
318 	db_unread_token(t);
319 	*valuep = lhs;
320 	return (true);
321 }
322 
323 static bool
324 db_logical_and_expr(
325 	db_expr_t *valuep)
326 {
327 	db_expr_t	lhs, rhs;
328 	int		t;
329 
330 	if (!db_logical_relation_expr(&lhs))
331 	    return (false);
332 
333 	t = db_read_token();
334 	while (t == tLOG_AND) {
335 	    if (!db_logical_relation_expr(&rhs)) {
336 		db_printf("Expression syntax error after '%s'\n", "&&");
337 		db_error(NULL);
338 		/*NOTREACHED*/
339 	    }
340 	    lhs = (lhs && rhs);
341 	    t = db_read_token();
342 	}
343 	db_unread_token(t);
344 	*valuep = lhs;
345 	return (true);
346 }
347 
348 static bool
349 db_logical_or_expr(
350 	db_expr_t *valuep)
351 {
352 	db_expr_t	lhs, rhs;
353 	int		t;
354 
355 	if (!db_logical_and_expr(&lhs))
356 		return(false);
357 
358 	t = db_read_token();
359 	while (t == tLOG_OR) {
360 		if (!db_logical_and_expr(&rhs)) {
361 			db_printf("Expression syntax error after '%s'\n", "||");
362 			db_error(NULL);
363 			/*NOTREACHED*/
364 		}
365 		lhs = (lhs || rhs);
366 		t = db_read_token();
367 	}
368 	db_unread_token(t);
369 	*valuep = lhs;
370 	return (true);
371 }
372 
373 int
374 db_expression(db_expr_t *valuep)
375 {
376 	return (db_logical_or_expr(valuep));
377 }
378