1 /* 2 * Copyright (c) 2012NAME, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. 8 * 9 * This code is distributed in the hope that it will be useful, but WITHOUT 10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 12 * version 2 for more details (a copy is included in the LICENSE file that 13 * accompanied this code). 14 * 15 * You should have received a copy of the GNU General Public License version 16 * 2 along with this work; if not, write to the Free Software Foundation, 17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 18 * 19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 20 * or visit www.oracle.com if you need additional information or have any 21 * questions. 22 * 23 */ 24 25 #include "precompiled.hpp" 26 #include "memory/oopFactory.hpp" 27 #include "runtime/javaCalls.hpp" 28 #include "runtime/mutexLocker.hpp" 29 #include "services/diagnosticArgument.hpp" 30 #include "services/diagnosticFramework.hpp" 31 #include "services/management.hpp" 32 33 CmdLine::CmdLine(const char* line, size_t len, bool no_command_name) { 34 assert(line != NULL, "Command line string should not be NULL"); 35 const char* line_end; 36 const char* cmd_end; 37 38 _cmd = line; 39 line_end = &line[len]; 40 41 // Skip whitespace in the beginning of the line. 42 while (_cmd < line_end && isspace((int) _cmd[0])) { 43 _cmd++; 44 } 45 cmd_end = _cmd; 46 47 if (no_command_name) { 48 _cmd = NULL; 49 _cmd_len = 0; 50 } else { 51 // Look for end of the command name 52 while (cmd_end < line_end && !isspace((int) cmd_end[0])) { 53 cmd_end++; 54 } 55 _cmd_len = cmd_end - _cmd; 56 } 57 _args = cmd_end; 58 _args_len = line_end - _args; 59 } 60 61 bool DCmdArgIter::next(TRAPS) { 62 if (_len == 0) return false; 63 // skipping spaces 64 while (_cursor < _len - 1 && _buffer[_cursor] == _delim) { 65 _cursor++; 66 } 67 // handling end of command line 68 if (_cursor >= _len - 1) { 69 _cursor = _len - 1; 70 _key_addr = &_buffer[_len - 1]; 71 _key_len = 0; 72 _value_addr = &_buffer[_len - 1]; 73 _value_len = 0; 74 return false; 75 } 76 77 // extracting first item, argument or option name 78 _key_addr = &_buffer[_cursor]; 79 80 while (_cursor <= _len - 1 && _buffer[_cursor] != '=' && _buffer[_cursor] != _delim) { 81 // argument can be surrounded by single or double quotes 82 if (_buffer[_cursor] == '\"' || _buffer[_cursor] == '\'') { 83 _key_addr++; 84 char quote = _buffer[_cursor]; 85 while (_cursor < _len - 1) { 86 _cursor++; 87 if (_buffer[_cursor] == quote && _buffer[_cursor - 1] != '\\') { 88 break; 89 } 90 } 91 if (_buffer[_cursor] != quote) { 92 THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), 93 "Format error in diagnostic command arguments", false); 94 } 95 break; 96 } 97 _cursor++; 98 } 99 _key_len = &_buffer[_cursor] - _key_addr; 100 // check if the argument has the <key>=<value> format 101 if (_cursor <= _len -1 && _buffer[_cursor] == '=') { 102 _cursor++; 103 _value_addr = &_buffer[_cursor]; 104 // extract the value 105 while (_cursor <= _len - 1 && _buffer[_cursor] != _delim) { 106 // value can be surrounded by simple or double quotes 107 if (_buffer[_cursor] == '\"' || _buffer[_cursor] == '\'') { 108 _value_addr++; 109 char quote = _buffer[_cursor]; 110 while (_cursor < _len - 1) { 111 _cursor++; 112 if (_buffer[_cursor] == quote && _buffer[_cursor - 1] != '\\') { 113 break; 114 } 115 } 116 if (_buffer[_cursor] != quote) { 117 THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), 118 "Format error in diagnostic command arguments", false); 119 } 120 break; 121 } 122 _cursor++; 123 } 124 _value_len = &_buffer[_cursor] - _value_addr; 125 } else { 126 _value_addr = NULL; 127 _value_len = 0; 128 } 129 return _key_len != 0; 130 } 131 132 bool DCmdInfo::by_name(void* cmd_name, DCmdInfo* info) { 133 if (info == NULL) return false; 134 return strcmp((const char*)cmd_name, info->name()) == 0; 135 } 136 137 void DCmdParser::add_dcmd_option(GenDCmdArgument* arg) { 138 assert(arg != NULL, "Sanity"); 139 if (_options == NULL) { 140 _options = arg; 141 } else { 142 GenDCmdArgument* o = _options; 143 while (o->next() != NULL) { 144 o = o->next(); 145 } 146 o->set_next(arg); 147 } 148 arg->set_next(NULL); 149 Thread* THREAD = Thread::current(); 150 arg->init_value(THREAD); 151 if (HAS_PENDING_EXCEPTION) { 152 fatal("Initialization must be successful"); 153 } 154 } 155 156 void DCmdParser::add_dcmd_argument(GenDCmdArgument* arg) { 157 assert(arg != NULL, "Sanity"); 158 if (_arguments_list == NULL) { 159 _arguments_list = arg; 160 } else { 161 GenDCmdArgument* a = _arguments_list; 162 while (a->next() != NULL) { 163 a = a->next(); 164 } 165 a->set_next(arg); 166 } 167 arg->set_next(NULL); 168 Thread* THREAD = Thread::current(); 169 arg->init_value(THREAD); 170 if (HAS_PENDING_EXCEPTION) { 171 fatal("Initialization must be successful"); 172 } 173 } 174 175 void DCmdParser::parse(CmdLine* line, char delim, TRAPS) { 176 GenDCmdArgument* next_argument = _arguments_list; 177 DCmdArgIter iter(line->args_addr(), line->args_len(), delim); 178 bool cont = iter.next(CHECK); 179 while (cont) { 180 GenDCmdArgument* arg = lookup_dcmd_option(iter.key_addr(), 181 iter.key_length()); 182 if (arg != NULL) { 183 arg->read_value(iter.value_addr(), iter.value_length(), CHECK); 184 } else { 185 if (next_argument != NULL) { 186 arg = next_argument; 187 arg->read_value(iter.key_addr(), iter.key_length(), CHECK); 188 next_argument = next_argument->next(); 189 } else { 190 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), 191 "Unknown argument in diagnostic command"); 192 } 193 } 194 cont = iter.next(CHECK); 195 } 196 check(CHECK); 197 } 198 199 GenDCmdArgument* DCmdParser::lookup_dcmd_option(const char* name, size_t len) { 200 GenDCmdArgument* arg = _options; 201 while (arg != NULL) { 202 if (strlen(arg->name()) == len && 203 strncmp(name, arg->name(), len) == 0) { 204 return arg; 205 } 206 arg = arg->next(); 207 } 208 return NULL; 209 } 210 211 void DCmdParser::check(TRAPS) { 212 GenDCmdArgument* arg = _arguments_list; 213 while (arg != NULL) { 214 if (arg->is_mandatory() && !arg->has_value()) { 215 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), 216 "Missing argument for diagnostic command"); 217 } 218 arg = arg->next(); 219 } 220 arg = _options; 221 while (arg != NULL) { 222 if (arg->is_mandatory() && !arg->has_value()) { 223 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), 224 "Missing option for diagnostic command"); 225 } 226 arg = arg->next(); 227 } 228 } 229 230 void DCmdParser::print_help(outputStream* out, const char* cmd_name) { 231 out->print("Syntax : %s %s", cmd_name, _options == NULL ? "" : "[options]"); 232 GenDCmdArgument* arg = _arguments_list; 233 while (arg != NULL) { 234 if (arg->is_mandatory()) { 235 out->print(" <%s>", arg->name()); 236 } else { 237 out->print(" [<%s>]", arg->name()); 238 } 239 arg = arg->next(); 240 } 241 out->print_cr(""); 242 if (_arguments_list != NULL) { 243 out->print_cr("\nArguments:"); 244 arg = _arguments_list; 245 while (arg != NULL) { 246 out->print("\t%s : %s %s (%s, ", arg->name(), 247 arg->is_mandatory() ? "" : "[optional]", 248 arg->description(), arg->type()); 249 if (arg->has_default()) { 250 out->print(arg->default_string()); 251 } else { 252 out->print("no default value"); 253 } 254 out->print_cr(")"); 255 arg = arg->next(); 256 } 257 } 258 if (_options != NULL) { 259 out->print_cr("\nOptions: (options must be specified using the <key> or <key>=<value> syntax)"); 260 arg = _options; 261 while (arg != NULL) { 262 out->print("\t%s : %s %s (%s, ", arg->name(), 263 arg->is_mandatory() ? "" : "[optional]", 264 arg->description(), arg->type()); 265 if (arg->has_default()) { 266 out->print(arg->default_string()); 267 } else { 268 out->print("no default value"); 269 } 270 out->print_cr(")"); 271 arg = arg->next(); 272 } 273 } 274 } 275 276 void DCmdParser::reset(TRAPS) { 277 GenDCmdArgument* arg = _arguments_list; 278 while (arg != NULL) { 279 arg->reset(CHECK); 280 arg = arg->next(); 281 } 282 arg = _options; 283 while (arg != NULL) { 284 arg->reset(CHECK); 285 arg = arg->next(); 286 } 287 } 288 289 void DCmdParser::cleanup() { 290 GenDCmdArgument* arg = _arguments_list; 291 while (arg != NULL) { 292 arg->cleanup(); 293 arg = arg->next(); 294 } 295 arg = _options; 296 while (arg != NULL) { 297 arg->cleanup(); 298 arg = arg->next(); 299 } 300 } 301 302 int DCmdParser::num_arguments() { 303 GenDCmdArgument* arg = _arguments_list; 304 int count = 0; 305 while (arg != NULL) { 306 count++; 307 arg = arg->next(); 308 } 309 arg = _options; 310 while (arg != NULL) { 311 count++; 312 arg = arg->next(); 313 } 314 return count; 315 } 316 317 GrowableArray<const char *>* DCmdParser::argument_name_array() { 318 int count = num_arguments(); 319 GrowableArray<const char *>* array = new GrowableArray<const char *>(count); 320 GenDCmdArgument* arg = _arguments_list; 321 while (arg != NULL) { 322 array->append(arg->name()); 323 arg = arg->next(); 324 } 325 arg = _options; 326 while (arg != NULL) { 327 array->append(arg->name()); 328 arg = arg->next(); 329 } 330 return array; 331 } 332 333 GrowableArray<DCmdArgumentInfo*>* DCmdParser::argument_info_array() { 334 int count = num_arguments(); 335 GrowableArray<DCmdArgumentInfo*>* array = new GrowableArray<DCmdArgumentInfo *>(count); 336 int idx = 0; 337 GenDCmdArgument* arg = _arguments_list; 338 while (arg != NULL) { 339 array->append(new DCmdArgumentInfo(arg->name(), arg->description(), 340 arg->type(), arg->default_string(), arg->is_mandatory(), 341 false, idx)); 342 idx++; 343 arg = arg->next(); 344 } 345 arg = _options; 346 while (arg != NULL) { 347 array->append(new DCmdArgumentInfo(arg->name(), arg->description(), 348 arg->type(), arg->default_string(), arg->is_mandatory(), 349 true)); 350 arg = arg->next(); 351 } 352 return array; 353 } 354 355 DCmdFactory* DCmdFactory::_DCmdFactoryList = NULL; 356 357 void DCmd::parse_and_execute(outputStream* out, const char* cmdline, 358 char delim, TRAPS) { 359 360 if (cmdline == NULL) return; // Nothing to do! 361 DCmdIter iter(cmdline, '\n'); 362 363 while (iter.has_next()) { 364 CmdLine line = iter.next(); 365 if (line.is_stop()) { 366 break; 367 } 368 if (line.is_executable()) { 369 DCmd* command = DCmdFactory::create_local_DCmd(line, out, CHECK); 370 assert(command != NULL, "command error must be handled before this line"); 371 DCmdMark mark(command); 372 command->parse(&line, delim, CHECK); 373 command->execute(CHECK); 374 } 375 } 376 } 377 378 void DCmdWithParser::parse(CmdLine* line, char delim, TRAPS) { 379 _dcmdparser.parse(line, delim, CHECK); 380 } 381 382 void DCmdWithParser::print_help(const char* name) { 383 _dcmdparser.print_help(output(), name); 384 } 385 386 void DCmdWithParser::reset(TRAPS) { 387 _dcmdparser.reset(CHECK); 388 } 389 390 void DCmdWithParser::cleanup() { 391 _dcmdparser.cleanup(); 392 } 393 394 GrowableArray<const char*>* DCmdWithParser::argument_name_array() { 395 return _dcmdparser.argument_name_array(); 396 } 397 398 GrowableArray<DCmdArgumentInfo*>* DCmdWithParser::argument_info_array() { 399 return _dcmdparser.argument_info_array(); 400 } 401 402 Mutex* DCmdFactory::_dcmdFactory_lock = new Mutex(Mutex::leaf, "DCmdFactory", true); 403 404 DCmdFactory* DCmdFactory::factory(const char* name, size_t len) { 405 MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag); 406 DCmdFactory* factory = _DCmdFactoryList; 407 while (factory != NULL) { 408 if (strlen(factory->name()) == len && 409 strncmp(name, factory->name(), len) == 0) { 410 return factory; 411 } 412 factory = factory->_next; 413 } 414 return NULL; 415 } 416 417 int DCmdFactory::register_DCmdFactory(DCmdFactory* factory) { 418 MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag); 419 factory->_next = _DCmdFactoryList; 420 _DCmdFactoryList = factory; 421 return 0; // Actually, there's no checks for duplicates 422 } 423 424 DCmd* DCmdFactory::create_global_DCmd(CmdLine &line, outputStream* out, TRAPS) { 425 DCmdFactory* f = factory(line.cmd_addr(), line.cmd_len()); 426 if (f != NULL) { 427 if (f->is_enabled()) { 428 THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), 429 f->disabled_message()); 430 } 431 return f->create_Cheap_instance(out); 432 } 433 THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), 434 "Unknown diagnostic command"); 435 } 436 437 DCmd* DCmdFactory::create_local_DCmd(CmdLine &line, outputStream* out, TRAPS) { 438 DCmdFactory* f = factory(line.cmd_addr(), line.cmd_len()); 439 if (f != NULL) { 440 if (!f->is_enabled()) { 441 THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), 442 f->disabled_message()); 443 } 444 return f->create_resource_instance(out); 445 } 446 THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), 447 "Unknown diagnostic command"); 448 } 449 450 GrowableArray<const char*>* DCmdFactory::DCmd_list() { 451 MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag); 452 GrowableArray<const char*>* array = new GrowableArray<const char*>(); 453 DCmdFactory* factory = _DCmdFactoryList; 454 while (factory != NULL) { 455 if (!factory->is_hidden()) { 456 array->append(factory->name()); 457 } 458 factory = factory->next(); 459 } 460 return array; 461 } 462 463 GrowableArray<DCmdInfo*>* DCmdFactory::DCmdInfo_list() { 464 MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag); 465 GrowableArray<DCmdInfo*>* array = new GrowableArray<DCmdInfo*>(); 466 DCmdFactory* factory = _DCmdFactoryList; 467 while (factory != NULL) { 468 if (!factory->is_hidden()) { 469 array->append(new DCmdInfo(factory->name(), 470 factory->description(), factory->impact(), 471 factory->num_arguments(), factory->is_enabled())); 472 } 473 factory = factory->next(); 474 } 475 return array; 476 }