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
vfetch(void * buf,size_t nbytes,uintptr_t addr)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
ffetch(void * buf,size_t nbytes,uintptr_t addr)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
yyexpand(int val)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