1/*
2 * Copyright (c) 2011, 2019, 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 "jvm.h"
27#include "classfile/classLoaderHierarchyDCmd.hpp"
28#include "classfile/classLoaderStats.hpp"
29#include "compiler/compileBroker.hpp"
30#include "compiler/directivesParser.hpp"
31#include "gc/shared/gcVMOperations.hpp"
32#include "memory/metaspace/metaspaceDCmd.hpp"
33#include "memory/resourceArea.hpp"
34#include "memory/universe.hpp"
35#include "oops/objArrayOop.inline.hpp"
36#include "oops/oop.inline.hpp"
37#include "oops/typeArrayOop.inline.hpp"
38#include "runtime/fieldDescriptor.inline.hpp"
39#include "runtime/flags/jvmFlag.hpp"
40#include "runtime/handles.inline.hpp"
41#include "runtime/interfaceSupport.inline.hpp"
42#include "runtime/javaCalls.hpp"
43#include "runtime/os.hpp"
44#include "services/diagnosticArgument.hpp"
45#include "services/diagnosticCommand.hpp"
46#include "services/diagnosticFramework.hpp"
47#include "services/heapDumper.hpp"
48#include "services/management.hpp"
49#include "services/writeableFlags.hpp"
50#include "utilities/debug.hpp"
51#include "utilities/events.hpp"
52#include "utilities/formatBuffer.hpp"
53#include "utilities/macros.hpp"
54
55
56static void loadAgentModule(TRAPS) {
57 ResourceMark rm(THREAD);
58 HandleMark hm(THREAD);
59
60 JavaValue result(T_OBJECT);
61 Handle h_module_name = java_lang_String::create_from_str("jdk.management.agent", CHECK);
62 JavaCalls::call_static(&result,
63 SystemDictionary::module_Modules_klass(),
64 vmSymbols::loadModule_name(),
65 vmSymbols::loadModule_signature(),
66 h_module_name,
67 THREAD);
68}
69
70void DCmdRegistrant::register_dcmds(){
71 // Registration of the diagnostic commands
72 // First argument specifies which interfaces will export the command
73 // Second argument specifies if the command is enabled
74 // Third argument specifies if the command is hidden
75 uint32_t full_export = DCmd_Source_Internal | DCmd_Source_AttachAPI
76 | DCmd_Source_MBean;
77 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HelpDCmd>(full_export, true, false));
78 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VersionDCmd>(full_export, true, false));
79 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CommandLineDCmd>(full_export, true, false));
80 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<PrintSystemPropertiesDCmd>(full_export, true, false));
81 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<PrintVMFlagsDCmd>(full_export, true, false));
82 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<SetVMFlagDCmd>(full_export, true, false));
83 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VMDynamicLibrariesDCmd>(full_export, true, false));
84 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VMUptimeDCmd>(full_export, true, false));
85 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VMInfoDCmd>(full_export, true, false));
86 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<SystemGCDCmd>(full_export, true, false));
87 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<RunFinalizationDCmd>(full_export, true, false));
88 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HeapInfoDCmd>(full_export, true, false));
89 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<FinalizerInfoDCmd>(full_export, true, false));
90#if INCLUDE_SERVICES
91 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HeapDumpDCmd>(DCmd_Source_Internal | DCmd_Source_AttachAPI, true, false));
92 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassHistogramDCmd>(full_export, true, false));
93 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassStatsDCmd>(full_export, true, false));
94 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<SystemDictionaryDCmd>(full_export, true, false));
95 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassHierarchyDCmd>(full_export, true, false));
96 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<SymboltableDCmd>(full_export, true, false));
97 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<StringtableDCmd>(full_export, true, false));
98 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<metaspace::MetaspaceDCmd>(full_export, true, false));
99 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<EventLogDCmd>(full_export, true, false));
100#if INCLUDE_JVMTI // Both JVMTI and SERVICES have to be enabled to have this dcmd
101 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JVMTIAgentLoadDCmd>(full_export, true, false));
102#endif // INCLUDE_JVMTI
103#endif // INCLUDE_SERVICES
104#if INCLUDE_JVMTI
105 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JVMTIDataDumpDCmd>(full_export, true, false));
106#endif // INCLUDE_JVMTI
107 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ThreadDumpDCmd>(full_export, true, false));
108 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassLoaderStatsDCmd>(full_export, true, false));
109 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassLoaderHierarchyDCmd>(full_export, true, false));
110 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CompileQueueDCmd>(full_export, true, false));
111 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CodeListDCmd>(full_export, true, false));
112 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CodeCacheDCmd>(full_export, true, false));
113 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<TouchedMethodsDCmd>(full_export, true, false));
114 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CodeHeapAnalyticsDCmd>(full_export, true, false));
115
116 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CompilerDirectivesPrintDCmd>(full_export, true, false));
117 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CompilerDirectivesAddDCmd>(full_export, true, false));
118 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CompilerDirectivesRemoveDCmd>(full_export, true, false));
119 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CompilerDirectivesClearDCmd>(full_export, true, false));
120
121 // Enhanced JMX Agent Support
122 // These commands won't be exported via the DiagnosticCommandMBean until an
123 // appropriate permission is created for them
124 uint32_t jmx_agent_export_flags = DCmd_Source_Internal | DCmd_Source_AttachAPI;
125 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JMXStartRemoteDCmd>(jmx_agent_export_flags, true,false));
126 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JMXStartLocalDCmd>(jmx_agent_export_flags, true,false));
127 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JMXStopRemoteDCmd>(jmx_agent_export_flags, true,false));
128 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JMXStatusDCmd>(jmx_agent_export_flags, true,false));
129
130 // Debug on cmd (only makes sense with JVMTI since the agentlib needs it).
131#if INCLUDE_JVMTI
132 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<DebugOnCmdStartDCmd>(full_export, true, true));
133#endif // INCLUDE_JVMTI
134
135}
136
137#ifndef HAVE_EXTRA_DCMD
138void DCmdRegistrant::register_dcmds_ext(){
139 // Do nothing here
140}
141#endif
142
143
144HelpDCmd::HelpDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap),
145 _all("-all", "Show help for all commands", "BOOLEAN", false, "false"),
146 _cmd("command name", "The name of the command for which we want help",
147 "STRING", false) {
148 _dcmdparser.add_dcmd_option(&_all);
149 _dcmdparser.add_dcmd_argument(&_cmd);
150};
151
152
153static int compare_strings(const char** s1, const char** s2) {
154 return ::strcmp(*s1, *s2);
155}
156
157void HelpDCmd::execute(DCmdSource source, TRAPS) {
158 if (_all.value()) {
159 GrowableArray<const char*>* cmd_list = DCmdFactory::DCmd_list(source);
160 cmd_list->sort(compare_strings);
161 for (int i = 0; i < cmd_list->length(); i++) {
162 DCmdFactory* factory = DCmdFactory::factory(source, cmd_list->at(i),
163 strlen(cmd_list->at(i)));
164 output()->print_cr("%s%s", factory->name(),
165 factory->is_enabled() ? "" : " [disabled]");
166 output()->print_cr("\t%s", factory->description());
167 output()->cr();
168 factory = factory->next();
169 }
170 } else if (_cmd.has_value()) {
171 DCmd* cmd = NULL;
172 DCmdFactory* factory = DCmdFactory::factory(source, _cmd.value(),
173 strlen(_cmd.value()));
174 if (factory != NULL) {
175 output()->print_cr("%s%s", factory->name(),
176 factory->is_enabled() ? "" : " [disabled]");
177 output()->print_cr("%s", factory->description());
178 output()->print_cr("\nImpact: %s", factory->impact());
179 JavaPermission p = factory->permission();
180 if(p._class != NULL) {
181 if(p._action != NULL) {
182 output()->print_cr("\nPermission: %s(%s, %s)",
183 p._class, p._name == NULL ? "null" : p._name, p._action);
184 } else {
185 output()->print_cr("\nPermission: %s(%s)",
186 p._class, p._name == NULL ? "null" : p._name);
187 }
188 }
189 output()->cr();
190 cmd = factory->create_resource_instance(output());
191 if (cmd != NULL) {
192 DCmdMark mark(cmd);
193 cmd->print_help(factory->name());
194 }
195 } else {
196 output()->print_cr("Help unavailable : '%s' : No such command", _cmd.value());
197 }
198 } else {
199 output()->print_cr("The following commands are available:");
200 GrowableArray<const char *>* cmd_list = DCmdFactory::DCmd_list(source);
201 cmd_list->sort(compare_strings);
202 for (int i = 0; i < cmd_list->length(); i++) {
203 DCmdFactory* factory = DCmdFactory::factory(source, cmd_list->at(i),
204 strlen(cmd_list->at(i)));
205 output()->print_cr("%s%s", factory->name(),
206 factory->is_enabled() ? "" : " [disabled]");
207 factory = factory->_next;
208 }
209 output()->print_cr("\nFor more information about a specific command use 'help <command>'.");
210 }
211}
212
213int HelpDCmd::num_arguments() {
214 ResourceMark rm;
215 HelpDCmd* dcmd = new HelpDCmd(NULL, false);
216 if (dcmd != NULL) {
217 DCmdMark mark(dcmd);
218 return dcmd->_dcmdparser.num_arguments();
219 } else {
220 return 0;
221 }
222}
223
224void VersionDCmd::execute(DCmdSource source, TRAPS) {
225 output()->print_cr("%s version %s", VM_Version::vm_name(),
226 VM_Version::vm_release());
227 JDK_Version jdk_version = JDK_Version::current();
228 if (jdk_version.patch_version() > 0) {
229 output()->print_cr("JDK %d.%d.%d.%d", jdk_version.major_version(),
230 jdk_version.minor_version(), jdk_version.security_version(),
231 jdk_version.patch_version());
232 } else {
233 output()->print_cr("JDK %d.%d.%d", jdk_version.major_version(),
234 jdk_version.minor_version(), jdk_version.security_version());
235 }
236}
237
238PrintVMFlagsDCmd::PrintVMFlagsDCmd(outputStream* output, bool heap) :
239 DCmdWithParser(output, heap),
240 _all("-all", "Print all flags supported by the VM", "BOOLEAN", false, "false") {
241 _dcmdparser.add_dcmd_option(&_all);
242}
243
244void PrintVMFlagsDCmd::execute(DCmdSource source, TRAPS) {
245 if (_all.value()) {
246 JVMFlag::printFlags(output(), true);
247 } else {
248 JVMFlag::printSetFlags(output());
249 }
250}
251
252int PrintVMFlagsDCmd::num_arguments() {
253 ResourceMark rm;
254 PrintVMFlagsDCmd* dcmd = new PrintVMFlagsDCmd(NULL, false);
255 if (dcmd != NULL) {
256 DCmdMark mark(dcmd);
257 return dcmd->_dcmdparser.num_arguments();
258 } else {
259 return 0;
260 }
261}
262
263SetVMFlagDCmd::SetVMFlagDCmd(outputStream* output, bool heap) :
264 DCmdWithParser(output, heap),
265 _flag("flag name", "The name of the flag we want to set",
266 "STRING", true),
267 _value("string value", "The value we want to set", "STRING", false) {
268 _dcmdparser.add_dcmd_argument(&_flag);
269 _dcmdparser.add_dcmd_argument(&_value);
270}
271
272void SetVMFlagDCmd::execute(DCmdSource source, TRAPS) {
273 const char* val = NULL;
274 if (_value.value() != NULL) {
275 val = _value.value();
276 }
277
278 FormatBuffer<80> err_msg("%s", "");
279 int ret = WriteableFlags::set_flag(_flag.value(), val, JVMFlag::MANAGEMENT, err_msg);
280
281 if (ret != JVMFlag::SUCCESS) {
282 output()->print_cr("%s", err_msg.buffer());
283 }
284}
285
286int SetVMFlagDCmd::num_arguments() {
287 ResourceMark rm;
288 SetVMFlagDCmd* dcmd = new SetVMFlagDCmd(NULL, false);
289 if (dcmd != NULL) {
290 DCmdMark mark(dcmd);
291 return dcmd->_dcmdparser.num_arguments();
292 } else {
293 return 0;
294 }
295}
296
297void JVMTIDataDumpDCmd::execute(DCmdSource source, TRAPS) {
298 if (JvmtiExport::should_post_data_dump()) {
299 JvmtiExport::post_data_dump();
300 }
301}
302
303#if INCLUDE_SERVICES
304JVMTIAgentLoadDCmd::JVMTIAgentLoadDCmd(outputStream* output, bool heap) :
305 DCmdWithParser(output, heap),
306 _libpath("library path", "Absolute path of the JVMTI agent to load.",
307 "STRING", true),
308 _option("agent option", "Option string to pass the agent.", "STRING", false) {
309 _dcmdparser.add_dcmd_argument(&_libpath);
310 _dcmdparser.add_dcmd_argument(&_option);
311}
312
313void JVMTIAgentLoadDCmd::execute(DCmdSource source, TRAPS) {
314
315 if (_libpath.value() == NULL) {
316 output()->print_cr("JVMTI.agent_load dcmd needs library path.");
317 return;
318 }
319
320 char *suffix = strrchr(_libpath.value(), '.');
321 bool is_java_agent = (suffix != NULL) && (strncmp(".jar", suffix, 4) == 0);
322
323 if (is_java_agent) {
324 if (_option.value() == NULL) {
325 JvmtiExport::load_agent_library("instrument", "false",
326 _libpath.value(), output());
327 } else {
328 size_t opt_len = strlen(_libpath.value()) + strlen(_option.value()) + 2;
329 if (opt_len > 4096) {
330 output()->print_cr("JVMTI agent attach failed: Options is too long.");
331 return;
332 }
333
334 char *opt = (char *)os::malloc(opt_len, mtInternal);
335 if (opt == NULL) {
336 output()->print_cr("JVMTI agent attach failed: "
337 "Could not allocate " SIZE_FORMAT " bytes for argument.",
338 opt_len);
339 return;
340 }
341
342 jio_snprintf(opt, opt_len, "%s=%s", _libpath.value(), _option.value());
343 JvmtiExport::load_agent_library("instrument", "false", opt, output());
344
345 os::free(opt);
346 }
347 } else {
348 JvmtiExport::load_agent_library(_libpath.value(), "true",
349 _option.value(), output());
350 }
351}
352
353int JVMTIAgentLoadDCmd::num_arguments() {
354 ResourceMark rm;
355 JVMTIAgentLoadDCmd* dcmd = new JVMTIAgentLoadDCmd(NULL, false);
356 if (dcmd != NULL) {
357 DCmdMark mark(dcmd);
358 return dcmd->_dcmdparser.num_arguments();
359 } else {
360 return 0;
361 }
362}
363#endif // INCLUDE_SERVICES
364
365void PrintSystemPropertiesDCmd::execute(DCmdSource source, TRAPS) {
366 // load VMSupport
367 Symbol* klass = vmSymbols::jdk_internal_vm_VMSupport();
368 Klass* k = SystemDictionary::resolve_or_fail(klass, true, CHECK);
369 InstanceKlass* ik = InstanceKlass::cast(k);
370 if (ik->should_be_initialized()) {
371 ik->initialize(THREAD);
372 }
373 if (HAS_PENDING_EXCEPTION) {
374 java_lang_Throwable::print(PENDING_EXCEPTION, output());
375 output()->cr();
376 CLEAR_PENDING_EXCEPTION;
377 return;
378 }
379
380 // invoke the serializePropertiesToByteArray method
381 JavaValue result(T_OBJECT);
382 JavaCallArguments args;
383
384 Symbol* signature = vmSymbols::serializePropertiesToByteArray_signature();
385 JavaCalls::call_static(&result,
386 ik,
387 vmSymbols::serializePropertiesToByteArray_name(),
388 signature,
389 &args,
390 THREAD);
391 if (HAS_PENDING_EXCEPTION) {
392 java_lang_Throwable::print(PENDING_EXCEPTION, output());
393 output()->cr();
394 CLEAR_PENDING_EXCEPTION;
395 return;
396 }
397
398 // The result should be a [B
399 oop res = (oop)result.get_jobject();
400 assert(res->is_typeArray(), "just checking");
401 assert(TypeArrayKlass::cast(res->klass())->element_type() == T_BYTE, "just checking");
402
403 // copy the bytes to the output stream
404 typeArrayOop ba = typeArrayOop(res);
405 jbyte* addr = typeArrayOop(res)->byte_at_addr(0);
406 output()->print_raw((const char*)addr, ba->length());
407}
408
409VMUptimeDCmd::VMUptimeDCmd(outputStream* output, bool heap) :
410 DCmdWithParser(output, heap),
411 _date("-date", "Add a prefix with current date", "BOOLEAN", false, "false") {
412 _dcmdparser.add_dcmd_option(&_date);
413}
414
415void VMUptimeDCmd::execute(DCmdSource source, TRAPS) {
416 if (_date.value()) {
417 output()->date_stamp(true, "", ": ");
418 }
419 output()->time_stamp().update_to(tty->time_stamp().ticks());
420 output()->stamp();
421 output()->print_cr(" s");
422}
423
424int VMUptimeDCmd::num_arguments() {
425 ResourceMark rm;
426 VMUptimeDCmd* dcmd = new VMUptimeDCmd(NULL, false);
427 if (dcmd != NULL) {
428 DCmdMark mark(dcmd);
429 return dcmd->_dcmdparser.num_arguments();
430 } else {
431 return 0;
432 }
433}
434
435void VMInfoDCmd::execute(DCmdSource source, TRAPS) {
436 VMError::print_vm_info(_output);
437}
438
439void SystemGCDCmd::execute(DCmdSource source, TRAPS) {
440 Universe::heap()->collect(GCCause::_dcmd_gc_run);
441}
442
443void RunFinalizationDCmd::execute(DCmdSource source, TRAPS) {
444 Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_System(),
445 true, CHECK);
446 JavaValue result(T_VOID);
447 JavaCalls::call_static(&result, k,
448 vmSymbols::run_finalization_name(),
449 vmSymbols::void_method_signature(), CHECK);
450}
451
452void HeapInfoDCmd::execute(DCmdSource source, TRAPS) {
453 MutexLocker hl(Heap_lock);
454 Universe::heap()->print_on(output());
455}
456
457void FinalizerInfoDCmd::execute(DCmdSource source, TRAPS) {
458 ResourceMark rm;
459
460 Klass* k = SystemDictionary::resolve_or_fail(
461 vmSymbols::finalizer_histogram_klass(), true, CHECK);
462
463 JavaValue result(T_ARRAY);
464
465 // We are calling lang.ref.FinalizerHistogram.getFinalizerHistogram() method
466 // and expect it to return array of FinalizerHistogramEntry as Object[]
467
468 JavaCalls::call_static(&result, k,
469 vmSymbols::get_finalizer_histogram_name(),
470 vmSymbols::void_finalizer_histogram_entry_array_signature(), CHECK);
471
472 objArrayOop result_oop = (objArrayOop) result.get_jobject();
473 if (result_oop->length() == 0) {
474 output()->print_cr("No instances waiting for finalization found");
475 return;
476 }
477
478 oop foop = result_oop->obj_at(0);
479 InstanceKlass* ik = InstanceKlass::cast(foop->klass());
480
481 fieldDescriptor count_fd, name_fd;
482
483 Klass* count_res = ik->find_field(
484 vmSymbols::finalizer_histogram_entry_count_field(), vmSymbols::int_signature(), &count_fd);
485
486 Klass* name_res = ik->find_field(
487 vmSymbols::finalizer_histogram_entry_name_field(), vmSymbols::string_signature(), &name_fd);
488
489 assert(count_res != NULL && name_res != NULL, "Unexpected layout of FinalizerHistogramEntry");
490
491 output()->print_cr("Unreachable instances waiting for finalization");
492 output()->print_cr("#instances class name");
493 output()->print_cr("-----------------------");
494
495 for (int i = 0; i < result_oop->length(); ++i) {
496 oop element_oop = result_oop->obj_at(i);
497 oop str_oop = element_oop->obj_field(name_fd.offset());
498 char *name = java_lang_String::as_utf8_string(str_oop);
499 int count = element_oop->int_field(count_fd.offset());
500 output()->print_cr("%10d %s", count, name);
501 }
502}
503
504#if INCLUDE_SERVICES // Heap dumping/inspection supported
505HeapDumpDCmd::HeapDumpDCmd(outputStream* output, bool heap) :
506 DCmdWithParser(output, heap),
507 _filename("filename","Name of the dump file", "STRING",true),
508 _all("-all", "Dump all objects, including unreachable objects",
509 "BOOLEAN", false, "false") {
510 _dcmdparser.add_dcmd_option(&_all);
511 _dcmdparser.add_dcmd_argument(&_filename);
512}
513
514void HeapDumpDCmd::execute(DCmdSource source, TRAPS) {
515 // Request a full GC before heap dump if _all is false
516 // This helps reduces the amount of unreachable objects in the dump
517 // and makes it easier to browse.
518 HeapDumper dumper(!_all.value() /* request GC if _all is false*/);
519 int res = dumper.dump(_filename.value());
520 if (res == 0) {
521 output()->print_cr("Heap dump file created");
522 } else {
523 // heap dump failed
524 ResourceMark rm;
525 char* error = dumper.error_as_C_string();
526 if (error == NULL) {
527 output()->print_cr("Dump failed - reason unknown");
528 } else {
529 output()->print_cr("%s", error);
530 }
531 }
532}
533
534int HeapDumpDCmd::num_arguments() {
535 ResourceMark rm;
536 HeapDumpDCmd* dcmd = new HeapDumpDCmd(NULL, false);
537 if (dcmd != NULL) {
538 DCmdMark mark(dcmd);
539 return dcmd->_dcmdparser.num_arguments();
540 } else {
541 return 0;
542 }
543}
544
545ClassHistogramDCmd::ClassHistogramDCmd(outputStream* output, bool heap) :
546 DCmdWithParser(output, heap),
547 _all("-all", "Inspect all objects, including unreachable objects",
548 "BOOLEAN", false, "false") {
549 _dcmdparser.add_dcmd_option(&_all);
550}
551
552void ClassHistogramDCmd::execute(DCmdSource source, TRAPS) {
553 VM_GC_HeapInspection heapop(output(),
554 !_all.value() /* request full gc if false */);
555 VMThread::execute(&heapop);
556}
557
558int ClassHistogramDCmd::num_arguments() {
559 ResourceMark rm;
560 ClassHistogramDCmd* dcmd = new ClassHistogramDCmd(NULL, false);
561 if (dcmd != NULL) {
562 DCmdMark mark(dcmd);
563 return dcmd->_dcmdparser.num_arguments();
564 } else {
565 return 0;
566 }
567}
568
569#define DEFAULT_COLUMNS "InstBytes,KlassBytes,CpAll,annotations,MethodCount,Bytecodes,MethodAll,ROAll,RWAll,Total"
570ClassStatsDCmd::ClassStatsDCmd(outputStream* output, bool heap) :
571 DCmdWithParser(output, heap),
572 _all("-all", "Show all columns",
573 "BOOLEAN", false, "false"),
574 _csv("-csv", "Print in CSV (comma-separated values) format for spreadsheets",
575 "BOOLEAN", false, "false"),
576 _help("-help", "Show meaning of all the columns",
577 "BOOLEAN", false, "false"),
578 _columns("columns", "Comma-separated list of all the columns to show. "
579 "If not specified, the following columns are shown: " DEFAULT_COLUMNS,
580 "STRING", false) {
581 _dcmdparser.add_dcmd_option(&_all);
582 _dcmdparser.add_dcmd_option(&_csv);
583 _dcmdparser.add_dcmd_option(&_help);
584 _dcmdparser.add_dcmd_argument(&_columns);
585}
586
587void ClassStatsDCmd::execute(DCmdSource source, TRAPS) {
588 VM_GC_HeapInspection heapop(output(),
589 true /* request_full_gc */);
590 heapop.set_csv_format(_csv.value());
591 heapop.set_print_help(_help.value());
592 heapop.set_print_class_stats(true);
593 if (_all.value()) {
594 if (_columns.has_value()) {
595 output()->print_cr("Cannot specify -all and individual columns at the same time");
596 return;
597 } else {
598 heapop.set_columns(NULL);
599 }
600 } else {
601 if (_columns.has_value()) {
602 heapop.set_columns(_columns.value());
603 } else {
604 heapop.set_columns(DEFAULT_COLUMNS);
605 }
606 }
607 VMThread::execute(&heapop);
608}
609
610int ClassStatsDCmd::num_arguments() {
611 ResourceMark rm;
612 ClassStatsDCmd* dcmd = new ClassStatsDCmd(NULL, false);
613 if (dcmd != NULL) {
614 DCmdMark mark(dcmd);
615 return dcmd->_dcmdparser.num_arguments();
616 } else {
617 return 0;
618 }
619}
620#endif // INCLUDE_SERVICES
621
622ThreadDumpDCmd::ThreadDumpDCmd(outputStream* output, bool heap) :
623 DCmdWithParser(output, heap),
624 _locks("-l", "print java.util.concurrent locks", "BOOLEAN", false, "false"),
625 _extended("-e", "print extended thread information", "BOOLEAN", false, "false") {
626 _dcmdparser.add_dcmd_option(&_locks);
627 _dcmdparser.add_dcmd_option(&_extended);
628}
629
630void ThreadDumpDCmd::execute(DCmdSource source, TRAPS) {
631 // thread stacks
632 VM_PrintThreads op1(output(), _locks.value(), _extended.value());
633 VMThread::execute(&op1);
634
635 // JNI global handles
636 VM_PrintJNI op2(output());
637 VMThread::execute(&op2);
638
639 // Deadlock detection
640 VM_FindDeadlocks op3(output());
641 VMThread::execute(&op3);
642}
643
644int ThreadDumpDCmd::num_arguments() {
645 ResourceMark rm;
646 ThreadDumpDCmd* dcmd = new ThreadDumpDCmd(NULL, false);
647 if (dcmd != NULL) {
648 DCmdMark mark(dcmd);
649 return dcmd->_dcmdparser.num_arguments();
650 } else {
651 return 0;
652 }
653}
654
655// Enhanced JMX Agent support
656
657JMXStartRemoteDCmd::JMXStartRemoteDCmd(outputStream *output, bool heap_allocated) :
658
659 DCmdWithParser(output, heap_allocated),
660
661 _config_file
662 ("config.file",
663 "set com.sun.management.config.file", "STRING", false),
664
665 _jmxremote_host
666 ("jmxremote.host",
667 "set com.sun.management.jmxremote.host", "STRING", false),
668
669 _jmxremote_port
670 ("jmxremote.port",
671 "set com.sun.management.jmxremote.port", "STRING", false),
672
673 _jmxremote_rmi_port
674 ("jmxremote.rmi.port",
675 "set com.sun.management.jmxremote.rmi.port", "STRING", false),
676
677 _jmxremote_ssl
678 ("jmxremote.ssl",
679 "set com.sun.management.jmxremote.ssl", "STRING", false),
680
681 _jmxremote_registry_ssl
682 ("jmxremote.registry.ssl",
683 "set com.sun.management.jmxremote.registry.ssl", "STRING", false),
684
685 _jmxremote_authenticate
686 ("jmxremote.authenticate",
687 "set com.sun.management.jmxremote.authenticate", "STRING", false),
688
689 _jmxremote_password_file
690 ("jmxremote.password.file",
691 "set com.sun.management.jmxremote.password.file", "STRING", false),
692
693 _jmxremote_access_file
694 ("jmxremote.access.file",
695 "set com.sun.management.jmxremote.access.file", "STRING", false),
696
697 _jmxremote_login_config
698 ("jmxremote.login.config",
699 "set com.sun.management.jmxremote.login.config", "STRING", false),
700
701 _jmxremote_ssl_enabled_cipher_suites
702 ("jmxremote.ssl.enabled.cipher.suites",
703 "set com.sun.management.jmxremote.ssl.enabled.cipher.suite", "STRING", false),
704
705 _jmxremote_ssl_enabled_protocols
706 ("jmxremote.ssl.enabled.protocols",
707 "set com.sun.management.jmxremote.ssl.enabled.protocols", "STRING", false),
708
709 _jmxremote_ssl_need_client_auth
710 ("jmxremote.ssl.need.client.auth",
711 "set com.sun.management.jmxremote.need.client.auth", "STRING", false),
712
713 _jmxremote_ssl_config_file
714 ("jmxremote.ssl.config.file",
715 "set com.sun.management.jmxremote.ssl_config_file", "STRING", false),
716
717// JDP Protocol support
718 _jmxremote_autodiscovery
719 ("jmxremote.autodiscovery",
720 "set com.sun.management.jmxremote.autodiscovery", "STRING", false),
721
722 _jdp_port
723 ("jdp.port",
724 "set com.sun.management.jdp.port", "INT", false),
725
726 _jdp_address
727 ("jdp.address",
728 "set com.sun.management.jdp.address", "STRING", false),
729
730 _jdp_source_addr
731 ("jdp.source_addr",
732 "set com.sun.management.jdp.source_addr", "STRING", false),
733
734 _jdp_ttl
735 ("jdp.ttl",
736 "set com.sun.management.jdp.ttl", "INT", false),
737
738 _jdp_pause
739 ("jdp.pause",
740 "set com.sun.management.jdp.pause", "INT", false),
741
742 _jdp_name
743 ("jdp.name",
744 "set com.sun.management.jdp.name", "STRING", false)
745
746 {
747 _dcmdparser.add_dcmd_option(&_config_file);
748 _dcmdparser.add_dcmd_option(&_jmxremote_host);
749 _dcmdparser.add_dcmd_option(&_jmxremote_port);
750 _dcmdparser.add_dcmd_option(&_jmxremote_rmi_port);
751 _dcmdparser.add_dcmd_option(&_jmxremote_ssl);
752 _dcmdparser.add_dcmd_option(&_jmxremote_registry_ssl);
753 _dcmdparser.add_dcmd_option(&_jmxremote_authenticate);
754 _dcmdparser.add_dcmd_option(&_jmxremote_password_file);
755 _dcmdparser.add_dcmd_option(&_jmxremote_access_file);
756 _dcmdparser.add_dcmd_option(&_jmxremote_login_config);
757 _dcmdparser.add_dcmd_option(&_jmxremote_ssl_enabled_cipher_suites);
758 _dcmdparser.add_dcmd_option(&_jmxremote_ssl_enabled_protocols);
759 _dcmdparser.add_dcmd_option(&_jmxremote_ssl_need_client_auth);
760 _dcmdparser.add_dcmd_option(&_jmxremote_ssl_config_file);
761 _dcmdparser.add_dcmd_option(&_jmxremote_autodiscovery);
762 _dcmdparser.add_dcmd_option(&_jdp_port);
763 _dcmdparser.add_dcmd_option(&_jdp_address);
764 _dcmdparser.add_dcmd_option(&_jdp_source_addr);
765 _dcmdparser.add_dcmd_option(&_jdp_ttl);
766 _dcmdparser.add_dcmd_option(&_jdp_pause);
767 _dcmdparser.add_dcmd_option(&_jdp_name);
768}
769
770
771int JMXStartRemoteDCmd::num_arguments() {
772 ResourceMark rm;
773 JMXStartRemoteDCmd* dcmd = new JMXStartRemoteDCmd(NULL, false);
774 if (dcmd != NULL) {
775 DCmdMark mark(dcmd);
776 return dcmd->_dcmdparser.num_arguments();
777 } else {
778 return 0;
779 }
780}
781
782
783void JMXStartRemoteDCmd::execute(DCmdSource source, TRAPS) {
784 ResourceMark rm(THREAD);
785 HandleMark hm(THREAD);
786
787 // Load and initialize the jdk.internal.agent.Agent class
788 // invoke startRemoteManagementAgent(string) method to start
789 // the remote management server.
790 // throw java.lang.NoSuchMethodError if the method doesn't exist
791
792 loadAgentModule(CHECK);
793 Handle loader = Handle(THREAD, SystemDictionary::java_system_loader());
794 Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::jdk_internal_agent_Agent(), loader, Handle(), true, CHECK);
795
796 JavaValue result(T_VOID);
797
798 // Pass all command line arguments to java as key=value,...
799 // All checks are done on java side
800
801 int len = 0;
802 stringStream options;
803 char comma[2] = {0,0};
804
805 // Leave default values on Agent.class side and pass only
806 // agruments explicitly set by user. All arguments passed
807 // to jcmd override properties with the same name set by
808 // command line with -D or by managmenent.properties
809 // file.
810#define PUT_OPTION(a) \
811 do { \
812 if ( (a).is_set() ){ \
813 if ( *((a).type()) == 'I' ) { \
814 options.print("%scom.sun.management.%s=" JLONG_FORMAT, comma, (a).name(), (jlong)((a).value())); \
815 } else { \
816 options.print("%scom.sun.management.%s=%s", comma, (a).name(), (char*)((a).value())); \
817 } \
818 comma[0] = ','; \
819 }\
820 } while(0);
821
822
823 PUT_OPTION(_config_file);
824 PUT_OPTION(_jmxremote_host);
825 PUT_OPTION(_jmxremote_port);
826 PUT_OPTION(_jmxremote_rmi_port);
827 PUT_OPTION(_jmxremote_ssl);
828 PUT_OPTION(_jmxremote_registry_ssl);
829 PUT_OPTION(_jmxremote_authenticate);
830 PUT_OPTION(_jmxremote_password_file);
831 PUT_OPTION(_jmxremote_access_file);
832 PUT_OPTION(_jmxremote_login_config);
833 PUT_OPTION(_jmxremote_ssl_enabled_cipher_suites);
834 PUT_OPTION(_jmxremote_ssl_enabled_protocols);
835 PUT_OPTION(_jmxremote_ssl_need_client_auth);
836 PUT_OPTION(_jmxremote_ssl_config_file);
837 PUT_OPTION(_jmxremote_autodiscovery);
838 PUT_OPTION(_jdp_port);
839 PUT_OPTION(_jdp_address);
840 PUT_OPTION(_jdp_source_addr);
841 PUT_OPTION(_jdp_ttl);
842 PUT_OPTION(_jdp_pause);
843 PUT_OPTION(_jdp_name);
844
845#undef PUT_OPTION
846
847 Handle str = java_lang_String::create_from_str(options.as_string(), CHECK);
848 JavaCalls::call_static(&result, k, vmSymbols::startRemoteAgent_name(), vmSymbols::string_void_signature(), str, CHECK);
849}
850
851JMXStartLocalDCmd::JMXStartLocalDCmd(outputStream *output, bool heap_allocated) :
852 DCmd(output, heap_allocated) {
853 // do nothing
854}
855
856void JMXStartLocalDCmd::execute(DCmdSource source, TRAPS) {
857 ResourceMark rm(THREAD);
858 HandleMark hm(THREAD);
859
860 // Load and initialize the jdk.internal.agent.Agent class
861 // invoke startLocalManagementAgent(void) method to start
862 // the local management server
863 // throw java.lang.NoSuchMethodError if method doesn't exist
864
865 loadAgentModule(CHECK);
866 Handle loader = Handle(THREAD, SystemDictionary::java_system_loader());
867 Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::jdk_internal_agent_Agent(), loader, Handle(), true, CHECK);
868
869 JavaValue result(T_VOID);
870 JavaCalls::call_static(&result, k, vmSymbols::startLocalAgent_name(), vmSymbols::void_method_signature(), CHECK);
871}
872
873void JMXStopRemoteDCmd::execute(DCmdSource source, TRAPS) {
874 ResourceMark rm(THREAD);
875 HandleMark hm(THREAD);
876
877 // Load and initialize the jdk.internal.agent.Agent class
878 // invoke stopRemoteManagementAgent method to stop the
879 // management server
880 // throw java.lang.NoSuchMethodError if method doesn't exist
881
882 loadAgentModule(CHECK);
883 Handle loader = Handle(THREAD, SystemDictionary::java_system_loader());
884 Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::jdk_internal_agent_Agent(), loader, Handle(), true, CHECK);
885
886 JavaValue result(T_VOID);
887 JavaCalls::call_static(&result, k, vmSymbols::stopRemoteAgent_name(), vmSymbols::void_method_signature(), CHECK);
888}
889
890JMXStatusDCmd::JMXStatusDCmd(outputStream *output, bool heap_allocated) :
891 DCmd(output, heap_allocated) {
892 // do nothing
893}
894
895void JMXStatusDCmd::execute(DCmdSource source, TRAPS) {
896 ResourceMark rm(THREAD);
897 HandleMark hm(THREAD);
898
899 // Load and initialize the jdk.internal.agent.Agent class
900 // invoke getManagementAgentStatus() method to generate the status info
901 // throw java.lang.NoSuchMethodError if method doesn't exist
902
903 loadAgentModule(CHECK);
904 Handle loader = Handle(THREAD, SystemDictionary::java_system_loader());
905 Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::jdk_internal_agent_Agent(), loader, Handle(), true, CHECK);
906
907 JavaValue result(T_OBJECT);
908 JavaCalls::call_static(&result, k, vmSymbols::getAgentStatus_name(), vmSymbols::void_string_signature(), CHECK);
909
910 jvalue* jv = (jvalue*) result.get_value_addr();
911 oop str = (oop) jv->l;
912 if (str != NULL) {
913 char* out = java_lang_String::as_utf8_string(str);
914 if (out) {
915 output()->print_cr("%s", out);
916 return;
917 }
918 }
919 output()->print_cr("Error obtaining management agent status");
920}
921
922VMDynamicLibrariesDCmd::VMDynamicLibrariesDCmd(outputStream *output, bool heap_allocated) :
923 DCmd(output, heap_allocated) {
924 // do nothing
925}
926
927void VMDynamicLibrariesDCmd::execute(DCmdSource source, TRAPS) {
928 os::print_dll_info(output());
929 output()->cr();
930}
931
932void CompileQueueDCmd::execute(DCmdSource source, TRAPS) {
933 VM_PrintCompileQueue printCompileQueueOp(output());
934 VMThread::execute(&printCompileQueueOp);
935}
936
937void CodeListDCmd::execute(DCmdSource source, TRAPS) {
938 CodeCache::print_codelist(output());
939}
940
941void CodeCacheDCmd::execute(DCmdSource source, TRAPS) {
942 CodeCache::print_layout(output());
943}
944
945//---< BEGIN >--- CodeHeap State Analytics.
946CodeHeapAnalyticsDCmd::CodeHeapAnalyticsDCmd(outputStream* output, bool heap) :
947 DCmdWithParser(output, heap),
948 _function("function", "Function to be performed (aggregate, UsedSpace, FreeSpace, MethodCount, MethodSpace, MethodAge, MethodNames, discard", "STRING", false, "all"),
949 _granularity("granularity", "Detail level - smaller value -> more detail", "INT", false, "4096") {
950 _dcmdparser.add_dcmd_argument(&_function);
951 _dcmdparser.add_dcmd_argument(&_granularity);
952}
953
954void CodeHeapAnalyticsDCmd::execute(DCmdSource source, TRAPS) {
955 jlong granularity = _granularity.value();
956 if (granularity < 1) {
957 Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_IllegalArgumentException(),
958 "Invalid granularity value " JLONG_FORMAT ". Should be positive.\n", granularity);
959 return;
960 }
961
962 CompileBroker::print_heapinfo(output(), _function.value(), granularity);
963}
964
965int CodeHeapAnalyticsDCmd::num_arguments() {
966 ResourceMark rm;
967 CodeHeapAnalyticsDCmd* dcmd = new CodeHeapAnalyticsDCmd(NULL, false);
968 if (dcmd != NULL) {
969 DCmdMark mark(dcmd);
970 return dcmd->_dcmdparser.num_arguments();
971 } else {
972 return 0;
973 }
974}
975//---< END >--- CodeHeap State Analytics.
976
977EventLogDCmd::EventLogDCmd(outputStream* output, bool heap) :
978 DCmdWithParser(output, heap),
979 _log("log", "Name of log to be printed. If omitted, all logs are printed.", "STRING", false, NULL),
980 _max("max", "Maximum number of events to be printed (newest first). If omitted, all events are printed.", "STRING", false, NULL)
981{
982 _dcmdparser.add_dcmd_option(&_log);
983 _dcmdparser.add_dcmd_option(&_max);
984}
985
986void EventLogDCmd::execute(DCmdSource source, TRAPS) {
987 const char* max_value = _max.value();
988 long max = -1;
989 if (max_value != NULL) {
990 char* endptr = NULL;
991 max = ::strtol(max_value, &endptr, 10);
992 if (max == 0 && max_value == endptr) {
993 output()->print_cr("Invalid max option: \"%s\".", max_value);
994 return;
995 }
996 }
997 const char* log_name = _log.value();
998 if (log_name != NULL) {
999 Events::print_one(output(), log_name, max);
1000 } else {
1001 Events::print_all(output(), max);
1002 }
1003}
1004
1005int EventLogDCmd::num_arguments() {
1006 ResourceMark rm;
1007 EventLogDCmd* dcmd = new EventLogDCmd(NULL, false);
1008 if (dcmd != NULL) {
1009 DCmdMark mark(dcmd);
1010 return dcmd->_dcmdparser.num_arguments();
1011 } else {
1012 return 0;
1013 }
1014}
1015
1016void CompilerDirectivesPrintDCmd::execute(DCmdSource source, TRAPS) {
1017 DirectivesStack::print(output());
1018}
1019
1020CompilerDirectivesAddDCmd::CompilerDirectivesAddDCmd(outputStream* output, bool heap) :
1021 DCmdWithParser(output, heap),
1022 _filename("filename","Name of the directives file", "STRING",true) {
1023 _dcmdparser.add_dcmd_argument(&_filename);
1024}
1025
1026void CompilerDirectivesAddDCmd::execute(DCmdSource source, TRAPS) {
1027 DirectivesParser::parse_from_file(_filename.value(), output());
1028}
1029
1030int CompilerDirectivesAddDCmd::num_arguments() {
1031 ResourceMark rm;
1032 CompilerDirectivesAddDCmd* dcmd = new CompilerDirectivesAddDCmd(NULL, false);
1033 if (dcmd != NULL) {
1034 DCmdMark mark(dcmd);
1035 return dcmd->_dcmdparser.num_arguments();
1036 } else {
1037 return 0;
1038 }
1039}
1040
1041void CompilerDirectivesRemoveDCmd::execute(DCmdSource source, TRAPS) {
1042 DirectivesStack::pop(1);
1043}
1044
1045void CompilerDirectivesClearDCmd::execute(DCmdSource source, TRAPS) {
1046 DirectivesStack::clear();
1047}
1048#if INCLUDE_SERVICES
1049ClassHierarchyDCmd::ClassHierarchyDCmd(outputStream* output, bool heap) :
1050 DCmdWithParser(output, heap),
1051 _print_interfaces("-i", "Inherited interfaces should be printed.", "BOOLEAN", false, "false"),
1052 _print_subclasses("-s", "If a classname is specified, print its subclasses. "
1053 "Otherwise only its superclasses are printed.", "BOOLEAN", false, "false"),
1054 _classname("classname", "Name of class whose hierarchy should be printed. "
1055 "If not specified, all class hierarchies are printed.",
1056 "STRING", false) {
1057 _dcmdparser.add_dcmd_option(&_print_interfaces);
1058 _dcmdparser.add_dcmd_option(&_print_subclasses);
1059 _dcmdparser.add_dcmd_argument(&_classname);
1060}
1061
1062void ClassHierarchyDCmd::execute(DCmdSource source, TRAPS) {
1063 VM_PrintClassHierarchy printClassHierarchyOp(output(), _print_interfaces.value(),
1064 _print_subclasses.value(), _classname.value());
1065 VMThread::execute(&printClassHierarchyOp);
1066}
1067
1068int ClassHierarchyDCmd::num_arguments() {
1069 ResourceMark rm;
1070 ClassHierarchyDCmd* dcmd = new ClassHierarchyDCmd(NULL, false);
1071 if (dcmd != NULL) {
1072 DCmdMark mark(dcmd);
1073 return dcmd->_dcmdparser.num_arguments();
1074 } else {
1075 return 0;
1076 }
1077}
1078
1079#endif
1080
1081class VM_DumpTouchedMethods : public VM_Operation {
1082private:
1083 outputStream* _out;
1084public:
1085 VM_DumpTouchedMethods(outputStream* out) {
1086 _out = out;
1087 }
1088
1089 virtual VMOp_Type type() const { return VMOp_DumpTouchedMethods; }
1090
1091 virtual void doit() {
1092 Method::print_touched_methods(_out);
1093 }
1094};
1095
1096TouchedMethodsDCmd::TouchedMethodsDCmd(outputStream* output, bool heap) :
1097 DCmdWithParser(output, heap)
1098{}
1099
1100void TouchedMethodsDCmd::execute(DCmdSource source, TRAPS) {
1101 if (!LogTouchedMethods) {
1102 output()->print_cr("VM.print_touched_methods command requires -XX:+LogTouchedMethods");
1103 return;
1104 }
1105 VM_DumpTouchedMethods dumper(output());
1106 VMThread::execute(&dumper);
1107}
1108
1109int TouchedMethodsDCmd::num_arguments() {
1110 return 0;
1111}
1112
1113#if INCLUDE_JVMTI
1114extern "C" typedef char const* (JNICALL *debugInit_startDebuggingViaCommandPtr)(JNIEnv* env, jthread thread, char const** transport_name,
1115 char const** address, jboolean* first_start);
1116static debugInit_startDebuggingViaCommandPtr dvc_start_ptr = NULL;
1117
1118DebugOnCmdStartDCmd::DebugOnCmdStartDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap) {
1119}
1120
1121void DebugOnCmdStartDCmd::execute(DCmdSource source, TRAPS) {
1122 char const* transport = NULL;
1123 char const* addr = NULL;
1124 jboolean is_first_start = JNI_FALSE;
1125 JavaThread* thread = (JavaThread*) THREAD;
1126 jthread jt = JNIHandles::make_local(thread->threadObj());
1127 ThreadToNativeFromVM ttn(thread);
1128 const char *error = "Could not find jdwp agent.";
1129
1130 if (!dvc_start_ptr) {
1131 for (AgentLibrary* agent = Arguments::agents(); agent != NULL; agent = agent->next()) {
1132 if ((strcmp("jdwp", agent->name()) == 0) && (dvc_start_ptr == NULL)) {
1133 char const* func = "debugInit_startDebuggingViaCommand";
1134 dvc_start_ptr = (debugInit_startDebuggingViaCommandPtr) os::find_agent_function(agent, false, &func, 1);
1135 }
1136 }
1137 }
1138
1139 if (dvc_start_ptr) {
1140 error = dvc_start_ptr(thread->jni_environment(), jt, &transport, &addr, &is_first_start);
1141 }
1142
1143 if (error != NULL) {
1144 output()->print_cr("Debugging has not been started: %s", error);
1145 } else {
1146 output()->print_cr(is_first_start ? "Debugging has been started." : "Debugging is already active.");
1147 output()->print_cr("Transport : %s", transport ? transport : "#unknown");
1148 output()->print_cr("Address : %s", addr ? addr : "#unknown");
1149 }
1150}
1151#endif // INCLUDE_JVMTI
1152