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