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 "gc_implementation/shared/vmGCOperations.hpp" 27 #include "runtime/javaCalls.hpp" 28 #include "services/diagnosticArgument.hpp" 29 #include "services/diagnosticCommand.hpp" 30 #include "services/diagnosticFramework.hpp" 31 #include "services/heapDumper.hpp" 32 #include "services/management.hpp" 33 34 void DCmdRegistrant::register_dcmds(){ 35 // Registration of the diagnostic commands 36 // First boolean argument specifies if the command is enabled 37 // Second boolean argument specifies if the command is hidden 38 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HelpDCmd>(true, false)); 39 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VersionDCmd>(true, false)); 40 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CommandLineDCmd>(true, false)); 41 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<PrintSystemPropertiesDCmd>(true, false)); 42 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<PrintVMFlagsDCmd>(true, false)); 43 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VMUptimeDCmd>(true, false)); 44 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<SystemGCDCmd>(true, false)); 45 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<RunFinalizationDCmd>(true, false)); 46 #ifndef SERVICES_KERNEL // Heap dumping not supported 47 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HeapDumpDCmd>(true, false)); 48 #endif // SERVICES_KERNEL 49 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassHistogramDCmd>(true, false)); 50 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ThreadDumpDCmd>(true, false)); 51 52 } 53 54 #ifndef HAVE_EXTRA_DCMD 55 void DCmdRegistrant::register_dcmds_ext(){ 56 // Do nothing here 57 } 58 #endif 59 60 61 HelpDCmd::HelpDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap), 62 _all("-all", "Show help for all commands", "BOOLEAN", false, "false"), 63 _cmd("command name", "The name of the command for which we want help", 64 "STRING", false) { 65 _dcmdparser.add_dcmd_option(&_all); 66 _dcmdparser.add_dcmd_argument(&_cmd); 67 }; 68 69 void HelpDCmd::execute(TRAPS) { 70 if (_all.value()) { 71 GrowableArray<const char*>* cmd_list = DCmdFactory::DCmd_list(); 72 for (int i = 0; i < cmd_list->length(); i++) { 73 DCmdFactory* factory = DCmdFactory::factory(cmd_list->at(i), 74 strlen(cmd_list->at(i))); 75 if (!factory->is_hidden()) { 76 output()->print_cr("%s%s", factory->name(), 77 factory->is_enabled() ? "" : " [disabled]"); 78 output()->print_cr("\t%s", factory->description()); 79 output()->cr(); 80 } 81 factory = factory->next(); 82 } 83 } else if (_cmd.has_value()) { 84 DCmd* cmd = NULL; 85 DCmdFactory* factory = DCmdFactory::factory(_cmd.value(), 86 strlen(_cmd.value())); 87 if (factory != NULL) { 88 output()->print_cr("%s%s", factory->name(), 89 factory->is_enabled() ? "" : " [disabled]"); 90 output()->print_cr(factory->description()); 91 output()->print_cr("\nImpact: %s", factory->impact()); 92 output()->cr(); 93 cmd = factory->create_resource_instance(output()); 94 if (cmd != NULL) { 95 DCmdMark mark(cmd); 96 cmd->print_help(factory->name()); 97 } 98 } else { 99 output()->print_cr("Help unavailable : '%s' : No such command", _cmd.value()); 100 } 101 } else { 102 output()->print_cr("The following commands are available:"); 103 GrowableArray<const char *>* cmd_list = DCmdFactory::DCmd_list(); 104 for (int i = 0; i < cmd_list->length(); i++) { 105 DCmdFactory* factory = DCmdFactory::factory(cmd_list->at(i), 106 strlen(cmd_list->at(i))); 107 if (!factory->is_hidden()) { 108 output()->print_cr("%s%s", factory->name(), 109 factory->is_enabled() ? "" : " [disabled]"); 110 } 111 factory = factory->_next; 112 } 113 output()->print_cr("\nFor more information about a specific command use 'help <command>'."); 114 } 115 } 116 117 int HelpDCmd::num_arguments() { 118 ResourceMark rm; 119 HelpDCmd* dcmd = new HelpDCmd(NULL, false); 120 if (dcmd != NULL) { 121 DCmdMark mark(dcmd); 122 return dcmd->_dcmdparser.num_arguments(); 123 } else { 124 return 0; 125 } 126 } 127 128 void VersionDCmd::execute(TRAPS) { 129 output()->print_cr("%s version %s", Abstract_VM_Version::vm_name(), 130 Abstract_VM_Version::vm_release()); 131 JDK_Version jdk_version = JDK_Version::current(); 132 if (jdk_version.update_version() > 0) { 133 output()->print_cr("JDK %d.%d_%02d", jdk_version.major_version(), 134 jdk_version.minor_version(), jdk_version.update_version()); 135 } else { 136 output()->print_cr("JDK %d.%d", jdk_version.major_version(), 137 jdk_version.minor_version()); 138 } 139 } 140 141 PrintVMFlagsDCmd::PrintVMFlagsDCmd(outputStream* output, bool heap) : 142 DCmdWithParser(output, heap), 143 _all("-all", "Print all flags supported by the VM", "BOOLEAN", false, "false") { 144 _dcmdparser.add_dcmd_option(&_all); 145 } 146 147 void PrintVMFlagsDCmd::execute(TRAPS) { 148 if (_all.value()) { 149 CommandLineFlags::printFlags(output(), true); 150 } else { 151 CommandLineFlags::printSetFlags(output()); 152 } 153 } 154 155 int PrintVMFlagsDCmd::num_arguments() { 156 ResourceMark rm; 157 PrintVMFlagsDCmd* dcmd = new PrintVMFlagsDCmd(NULL, false); 158 if (dcmd != NULL) { 159 DCmdMark mark(dcmd); 160 return dcmd->_dcmdparser.num_arguments(); 161 } else { 162 return 0; 163 } 164 } 165 166 void PrintSystemPropertiesDCmd::execute(TRAPS) { 167 // load sun.misc.VMSupport 168 Symbol* klass = vmSymbols::sun_misc_VMSupport(); 169 klassOop k = SystemDictionary::resolve_or_fail(klass, true, CHECK); 170 instanceKlassHandle ik (THREAD, k); 171 if (ik->should_be_initialized()) { 172 ik->initialize(THREAD); 173 } 174 if (HAS_PENDING_EXCEPTION) { 175 java_lang_Throwable::print(PENDING_EXCEPTION, output()); 176 output()->cr(); 177 CLEAR_PENDING_EXCEPTION; 178 return; 179 } 180 181 // invoke the serializePropertiesToByteArray method 182 JavaValue result(T_OBJECT); 183 JavaCallArguments args; 184 185 Symbol* signature = vmSymbols::serializePropertiesToByteArray_signature(); 186 JavaCalls::call_static(&result, 187 ik, 188 vmSymbols::serializePropertiesToByteArray_name(), 189 signature, 190 &args, 191 THREAD); 192 if (HAS_PENDING_EXCEPTION) { 193 java_lang_Throwable::print(PENDING_EXCEPTION, output()); 194 output()->cr(); 195 CLEAR_PENDING_EXCEPTION; 196 return; 197 } 198 199 // The result should be a [B 200 oop res = (oop)result.get_jobject(); 201 assert(res->is_typeArray(), "just checking"); 202 assert(typeArrayKlass::cast(res->klass())->element_type() == T_BYTE, "just checking"); 203 204 // copy the bytes to the output stream 205 typeArrayOop ba = typeArrayOop(res); 206 jbyte* addr = typeArrayOop(res)->byte_at_addr(0); 207 output()->print_raw((const char*)addr, ba->length()); 208 } 209 210 VMUptimeDCmd::VMUptimeDCmd(outputStream* output, bool heap) : 211 DCmdWithParser(output, heap), 212 _date("-date", "Add a prefix with current date", "BOOLEAN", false, "false") { 213 _dcmdparser.add_dcmd_option(&_date); 214 } 215 216 void VMUptimeDCmd::execute(TRAPS) { 217 if (_date.value()) { 218 output()->date_stamp(true, "", ": "); 219 } 220 output()->time_stamp().update_to(tty->time_stamp().ticks()); 221 output()->stamp(); 222 output()->print_cr(" s"); 223 } 224 225 int VMUptimeDCmd::num_arguments() { 226 ResourceMark rm; 227 VMUptimeDCmd* dcmd = new VMUptimeDCmd(NULL, false); 228 if (dcmd != NULL) { 229 DCmdMark mark(dcmd); 230 return dcmd->_dcmdparser.num_arguments(); 231 } else { 232 return 0; 233 } 234 } 235 236 void SystemGCDCmd::execute(TRAPS) { 237 Universe::heap()->collect(GCCause::_java_lang_system_gc); 238 } 239 240 void RunFinalizationDCmd::execute(TRAPS) { 241 klassOop k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_System(), 242 true, CHECK); 243 instanceKlassHandle klass(THREAD, k); 244 JavaValue result(T_VOID); 245 JavaCalls::call_static(&result, klass, 246 vmSymbols::run_finalization_name(), 247 vmSymbols::void_method_signature(), CHECK); 248 } 249 250 #ifndef SERVICES_KERNEL // Heap dumping not supported 251 HeapDumpDCmd::HeapDumpDCmd(outputStream* output, bool heap) : 252 DCmdWithParser(output, heap), 253 _filename("filename","Name of the dump file", "STRING",true), 254 _all("-all", "Dump all objects, including unreachable objects", 255 "BOOLEAN", false, "false") { 256 _dcmdparser.add_dcmd_option(&_all); 257 _dcmdparser.add_dcmd_argument(&_filename); 258 } 259 260 void HeapDumpDCmd::execute(TRAPS) { 261 // Request a full GC before heap dump if _all is false 262 // This helps reduces the amount of unreachable objects in the dump 263 // and makes it easier to browse. 264 HeapDumper dumper(!_all.value() /* request GC if _all is false*/); 265 int res = dumper.dump(_filename.value()); 266 if (res == 0) { 267 output()->print_cr("Heap dump file created"); 268 } else { 269 // heap dump failed 270 ResourceMark rm; 271 char* error = dumper.error_as_C_string(); 272 if (error == NULL) { 273 output()->print_cr("Dump failed - reason unknown"); 274 } else { 275 output()->print_cr("%s", error); 276 } 277 } 278 } 279 280 int HeapDumpDCmd::num_arguments() { 281 ResourceMark rm; 282 HeapDumpDCmd* dcmd = new HeapDumpDCmd(NULL, false); 283 if (dcmd != NULL) { 284 DCmdMark mark(dcmd); 285 return dcmd->_dcmdparser.num_arguments(); 286 } else { 287 return 0; 288 } 289 } 290 #endif // SERVICES_KERNEL 291 292 ClassHistogramDCmd::ClassHistogramDCmd(outputStream* output, bool heap) : 293 DCmdWithParser(output, heap), 294 _all("-all", "Inspect all objects, including unreachable objects", 295 "BOOLEAN", false, "false") { 296 _dcmdparser.add_dcmd_option(&_all); 297 } 298 299 void ClassHistogramDCmd::execute(TRAPS) { 300 VM_GC_HeapInspection heapop(output(), 301 !_all.value() /* request full gc if false */, 302 true /* need_prologue */); 303 VMThread::execute(&heapop); 304 } 305 306 int ClassHistogramDCmd::num_arguments() { 307 ResourceMark rm; 308 ClassHistogramDCmd* dcmd = new ClassHistogramDCmd(NULL, false); 309 if (dcmd != NULL) { 310 DCmdMark mark(dcmd); 311 return dcmd->_dcmdparser.num_arguments(); 312 } else { 313 return 0; 314 } 315 } 316 317 ThreadDumpDCmd::ThreadDumpDCmd(outputStream* output, bool heap) : 318 DCmdWithParser(output, heap), 319 _locks("-l", "print java.util.concurrent locks", "BOOLEAN", false, "false") { 320 _dcmdparser.add_dcmd_option(&_locks); 321 } 322 323 void ThreadDumpDCmd::execute(TRAPS) { 324 // thread stacks 325 VM_PrintThreads op1(output(), _locks.value()); 326 VMThread::execute(&op1); 327 328 // JNI global handles 329 VM_PrintJNI op2(output()); 330 VMThread::execute(&op2); 331 332 // Deadlock detection 333 VM_FindDeadlocks op3(output()); 334 VMThread::execute(&op3); 335 } 336 337 int ThreadDumpDCmd::num_arguments() { 338 ResourceMark rm; 339 ThreadDumpDCmd* dcmd = new ThreadDumpDCmd(NULL, false); 340 if (dcmd != NULL) { 341 DCmdMark mark(dcmd); 342 return dcmd->_dcmdparser.num_arguments(); 343 } else { 344 return 0; 345 } 346 }