Path: blob/aarch64-shenandoah-jdk8u272-b10/hotspot/src/share/vm/services/diagnosticFramework.cpp
32285 views
/*1* Copyright (c) 2011, 2014, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*22*/2324#include "precompiled.hpp"25#include "memory/oopFactory.hpp"26#include "runtime/javaCalls.hpp"27#include "runtime/mutexLocker.hpp"28#include "services/diagnosticArgument.hpp"29#include "services/diagnosticFramework.hpp"30#include "services/management.hpp"3132CmdLine::CmdLine(const char* line, size_t len, bool no_command_name) {33assert(line != NULL, "Command line string should not be NULL");34const char* line_end;35const char* cmd_end;3637_cmd = line;38line_end = &line[len];3940// Skip whitespace in the beginning of the line.41while (_cmd < line_end && isspace((int) _cmd[0])) {42_cmd++;43}44cmd_end = _cmd;4546if (no_command_name) {47_cmd = NULL;48_cmd_len = 0;49} else {50// Look for end of the command name51while (cmd_end < line_end && !isspace((int) cmd_end[0])) {52cmd_end++;53}54_cmd_len = cmd_end - _cmd;55}56_args = cmd_end;57_args_len = line_end - _args;58}5960bool DCmdArgIter::next(TRAPS) {61if (_len == 0) return false;62// skipping spaces63while (_cursor < _len - 1 && _buffer[_cursor] == _delim) {64_cursor++;65}66// handling end of command line67if (_cursor >= _len - 1) {68_cursor = _len - 1;69_key_addr = &_buffer[_len - 1];70_key_len = 0;71_value_addr = &_buffer[_len - 1];72_value_len = 0;73return false;74}75// extracting first item, argument or option name76_key_addr = &_buffer[_cursor];77bool arg_had_quotes = false;78while (_cursor <= _len - 1 && _buffer[_cursor] != '=' && _buffer[_cursor] != _delim) {79// argument can be surrounded by single or double quotes80if (_buffer[_cursor] == '\"' || _buffer[_cursor] == '\'') {81_key_addr++;82char quote = _buffer[_cursor];83arg_had_quotes = true;84while (_cursor < _len - 1) {85_cursor++;86if (_buffer[_cursor] == quote && _buffer[_cursor - 1] != '\\') {87break;88}89}90if (_buffer[_cursor] != quote) {91THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),92"Format error in diagnostic command arguments", false);93}94break;95}96_cursor++;97}98_key_len = &_buffer[_cursor] - _key_addr;99if (arg_had_quotes) {100// if the argument was quoted, we need to step past the last quote here101_cursor++;102}103// check if the argument has the <key>=<value> format104if (_cursor <= _len -1 && _buffer[_cursor] == '=') {105_cursor++;106_value_addr = &_buffer[_cursor];107bool value_had_quotes = false;108// extract the value109while (_cursor <= _len - 1 && _buffer[_cursor] != _delim) {110// value can be surrounded by simple or double quotes111if (_buffer[_cursor] == '\"' || _buffer[_cursor] == '\'') {112_value_addr++;113char quote = _buffer[_cursor];114value_had_quotes = true;115while (_cursor < _len - 1) {116_cursor++;117if (_buffer[_cursor] == quote && _buffer[_cursor - 1] != '\\') {118break;119}120}121if (_buffer[_cursor] != quote) {122THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),123"Format error in diagnostic command arguments", false);124}125break;126}127_cursor++;128}129_value_len = &_buffer[_cursor] - _value_addr;130if (value_had_quotes) {131// if the value was quoted, we need to step past the last quote here132_cursor++;133}134} else {135_value_addr = NULL;136_value_len = 0;137}138return _key_len != 0;139}140141bool DCmdInfo::by_name(void* cmd_name, DCmdInfo* info) {142if (info == NULL) return false;143return strcmp((const char*)cmd_name, info->name()) == 0;144}145146void DCmdParser::add_dcmd_option(GenDCmdArgument* arg) {147assert(arg != NULL, "Sanity");148if (_options == NULL) {149_options = arg;150} else {151GenDCmdArgument* o = _options;152while (o->next() != NULL) {153o = o->next();154}155o->set_next(arg);156}157arg->set_next(NULL);158Thread* THREAD = Thread::current();159arg->init_value(THREAD);160if (HAS_PENDING_EXCEPTION) {161fatal("Initialization must be successful");162}163}164165void DCmdParser::add_dcmd_argument(GenDCmdArgument* arg) {166assert(arg != NULL, "Sanity");167if (_arguments_list == NULL) {168_arguments_list = arg;169} else {170GenDCmdArgument* a = _arguments_list;171while (a->next() != NULL) {172a = a->next();173}174a->set_next(arg);175}176arg->set_next(NULL);177Thread* THREAD = Thread::current();178arg->init_value(THREAD);179if (HAS_PENDING_EXCEPTION) {180fatal("Initialization must be successful");181}182}183184void DCmdParser::parse(CmdLine* line, char delim, TRAPS) {185GenDCmdArgument* next_argument = _arguments_list;186DCmdArgIter iter(line->args_addr(), line->args_len(), delim);187bool cont = iter.next(CHECK);188while (cont) {189GenDCmdArgument* arg = lookup_dcmd_option(iter.key_addr(),190iter.key_length());191if (arg != NULL) {192arg->read_value(iter.value_addr(), iter.value_length(), CHECK);193} else {194if (next_argument != NULL) {195arg = next_argument;196arg->read_value(iter.key_addr(), iter.key_length(), CHECK);197next_argument = next_argument->next();198} else {199const size_t buflen = 120;200const size_t argbuflen = 30;201char buf[buflen];202char argbuf[argbuflen];203size_t len = MIN2<size_t>(iter.key_length(), argbuflen - 1);204205strncpy(argbuf, iter.key_addr(), len);206argbuf[len] = '\0';207jio_snprintf(buf, buflen - 1, "Unknown argument '%s' in diagnostic command.", argbuf);208209THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), buf);210}211}212cont = iter.next(CHECK);213}214check(CHECK);215}216217GenDCmdArgument* DCmdParser::lookup_dcmd_option(const char* name, size_t len) {218GenDCmdArgument* arg = _options;219while (arg != NULL) {220if (strlen(arg->name()) == len &&221strncmp(name, arg->name(), len) == 0) {222return arg;223}224arg = arg->next();225}226return NULL;227}228229void DCmdParser::check(TRAPS) {230const size_t buflen = 256;231char buf[buflen];232GenDCmdArgument* arg = _arguments_list;233while (arg != NULL) {234if (arg->is_mandatory() && !arg->has_value()) {235jio_snprintf(buf, buflen - 1, "The argument '%s' is mandatory.", arg->name());236THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), buf);237}238arg = arg->next();239}240arg = _options;241while (arg != NULL) {242if (arg->is_mandatory() && !arg->has_value()) {243jio_snprintf(buf, buflen - 1, "The option '%s' is mandatory.", arg->name());244THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(), buf);245}246arg = arg->next();247}248}249250void DCmdParser::print_help(outputStream* out, const char* cmd_name) {251out->print("Syntax : %s %s", cmd_name, _options == NULL ? "" : "[options]");252GenDCmdArgument* arg = _arguments_list;253while (arg != NULL) {254if (arg->is_mandatory()) {255out->print(" <%s>", arg->name());256} else {257out->print(" [<%s>]", arg->name());258}259arg = arg->next();260}261out->cr();262if (_arguments_list != NULL) {263out->print_cr("\nArguments:");264arg = _arguments_list;265while (arg != NULL) {266out->print("\t%s : %s %s (%s, ", arg->name(),267arg->is_mandatory() ? "" : "[optional]",268arg->description(), arg->type());269if (arg->has_default()) {270out->print("%s", arg->default_string());271} else {272out->print("no default value");273}274out->print_cr(")");275arg = arg->next();276}277}278if (_options != NULL) {279out->print_cr("\nOptions: (options must be specified using the <key> or <key>=<value> syntax)");280arg = _options;281while (arg != NULL) {282out->print("\t%s : %s %s (%s, ", arg->name(),283arg->is_mandatory() ? "" : "[optional]",284arg->description(), arg->type());285if (arg->has_default()) {286out->print("%s", arg->default_string());287} else {288out->print("no default value");289}290out->print_cr(")");291arg = arg->next();292}293}294}295296void DCmdParser::reset(TRAPS) {297GenDCmdArgument* arg = _arguments_list;298while (arg != NULL) {299arg->reset(CHECK);300arg = arg->next();301}302arg = _options;303while (arg != NULL) {304arg->reset(CHECK);305arg = arg->next();306}307}308309void DCmdParser::cleanup() {310GenDCmdArgument* arg = _arguments_list;311while (arg != NULL) {312arg->cleanup();313arg = arg->next();314}315arg = _options;316while (arg != NULL) {317arg->cleanup();318arg = arg->next();319}320}321322int DCmdParser::num_arguments() {323GenDCmdArgument* arg = _arguments_list;324int count = 0;325while (arg != NULL) {326count++;327arg = arg->next();328}329arg = _options;330while (arg != NULL) {331count++;332arg = arg->next();333}334return count;335}336337GrowableArray<const char *>* DCmdParser::argument_name_array() {338int count = num_arguments();339GrowableArray<const char *>* array = new GrowableArray<const char *>(count);340GenDCmdArgument* arg = _arguments_list;341while (arg != NULL) {342array->append(arg->name());343arg = arg->next();344}345arg = _options;346while (arg != NULL) {347array->append(arg->name());348arg = arg->next();349}350return array;351}352353GrowableArray<DCmdArgumentInfo*>* DCmdParser::argument_info_array() {354int count = num_arguments();355GrowableArray<DCmdArgumentInfo*>* array = new GrowableArray<DCmdArgumentInfo *>(count);356int idx = 0;357GenDCmdArgument* arg = _arguments_list;358while (arg != NULL) {359array->append(new DCmdArgumentInfo(arg->name(), arg->description(),360arg->type(), arg->default_string(), arg->is_mandatory(),361false, arg->allow_multiple(), idx));362idx++;363arg = arg->next();364}365arg = _options;366while (arg != NULL) {367array->append(new DCmdArgumentInfo(arg->name(), arg->description(),368arg->type(), arg->default_string(), arg->is_mandatory(),369true, arg->allow_multiple()));370arg = arg->next();371}372return array;373}374375DCmdFactory* DCmdFactory::_DCmdFactoryList = NULL;376bool DCmdFactory::_has_pending_jmx_notification = false;377378void DCmd::parse_and_execute(DCmdSource source, outputStream* out,379const char* cmdline, char delim, TRAPS) {380381if (cmdline == NULL) return; // Nothing to do!382DCmdIter iter(cmdline, '\n');383384int count = 0;385while (iter.has_next()) {386if(source == DCmd_Source_MBean && count > 0) {387// When diagnostic commands are invoked via JMX, each command line388// must contains one and only one command because of the Permission389// checks performed by the DiagnosticCommandMBean390THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),391"Invalid syntax");392}393CmdLine line = iter.next();394if (line.is_stop()) {395break;396}397if (line.is_executable()) {398DCmd* command = DCmdFactory::create_local_DCmd(source, line, out, CHECK);399assert(command != NULL, "command error must be handled before this line");400DCmdMark mark(command);401command->parse(&line, delim, CHECK);402command->execute(source, CHECK);403}404count++;405}406}407408void DCmdWithParser::parse(CmdLine* line, char delim, TRAPS) {409_dcmdparser.parse(line, delim, CHECK);410}411412void DCmdWithParser::print_help(const char* name) {413_dcmdparser.print_help(output(), name);414}415416void DCmdWithParser::reset(TRAPS) {417_dcmdparser.reset(CHECK);418}419420void DCmdWithParser::cleanup() {421_dcmdparser.cleanup();422}423424GrowableArray<const char*>* DCmdWithParser::argument_name_array() {425return _dcmdparser.argument_name_array();426}427428GrowableArray<DCmdArgumentInfo*>* DCmdWithParser::argument_info_array() {429return _dcmdparser.argument_info_array();430}431432void DCmdFactory::push_jmx_notification_request() {433MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);434_has_pending_jmx_notification = true;435Service_lock->notify_all();436}437438void DCmdFactory::send_notification(TRAPS) {439DCmdFactory::send_notification_internal(THREAD);440// Clearing pending exception to avoid premature termination of441// the service thread442if (HAS_PENDING_EXCEPTION) {443CLEAR_PENDING_EXCEPTION;444}445}446void DCmdFactory::send_notification_internal(TRAPS) {447ResourceMark rm(THREAD);448HandleMark hm(THREAD);449bool notif = false;450{451MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);452notif = _has_pending_jmx_notification;453_has_pending_jmx_notification = false;454}455if (notif) {456457Klass* k = Management::sun_management_ManagementFactoryHelper_klass(CHECK);458instanceKlassHandle mgmt_factory_helper_klass(THREAD, k);459460JavaValue result(T_OBJECT);461JavaCalls::call_static(&result,462mgmt_factory_helper_klass,463vmSymbols::getDiagnosticCommandMBean_name(),464vmSymbols::getDiagnosticCommandMBean_signature(),465CHECK);466467instanceOop m = (instanceOop) result.get_jobject();468instanceHandle dcmd_mbean_h(THREAD, m);469470Klass* k2 = Management::sun_management_DiagnosticCommandImpl_klass(CHECK);471instanceKlassHandle dcmd_mbean_klass(THREAD, k2);472473if (!dcmd_mbean_h->is_a(k2)) {474THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),475"ManagementFactory.getDiagnosticCommandMBean didn't return a DiagnosticCommandMBean instance");476}477478JavaValue result2(T_VOID);479JavaCallArguments args2(dcmd_mbean_h);480481JavaCalls::call_virtual(&result2,482dcmd_mbean_klass,483vmSymbols::createDiagnosticFrameworkNotification_name(),484vmSymbols::void_method_signature(),485&args2,486CHECK);487}488}489490Mutex* DCmdFactory::_dcmdFactory_lock = new Mutex(Mutex::leaf, "DCmdFactory", true);491bool DCmdFactory::_send_jmx_notification = false;492493DCmdFactory* DCmdFactory::factory(DCmdSource source, const char* name, size_t len) {494MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag);495DCmdFactory* factory = _DCmdFactoryList;496while (factory != NULL) {497if (strlen(factory->name()) == len &&498strncmp(name, factory->name(), len) == 0) {499if(factory->export_flags() & source) {500return factory;501} else {502return NULL;503}504}505factory = factory->_next;506}507return NULL;508}509510int DCmdFactory::register_DCmdFactory(DCmdFactory* factory) {511MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag);512factory->_next = _DCmdFactoryList;513_DCmdFactoryList = factory;514if (_send_jmx_notification && !factory->_hidden515&& (factory->_export_flags & DCmd_Source_MBean)) {516DCmdFactory::push_jmx_notification_request();517}518return 0; // Actually, there's no checks for duplicates519}520521DCmd* DCmdFactory::create_global_DCmd(DCmdSource source, CmdLine &line,522outputStream* out, TRAPS) {523DCmdFactory* f = factory(source, line.cmd_addr(), line.cmd_len());524if (f != NULL) {525if (f->is_enabled()) {526THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(),527f->disabled_message());528}529return f->create_Cheap_instance(out);530}531THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(),532"Unknown diagnostic command");533}534535DCmd* DCmdFactory::create_local_DCmd(DCmdSource source, CmdLine &line,536outputStream* out, TRAPS) {537DCmdFactory* f = factory(source, line.cmd_addr(), line.cmd_len());538if (f != NULL) {539if (!f->is_enabled()) {540THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(),541f->disabled_message());542}543return f->create_resource_instance(out);544}545THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(),546"Unknown diagnostic command");547}548549GrowableArray<const char*>* DCmdFactory::DCmd_list(DCmdSource source) {550MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag);551GrowableArray<const char*>* array = new GrowableArray<const char*>();552DCmdFactory* factory = _DCmdFactoryList;553while (factory != NULL) {554if (!factory->is_hidden() && (factory->export_flags() & source)) {555array->append(factory->name());556}557factory = factory->next();558}559return array;560}561562GrowableArray<DCmdInfo*>* DCmdFactory::DCmdInfo_list(DCmdSource source ) {563MutexLockerEx ml(_dcmdFactory_lock, Mutex::_no_safepoint_check_flag);564GrowableArray<DCmdInfo*>* array = new GrowableArray<DCmdInfo*>();565DCmdFactory* factory = _DCmdFactoryList;566while (factory != NULL) {567if (!factory->is_hidden() && (factory->export_flags() & source)) {568array->append(new DCmdInfo(factory->name(),569factory->description(), factory->impact(),570factory->permission(), factory->num_arguments(),571factory->is_enabled()));572}573factory = factory->next();574}575return array;576}577578579