1 /* 2 * Copyright (c) 2011, 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 if (_buffer[_cursor] == _delim) { 78 _cursor++; 79 } 80 81 // extracting first item, argument or option name 82 _key_addr = &_buffer[_cursor]; 83 84 while (_cursor <= _len - 1 && _buffer[_cursor] != '=' && _buffer[_cursor] != _delim) { 85 // argument can be surrounded by single or double quotes 86 if (_buffer[_cursor] == '\"' || _buffer[_cursor] == '\'') { 87 _key_addr++; 88 char quote = _buffer[_cursor]; 89 while (_cursor < _len - 1) { 90 _cursor++; 91 if (_buffer[_cursor] == quote && _buffer[_cursor - 1] != '\\') { 92 break; 93 } 94 } 95 if (_buffer[_cursor] != quote) { 96 THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), 97 "Format error in diagnostic command arguments", false); 98 } 99 break; 100 } 101 _cursor++; 102 } 103 _key_len = &_buffer[_cursor] - _key_addr; 104 // check if the argument has the <key>=<value> format 105 if (_cursor <= _len -1 && _buffer[_cursor] == '=') { 106 _cursor++; 107 _value_addr = &_buffer[_cursor]; 108 // extract the value 109 while (_cursor <= _len - 1 && _buffer[_cursor] != _delim) { 110 // value can be surrounded by simple or double quotes 111 if (_buffer[_cursor] == '\"' || _buffer[_cursor] == '\'') { 112 _value_addr++; 113 char quote = _buffer[_cursor]; 114 while (_cursor < _len - 1) { 115 _cursor++; 116 if (_buffer[_cursor] == quote && _buffer[_cursor - 1] != '\\') { 117 break; 118 } 119 } 120 if (_buffer[_cursor] != quote) { 121 THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), 122 "Format error in diagnostic command arguments", false); 123 } 124 break; 125 } 126 _cursor++; 127 } 128 _value_len = &_buffer[_cursor] - _value_addr; 129 } else { 130 _value_addr = NULL; 131 _value_len = 0; 132 } 133 return _key_len != 0; 134 } 135 136 bool DCmdInfo::by_name(void* cmd_name, DCmdInfo* info) { 137 if (info == NULL) return false; 138 return strcmp((const char*)cmd_name, info->name()) == 0; 139 } 140 141 void DCmdParser::add_dcmd_option(GenDCmdArgument* arg) { 142 assert(arg != NULL, "Sanity"); 143 if (_options == NULL) { 144 _options = arg; 145 } else { 146 GenDCmdArgument* o = _options; 147 while (o->next() != NULL) { 148 o = o->next(); 149 } 150 o->set_next(arg); 151 } 152 arg->set_next(NULL); 153 Thread* THREAD = Thread::current(); 154 arg->init_value(THREAD); 155 if (HAS_PENDING_EXCEPTION) { 156 fatal("Initialization must be successful"); 157 } 158 } 159 160 void DCmdParser::add_dcmd_argument(GenDCmdArgument* arg) { 161 assert(arg != NULL, "Sanity"); 162 if (_arguments_list == NULL) { 163 _arguments_list = arg; 164 } else { 165 GenDCmdArgument* a = _arguments_list; 166 while (a->next() != NULL) { 167 a = a->next(); 168 } 169 a->set_next(arg); 170 } 171 arg->set_next(NULL); 172 Thread* THREAD = Thread::current(); 173 arg->init_value(THREAD); 174 if (HAS_PENDING_EXCEPTION) { 175 fatal("Initialization must be successful"); 176 } 177 } 178 179 void DCmdParser::parse(CmdLine* line, char delim, TRAPS) { 180 GenDCmdArgument* next_argument = _arguments_list; 181 DCmdArgIter iter(line->args_addr(), line->args_len(), delim); 182 bool cont = iter.next(CHECK); 183 while (cont) { 184 GenDCmdArgument* arg = lookup_dcmd_option(iter.key_addr(), 185 iter.key_length()); 186 if (arg != NULL) { 187 arg->read_value(iter.value_addr(), iter.value_length(), CHECK); 188 } else { 189 if (next_argument != NULL) { 190 arg = next_argument; 191 arg->read_value(iter.key_addr(), iter.key_length(), CHECK); 192 next_argument = next_argument->next(); 193 } else { 194 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), 195 "Unknown argument in diagnostic command"); 196 } 197 } 198 cont = iter.next(CHECK); 199 } 200 check(CHECK); 201 } 202 203 GenDCmdArgument* DCmdParser::lookup_dcmd_option(const char* name, size_t len) { 204 GenDCmdArgument* arg = _options; 205 while (arg != NULL) { 206 if (strlen(arg->name()) == len && 207 strncmp(name, arg->name(), len) == 0) { 208 return arg; 209 } 210 arg = arg->next(); 211 } 212 return NULL; 213 } 214 215 void DCmdParser::check(TRAPS) { 216 GenDCmdArgument* arg = _arguments_list; 217 while (arg != NULL) { 218 if (arg->is_mandatory() && !arg->has_value()) { 219 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), 220 "Missing argument for diagnostic command"); 221 } 222 arg = arg->next(); 223 } 224 arg = _options; 225 while (arg != NULL) { 226 if (arg->is_mandatory() && !arg->has_value()) { 227 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), 228 "Missing option for diagnostic command"); 229 } 230 arg = arg->next(); 231 } 232 } 233 234 void DCmdParser::print_help(outputStream* out, const char* cmd_name) { 235 out->print("Syntax : %s %s", cmd_name, _options == NULL ? "" : "[options]"); 236 GenDCmdArgument* arg = _arguments_list; 237 while (arg != NULL) { 238 if (arg->is_mandatory()) { 239 out->print(" <%s>", arg->name()); 240 } else { 241 out->print(" [<%s>]", arg->name()); 242 } 243 arg = arg->next(); 244 } 245 out->print_cr(""); 246 if (_arguments_list != NULL) { 247 out->print_cr("\nArguments:"); 248 arg = _arguments_list; 249 while (arg != NULL) { 250 out->print("\t%s : %s %s (%s, ", arg->name(), 251 arg->is_mandatory() ? "" : "[optional]", 252 arg->description(), arg->type()); 253 if (arg->has_default()) { 254 out->print(arg->default_string()); 255 } else { 256 out->print("no default value"); 257 } 258 out->print_cr(")"); 259 arg = arg->next(); 260 } 261 } 262 if (_options != NULL) { 263 out->print_cr("\nOptions: (options must be specified using the <key> or <key>=<value> syntax)"); 264 arg = _options; 265 while (arg != NULL) { 266 out->print("\t%s : %s %s (%s, ", arg->name(), 267 arg->is_mandatory() ? "" : "[optional]", 268 arg->description(), arg->type()); 269 if (arg->has_default()) { 270 out->print(arg->default_string()); 271 } else { 272 out->print("no default value"); 273 } 274 out->print_cr(")"); 275 arg = arg->next(); 276 } 277 } 278 } 279 280 void DCmdParser::reset(TRAPS) { 281 GenDCmdArgument* arg = _arguments_list; 282 while (arg != NULL) { 283 arg->reset(CHECK); 284 arg = arg->next(); 285 } 286 arg = _options; 287 while (arg != NULL) { 288 arg->reset(CHECK); 289 arg = arg->next(); 290 } 291 } 292 293 void DCmdParser::cleanup() { 294 GenDCmdArgument* arg = _arguments_list; 295 while (arg != NULL) { 296 arg->cleanup(); 297 arg = arg->next(); 298 } 299 arg = _options; 300 while (arg != NULL) { 301 arg->cleanup(); 302 arg = arg->next(); 303 } 304 } 305 306 int DCmdParser::num_arguments() { 307 GenDCmdArgument* arg = _arguments_list; 308 int count = 0; 309 while (arg != NULL) { 310 count++; 311 arg = arg->next(); 312 } 313 arg = _options; 314 while (arg != NULL) { 315 count++; 316 arg = arg->next(); 317 } 318 return count; 319 } 320 321 GrowableArray<const char *>* DCmdParser::argument_name_array() { 322 int count = num_arguments(); 323 GrowableArray<const char *>* array = new GrowableArray<const char *>(count); 324 GenDCmdArgument* arg = _arguments_list; 325 while (arg != NULL) { 326 array->append(arg->name()); 327 arg = arg->next(); 328 } 329 arg = _options; 330 while (arg != NULL) { 331 array->append(arg->name()); 332 arg = arg->next(); 333 } 334 return array; 335 } 336 337 GrowableArray<DCmdArgumentInfo*>* DCmdParser::argument_info_array() { 338 int count = num_arguments(); 339 GrowableArray<DCmdArgumentInfo*>* array = new GrowableArray<DCmdArgumentInfo *>(count); 340 int idx = 0; 341 GenDCmdArgument* arg = _arguments_list; 342 while (arg != NULL) { 343 array->append(new DCmdArgumentInfo(arg->name(), arg->description(), 344 arg->type(), arg->default_string(), arg->is_mandatory(), 345 false, idx)); 346 idx++; 347 arg = arg->next(); 348 } 349 arg = _options; 350 while (arg != NULL) { 351 array->append(new DCmdArgumentInfo(arg->name(), arg->description(), 352 arg->type(), arg->default_string(), arg->is_mandatory(), 353 true)); 354 arg = arg->next(); 355 } 356 return array; 357 } 358 359 DCmdFactory* DCmdFactory::_DCmdFactoryList = NULL; 360 361 void DCmd::parse_and_execute(outputStream* out, const char* cmdline, 362 char delim, TRAPS) { 363 364 if (cmdline == NULL) return; // Nothing to do! 365 DCmdIter iter(cmdline, '\n'); 366 367 while (iter.has_next()) { 368 CmdLine line = iter.next(); 369 if (line.is_stop()) { 370 break; 371 } 372 if (line.is_executable()) { 373 DCmd* command = DCmdFactory::create_local_DCmd(line, out, CHECK); 374 assert(command != NULL, "command error must be handled before this line"); 375 DCmdMark mark(command); 376 command->parse(&line, delim, CHECK); 377 command->execute(CHECK); 378 } 379 } 380 } 381 382 void DCmdWithParser::parse(CmdLine* line, char delim, TRAPS) { 383 _dcmdparser.parse(line, delim, CHECK); 384 } 385 386 void DCmdWithParser::print_help(const char* name) { 387 _dcmdparser.print_help(output(), name); 388 } 389 390 void DCmdWithParser::reset(TRAPS) { 391 _dcmdparser.reset(CHECK); 392 } 393 394 void DCmdWithParser::cleanup() { 395 _dcmdparser.cleanup(); 396 } 397 398 GrowableArray<const char*>* DCmdWithParser::argument_name_array() { 399 return _dcmdparser.argument_name_array(); 400 } 401 402 GrowableArray<DCmdArgumentInfo*>* DCmdWithParser::argument_info_array() { 403 return _dcmdparser.argument_info_array(); 404 } 405 406 Mutex* DCmdFactory::_dcmdFactory_lock = new Mutex(Mutex::leaf, "DCmdFactory", true); 407 408 DCmdFactory* DCmdFactory::factory(const char* name, size_t len) { 409 MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag); 410 DCmdFactory* factory = _DCmdFactoryList; 411 while (factory != NULL) { 412 if (strlen(factory->name()) == len && 413 strncmp(name, factory->name(), len) == 0) { 414 return factory; 415 } 416 factory = factory->_next; 417 } 418 return NULL; 419 } 420 421 int DCmdFactory::register_DCmdFactory(DCmdFactory* factory) { 422 MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag); 423 factory->_next = _DCmdFactoryList; 424 _DCmdFactoryList = factory; 425 return 0; // Actually, there's no checks for duplicates 426 } 427 428 DCmd* DCmdFactory::create_global_DCmd(CmdLine &line, outputStream* out, TRAPS) { 429 DCmdFactory* f = factory(line.cmd_addr(), line.cmd_len()); 430 if (f != NULL) { 431 if (f->is_enabled()) { 432 THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), 433 f->disabled_message()); 434 } 435 return f->create_Cheap_instance(out); 436 } 437 THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), 438 "Unknown diagnostic command"); 439 } 440 441 DCmd* DCmdFactory::create_local_DCmd(CmdLine &line, outputStream* out, TRAPS) { 442 DCmdFactory* f = factory(line.cmd_addr(), line.cmd_len()); 443 if (f != NULL) { 444 if (!f->is_enabled()) { 445 THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), 446 f->disabled_message()); 447 } 448 return f->create_resource_instance(out); 449 } 450 THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(), 451 "Unknown diagnostic command"); 452 } 453 454 GrowableArray<const char*>* DCmdFactory::DCmd_list() { 455 MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag); 456 GrowableArray<const char*>* array = new GrowableArray<const char*>(); 457 DCmdFactory* factory = _DCmdFactoryList; 458 while (factory != NULL) { 459 if (!factory->is_hidden()) { 460 array->append(factory->name()); 461 } 462 factory = factory->next(); 463 } 464 return array; 465 } 466 467 GrowableArray<DCmdInfo*>* DCmdFactory::DCmdInfo_list() { 468 MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag); 469 GrowableArray<DCmdInfo*>* array = new GrowableArray<DCmdInfo*>(); 470 DCmdFactory* factory = _DCmdFactoryList; 471 while (factory != NULL) { 472 if (!factory->is_hidden()) { 473 array->append(new DCmdInfo(factory->name(), 474 factory->description(), factory->impact(), 475 factory->num_arguments(), factory->is_enabled())); 476 } 477 factory = factory->next(); 478 } 479 return array; 480 }