xref: /illumos-gate/usr/src/cmd/mdb/common/mdb/mdb_grammar.y (revision 8a6a72fd51dfee674c6daa8a222f68b1532516ab)
1 %{
2 /*
3  * CDDL HEADER START
4  *
5  * The contents of this file are subject to the terms of the
6  * Common Development and Distribution License (the "License").
7  * You may not use this file except in compliance with the License.
8  *
9  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10  * or http://www.opensolaris.org/os/licensing.
11  * See the License for the specific language governing permissions
12  * and limitations under the License.
13  *
14  * When distributing Covered Code, include this CDDL HEADER in each
15  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16  * If applicable, add the following below this CDDL HEADER, with the
17  * fields enclosed by brackets "[]" replaced with your own identifying
18  * information: Portions Copyright [yyyy] [name of copyright owner]
19  *
20  * CDDL HEADER END
21  *
22  */
23 /*
24  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
25  * Use is subject to license terms.
26  */
27 
28 #pragma ident	"%Z%%M%	%I%	%E% SMI"
29 
30 #include <mdb/mdb_types.h>
31 #include <mdb/mdb_debug.h>
32 #include <mdb/mdb_shell.h>
33 #include <mdb/mdb_string.h>
34 #include <mdb/mdb_frame.h>
35 #include <mdb/mdb_lex.h>
36 #include <mdb/mdb_io.h>
37 #include <mdb/mdb_nv.h>
38 #include <mdb/mdb.h>
39 
40 /*
41  * Utility routines to fetch values from the target's virtual address space
42  * and object file, respectively.  These are called from the handlers for
43  * the * /.../ and % /.../ code below.
44  */
45 
46 static void
47 vfetch(void *buf, size_t nbytes, uintptr_t addr)
48 {
49 	if (mdb_tgt_vread(mdb.m_target, buf, nbytes, addr) != nbytes)
50 		yyperror("failed to read from address %p", addr);
51 }
52 
53 static void
54 ffetch(void *buf, size_t nbytes, uintptr_t addr)
55 {
56 	if (mdb_tgt_fread(mdb.m_target, buf, nbytes, addr) != nbytes)
57 		yyperror("failed to read from address %p", addr);
58 }
59 
60 /*
61  * Because we define YYMAXDEPTH as zero below, we have to provide a YYEXPAND()
62  * function to expand our yys and yyv variables.  For simplicity, we currently
63  * define these structures statically; a more complex solution can be defined if
64  * it is ever needed.  If we return 'val', yacc assumes resize has failed.
65  */
66 static int
67 yyexpand(int val)
68 {
69 	return (val ? val : YYMAXDEPTH);
70 }
71 #define	YYEXPAND	yyexpand
72 
73 /*
74  * This will cause the rest of the yacc code to assume that yys and yyv are
75  * pointers, not static arrays.
76  */
77 #undef	YYMAXDEPTH
78 #define	YYMAXDEPTH	0
79 %}
80 
81 %union {
82 	char *l_string;
83 	char l_char;
84 	uintmax_t l_immediate;
85 	mdb_var_t *l_var;
86 	mdb_idcmd_t *l_dcmd;
87 }
88 
89 %token	<l_string>	MDB_TOK_SYMBOL
90 %token	<l_string>	MDB_TOK_STRING
91 %token	<l_char>	MDB_TOK_CHAR
92 %token	<l_immediate>	MDB_TOK_IMMEDIATE
93 %token	<l_dcmd>	MDB_TOK_DCMD
94 %token	<l_var>		MDB_TOK_VAR_REF
95 %token	<l_immediate>	MDB_TOK_LEXPR
96 %token	<l_immediate>	MDB_TOK_REXPR
97 %token	<l_immediate>	MDB_TOK_COR1_DEREF
98 %token	<l_immediate>	MDB_TOK_COR2_DEREF
99 %token	<l_immediate>	MDB_TOK_COR4_DEREF
100 %token	<l_immediate>	MDB_TOK_COR8_DEREF
101 %token	<l_immediate>	MDB_TOK_OBJ1_DEREF
102 %token	<l_immediate>	MDB_TOK_OBJ2_DEREF
103 %token	<l_immediate>	MDB_TOK_OBJ4_DEREF
104 %token	<l_immediate>	MDB_TOK_OBJ8_DEREF
105 
106 %left	'|'
107 %left	'^'
108 %left	'&'
109 %left	MDB_TOK_EQUAL MDB_TOK_NOTEQUAL
110 %left	MDB_TOK_LSHIFT MDB_TOK_RSHIFT
111 %left	'-' '+'
112 %left	'*' '%' '#'
113 
114 %right	MDB_COR_VALUE
115 %right	MDB_OBJ_VALUE
116 %right	MDB_INT_NEGATE
117 %right	MDB_BIT_COMPLEMENT
118 %right	MDB_LOG_NEGATE
119 %right	MDB_VAR_REFERENCE
120 
121 %type	<l_immediate>	expression
122 %type	<l_dcmd>	command
123 
124 %%
125 statement_list:	/* Empty */
126 	|	statement_list statement { return (0); }
127 	;
128 
129 terminator:	'\n'
130 	|	';'
131 
132 statement:	pipeline shell_pipe terminator {
133 			if (!mdb_call(mdb_nv_get_value(mdb.m_dot), 1, 0))
134 				return (0);
135 		}
136 
137 	|	expression pipeline shell_pipe terminator {
138 			if (!mdb_call($1, 1, DCMD_ADDRSPEC))
139 				return (0);
140 		}
141 
142 	|	expression ',' expression pipeline shell_pipe terminator {
143 			if (!mdb_call($1, $3, DCMD_ADDRSPEC | DCMD_LOOP))
144 				return (0);
145 		}
146 
147 	|	',' expression pipeline shell_pipe terminator {
148 			if (!mdb_call(mdb_nv_get_value(mdb.m_dot), $2,
149 			    DCMD_LOOP))
150 				return (0);
151 		}
152 
153 	|	expression terminator {
154 			mdb_frame_t *pfp = mdb_frame_pipe();
155 			/*
156 			 * The handling of naked expressions is slightly tricky:
157 			 * in a string context, we want to just set dot to the
158 			 * expression value.  In a pipe context, we also set
159 			 * dot but need to record the address in the right-
160 			 * hand command's addrv and update any vcbs that are
161 			 * active.  Otherwise, on the command-line, we have to
162 			 * support this as an alias for executing the previous
163 			 * command with the new value of dot.  Sigh.
164 			 */
165 			if (mdb_iob_isastr(mdb.m_in)) {
166 				mdb_nv_set_value(mdb.m_dot, $1);
167 				mdb.m_incr = 0;
168 			} else if (pfp != NULL && pfp->f_pcmd != NULL) {
169 				mdb_addrvec_unshift(&pfp->f_pcmd->c_addrv,
170 				    (uintptr_t)$1);
171 				mdb_vcb_update(pfp, (uintptr_t)$1);
172 				mdb_nv_set_value(mdb.m_dot, $1);
173 			} else {
174 				mdb_list_move(&mdb.m_lastc,
175 				    &mdb.m_frame->f_cmds);
176 				if (!mdb_call($1, 1, DCMD_ADDRSPEC))
177 					return (0);
178 			}
179 		}
180 
181 	|	expression ',' expression shell_pipe terminator {
182 			mdb_list_move(&mdb.m_lastc, &mdb.m_frame->f_cmds);
183 			if (!mdb_call($1, $3, DCMD_ADDRSPEC | DCMD_LOOP))
184 				return (0);
185 		}
186 
187 	|	',' expression shell_pipe terminator {
188 			uintmax_t dot = mdb_dot_incr(",");
189 			mdb_list_move(&mdb.m_lastc, &mdb.m_frame->f_cmds);
190 			if (!mdb_call(dot, $2, DCMD_LOOP))
191 				return (0);
192 		}
193 
194 	|	'!' MDB_TOK_STRING terminator {
195 			if (mdb_iob_isapipe(mdb.m_in))
196 				yyerror("syntax error");
197 			mdb_shell_exec($2);
198 		}
199 
200 	|	terminator {
201 			if ((mdb.m_flags & MDB_FL_REPLAST) &&
202 			    !mdb_iob_isastr(mdb.m_in)) {
203 				uintmax_t dot = mdb_dot_incr("\\n");
204 				/*
205 				 * If a bare terminator is encountered, execute
206 				 * the previous command if -o repeatlast is set
207 				 * and stdin is not an mdb_eval() string.
208 				 */
209 				mdb_list_move(&mdb.m_lastc,
210 				    &mdb.m_frame->f_cmds);
211 				if (!mdb_call(dot, 1, 0))
212 					return (0);
213 			}
214 		}
215 	;
216 
217 pipeline:	pipeline '|' command { mdb_cmd_create($3, &mdb.m_frame->f_argvec); }
218 	|	command { mdb_cmd_create($1, &mdb.m_frame->f_argvec); }
219 	;
220 
221 command:	'?' format_list { $$ = mdb_dcmd_lookup("?"); }
222 	|	'/' format_list	{ $$ = mdb_dcmd_lookup("/"); }
223 	|	'\\' format_list { $$ = mdb_dcmd_lookup("\\"); }
224 	|	'@' format_list { $$ = mdb_dcmd_lookup("@"); }
225 	|	'=' format_list { $$ = mdb_dcmd_lookup("="); }
226 	|	MDB_TOK_DCMD argument_list { $$ = $1; }
227 	|	'$' { $$ = mdb_dcmd_lookup("$?"); }
228 	;
229 
230 shell_pipe:	/* Empty */
231 	|	'!' MDB_TOK_STRING { mdb_shell_pipe($2); }
232 	;
233 
234 format_list:	/* Empty */
235 	|	format_list MDB_TOK_LEXPR expression MDB_TOK_REXPR {
236 			mdb_arg_t arg;
237 
238 			arg.a_type = MDB_TYPE_IMMEDIATE;
239 			arg.a_un.a_val = $3;
240 
241 			mdb_argvec_append(&mdb.m_frame->f_argvec, &arg);
242 		}
243 
244 	|	format_list MDB_TOK_IMMEDIATE {
245 			mdb_arg_t arg;
246 
247 			arg.a_type = MDB_TYPE_IMMEDIATE;
248 			arg.a_un.a_val = $2;
249 
250 			mdb_argvec_append(&mdb.m_frame->f_argvec, &arg);
251 		}
252 
253 	|	format_list MDB_TOK_STRING	{
254 			mdb_arg_t arg;
255 
256 			arg.a_type = MDB_TYPE_STRING;
257 			arg.a_un.a_str = $2;
258 
259 			mdb_argvec_append(&mdb.m_frame->f_argvec, &arg);
260 		}
261 
262 	|	format_list MDB_TOK_CHAR	{
263 			mdb_arg_t arg;
264 
265 			arg.a_type = MDB_TYPE_CHAR;
266 			arg.a_un.a_char = $2;
267 
268 			mdb_argvec_append(&mdb.m_frame->f_argvec, &arg);
269 		}
270 	;
271 
272 argument_list:	/* Empty */
273 	|	argument_list MDB_TOK_LEXPR expression MDB_TOK_REXPR {
274 			mdb_arg_t arg;
275 
276 			arg.a_type = MDB_TYPE_IMMEDIATE;
277 			arg.a_un.a_val = $3;
278 
279 			mdb_argvec_append(&mdb.m_frame->f_argvec, &arg);
280 		}
281 
282 	|	argument_list MDB_TOK_STRING {
283 			mdb_arg_t arg;
284 
285 			arg.a_type = MDB_TYPE_STRING;
286 			arg.a_un.a_str = $2;
287 
288 			mdb_argvec_append(&mdb.m_frame->f_argvec, &arg);
289 		}
290 	;
291 
292 expression:	expression '+' expression { $$ = $1 + $3; }
293 	|	expression '-' expression { $$ = $1 - $3; }
294 	|	expression '*' expression { $$ = $1 * $3; }
295 
296 	|	expression '%' expression {
297 			if ($3 == 0UL)
298 				yyerror("attempted to divide by zero");
299 
300 			$$ = (intmax_t)$1 / (intmax_t)$3;
301 		}
302 
303 	|	expression '&' expression { $$ = $1 & $3; }
304 	|	expression '|' expression { $$ = $1 | $3; }
305 	|	expression '^' expression { $$ = $1 ^ $3; }
306 
307 	|	expression MDB_TOK_EQUAL expression { $$ = ($1 == $3); }
308 	|	expression MDB_TOK_NOTEQUAL expression { $$ = ($1 != $3); }
309 
310 	|	expression MDB_TOK_LSHIFT expression { $$ = $1 << $3; }
311 	|	expression MDB_TOK_RSHIFT expression { $$ = $1 >> $3; }
312 
313 	|	expression '#' expression {
314 			if ($3 == 0UL)
315 				yyerror("attempted to divide by zero");
316 
317 			$$ = ((intptr_t)($1 + ($3 - 1)) / (intptr_t)$3) * $3;
318 		}
319 
320 	|	'*' expression %prec MDB_COR_VALUE {
321 			uintptr_t value;
322 
323 			vfetch(&value, sizeof (value), $2);
324 			$$ = value;
325 		}
326 
327 	|	MDB_TOK_COR1_DEREF expression %prec MDB_COR_VALUE {
328 			uint8_t value;
329 
330 			vfetch(&value, sizeof (value), $2);
331 			$$ = value;
332 		}
333 
334 	|	MDB_TOK_COR2_DEREF expression %prec MDB_COR_VALUE {
335 			uint16_t value;
336 
337 			vfetch(&value, sizeof (value), $2);
338 			$$ = value;
339 		}
340 
341 	|	MDB_TOK_COR4_DEREF expression %prec MDB_COR_VALUE {
342 			uint32_t value;
343 
344 			vfetch(&value, sizeof (value), $2);
345 			$$ = value;
346 		}
347 
348 	|	MDB_TOK_COR8_DEREF expression %prec MDB_COR_VALUE {
349 			uint64_t value;
350 
351 			vfetch(&value, sizeof (value), $2);
352 			$$ = value;
353 		}
354 
355 	|	'%' expression %prec MDB_OBJ_VALUE {
356 			uintptr_t value;
357 
358 			ffetch(&value, sizeof (value), $2);
359 			$$ = value;
360 		}
361 
362 	|	MDB_TOK_OBJ1_DEREF expression %prec MDB_OBJ_VALUE {
363 			uint8_t value;
364 
365 			ffetch(&value, sizeof (value), $2);
366 			$$ = value;
367 		}
368 
369 	|	MDB_TOK_OBJ2_DEREF expression %prec MDB_OBJ_VALUE {
370 			uint16_t value;
371 
372 			ffetch(&value, sizeof (value), $2);
373 			$$ = value;
374 		}
375 
376 	|	MDB_TOK_OBJ4_DEREF expression %prec MDB_OBJ_VALUE {
377 			uint32_t value;
378 
379 			ffetch(&value, sizeof (value), $2);
380 			$$ = value;
381 		}
382 
383 	|	MDB_TOK_OBJ8_DEREF expression %prec MDB_OBJ_VALUE {
384 			uint64_t value;
385 
386 			ffetch(&value, sizeof (value), $2);
387 			$$ = value;
388 		}
389 
390 	|	'-' expression %prec MDB_INT_NEGATE { $$ = -$2; }
391 	|	'~' expression %prec MDB_BIT_COMPLEMENT { $$ = ~$2; }
392 	|	'#' expression %prec MDB_LOG_NEGATE { $$ = !$2; }
393 	|	'(' expression ')' { $$ = $2; }
394 
395 	|	MDB_TOK_VAR_REF %prec MDB_VAR_REFERENCE {
396 			$$ = mdb_nv_get_value($1);
397 		}
398 
399 	|	MDB_TOK_SYMBOL {
400 			if (strcmp($1, ".") == 0) {
401 				$$ = mdb_nv_get_value(mdb.m_dot);
402 				strfree($1);
403 
404 			} else {
405 				const char *obj = MDB_TGT_OBJ_EVERY, *name = $1;
406 				char *s = (char *)$1;
407 				GElf_Sym sym;
408 
409 				if ((s = strrsplit(s, '`')) != NULL) {
410 					name = s;
411 					obj = $1;
412 				}
413 
414 				if (mdb_tgt_lookup_by_name(mdb.m_target,
415 				    obj, name, &sym, NULL) == -1) {
416 					strfree($1);
417 					yyperror("failed to dereference "
418 					    "symbol");
419 				}
420 
421 				strfree($1);
422 				$$ = (uintmax_t)sym.st_value;
423 			}
424 		}
425 
426 	|	'+' { $$ = mdb_dot_incr("+"); }
427 	|	'^' { $$ = mdb_dot_decr("^"); }
428 	|	'&' { $$ = mdb.m_raddr; }
429 	|	MDB_TOK_IMMEDIATE
430 	;
431 
432 %%
433