1 /*
2 * Copyright (c) 2011, 2025, 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 "cds/cds_globals.hpp"
26 #include "cds/cdsConfig.hpp"
27 #include "cds/cdsEndTrainingUpcall.hpp"
28 #include "classfile/classLoaderDataGraph.hpp"
29 #include "classfile/classLoaderHierarchyDCmd.hpp"
30 #include "classfile/classLoaderStats.hpp"
31 #include "classfile/javaClasses.hpp"
32 #include "classfile/systemDictionary.hpp"
33 #include "classfile/vmClasses.hpp"
34 #include "code/codeCache.hpp"
35 #include "compiler/compilationMemoryStatistic.hpp"
36 #include "compiler/compileBroker.hpp"
37 #include "compiler/compiler_globals.hpp"
38 #include "compiler/directivesParser.hpp"
39 #include "gc/shared/gcVMOperations.hpp"
40 #include "jvm.h"
41 #include "memory/metaspace/metaspaceDCmd.hpp"
42 #include "memory/metaspaceUtils.hpp"
43 #include "memory/resourceArea.hpp"
44 #include "memory/universe.hpp"
45 #include "nmt/memMapPrinter.hpp"
46 #include "nmt/memTracker.hpp"
47 #include "nmt/nmtDCmd.hpp"
48 #include "oops/instanceKlass.hpp"
49 #include "oops/objArrayOop.inline.hpp"
50 #include "oops/oop.inline.hpp"
51 #include "oops/typeArrayOop.inline.hpp"
52 #include "prims/jvmtiAgentList.hpp"
53 #include "runtime/fieldDescriptor.inline.hpp"
54 #include "runtime/flags/jvmFlag.hpp"
55 #include "runtime/handles.inline.hpp"
56 #include "runtime/javaCalls.hpp"
57 #include "runtime/jniHandles.hpp"
58 #include "runtime/os.hpp"
59 #include "runtime/vm_version.hpp"
60 #include "runtime/vmOperations.hpp"
61 #include "services/diagnosticArgument.hpp"
62 #include "services/diagnosticCommand.hpp"
63 #include "services/diagnosticFramework.hpp"
64 #include "services/heapDumper.hpp"
65 #include "services/management.hpp"
66 #include "services/writeableFlags.hpp"
67 #include "utilities/debug.hpp"
68 #include "utilities/events.hpp"
69 #include "utilities/formatBuffer.hpp"
70 #include "utilities/macros.hpp"
71 #include "utilities/parseInteger.hpp"
72 #ifdef LINUX
73 #include "mallocInfoDcmd.hpp"
74 #include "os_posix.hpp"
75 #include "trimCHeapDCmd.hpp"
76
77 #include <errno.h>
78 #endif
79
80 static void loadAgentModule(TRAPS) {
81 ResourceMark rm(THREAD);
82 HandleMark hm(THREAD);
83
84 JavaValue result(T_OBJECT);
85 Handle h_module_name = java_lang_String::create_from_str("jdk.management.agent", CHECK);
86 JavaCalls::call_static(&result,
87 vmClasses::module_Modules_klass(),
88 vmSymbols::loadModule_name(),
89 vmSymbols::loadModule_signature(),
90 h_module_name,
91 THREAD);
92 }
93
94 void DCmd::register_dcmds(){
95 // Registration of the diagnostic commands
96 // First argument specifies which interfaces will export the command
97 // Second argument specifies if the command is enabled
98 // Third argument specifies if the command is hidden
99 uint32_t full_export = DCmd_Source_Internal | DCmd_Source_AttachAPI
100 | DCmd_Source_MBean;
101 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HelpDCmd>(full_export, true, false));
102 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VersionDCmd>(full_export, true, false));
103 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CommandLineDCmd>(full_export, true, false));
104 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<PrintSystemPropertiesDCmd>(full_export, true, false));
105 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<PrintVMFlagsDCmd>(full_export, true, false));
106 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<SetVMFlagDCmd>(full_export, true, false));
107 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VMDynamicLibrariesDCmd>(full_export, true, false));
108 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VMUptimeDCmd>(full_export, true, false));
109 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VMInfoDCmd>(full_export, true, false));
110 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<SystemGCDCmd>(full_export, true, false));
111 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<RunFinalizationDCmd>(full_export, true, false));
112 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HeapInfoDCmd>(full_export, true, false));
113 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<FinalizerInfoDCmd>(full_export, true, false));
114 #if INCLUDE_SERVICES
115 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<HeapDumpDCmd>(DCmd_Source_Internal | DCmd_Source_AttachAPI, true, false));
116 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassHistogramDCmd>(full_export, true, false));
117 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<SystemDictionaryDCmd>(full_export, true, false));
118 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassHierarchyDCmd>(full_export, true, false));
119 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassesDCmd>(full_export, true, false));
120 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<SymboltableDCmd>(full_export, true, false));
121 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<StringtableDCmd>(full_export, true, false));
122 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<metaspace::MetaspaceDCmd>(full_export, true, false));
123 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<EventLogDCmd>(full_export, true, false));
124 #if INCLUDE_JVMTI // Both JVMTI and SERVICES have to be enabled to have this dcmd
125 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JVMTIAgentLoadDCmd>(full_export, true, false));
126 #endif // INCLUDE_JVMTI
127 #endif // INCLUDE_SERVICES
128 #if INCLUDE_JVMTI
129 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JVMTIDataDumpDCmd>(full_export, true, false));
130 #endif // INCLUDE_JVMTI
131 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ThreadDumpDCmd>(full_export, true, false));
132 #if INCLUDE_JVMTI
133 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ThreadDumpToFileDCmd>(full_export, true, false));
134 #endif // INCLUDE_JVMTI
135 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VThreadSchedulerDCmd>(full_export, true, false));
136 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<VThreadPollersDCmd>(full_export, true, false));
137 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassLoaderStatsDCmd>(full_export, true, false));
138 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassLoaderHierarchyDCmd>(full_export, true, false));
139 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CompileQueueDCmd>(full_export, true, false));
140 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CodeListDCmd>(full_export, true, false));
141 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CodeCacheDCmd>(full_export, true, false));
142 #if INCLUDE_CDS
143 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<AOTEndTrainingDCmd>(full_export, true, false));
144 #endif // INCLUDE_CDS
145 #ifdef LINUX
146 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<PerfMapDCmd>(full_export, true, false));
147 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<TrimCLibcHeapDCmd>(full_export, true, false));
148 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<MallocInfoDcmd>(full_export, true, false));
149 #endif // LINUX
150 #if defined(LINUX) || defined(_WIN64) || defined(__APPLE__)
151 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<SystemMapDCmd>(full_export, true,false));
152 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<SystemDumpMapDCmd>(full_export, true,false));
153 #endif // LINUX or WINDOWS or MacOS
154 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CodeHeapAnalyticsDCmd>(full_export, true, false));
155
156 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CompilerDirectivesPrintDCmd>(full_export, true, false));
157 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CompilerDirectivesAddDCmd>(full_export, true, false));
158 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CompilerDirectivesRemoveDCmd>(full_export, true, false));
159 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CompilerDirectivesClearDCmd>(full_export, true, false));
160 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<CompilationMemoryStatisticDCmd>(full_export, true, false));
161
162 // Enhanced JMX Agent Support
163 // These commands not currently exported via the DiagnosticCommandMBean
164 uint32_t jmx_agent_export_flags = DCmd_Source_Internal | DCmd_Source_AttachAPI;
165 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JMXStartRemoteDCmd>(jmx_agent_export_flags, true,false));
166 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JMXStartLocalDCmd>(jmx_agent_export_flags, true,false));
167 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JMXStopRemoteDCmd>(jmx_agent_export_flags, true,false));
168 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JMXStatusDCmd>(jmx_agent_export_flags, true,false));
169
170 #if INCLUDE_CDS
171 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<DumpSharedArchiveDCmd>(full_export, true, false));
172 #endif // INCLUDE_CDS
173
174 DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<NMTDCmd>(full_export, true, false));
175 }
176
177 HelpDCmd::HelpDCmd(outputStream* output, bool heap) : DCmdWithParser(output, heap),
178 _all("-all", "Show help for all commands", "BOOLEAN", false, "false"),
179 _cmd("command name", "The name of the command for which we want help",
180 "STRING", false) {
181 _dcmdparser.add_dcmd_option(&_all);
182 _dcmdparser.add_dcmd_argument(&_cmd);
183 };
184
185
186 static int compare_strings(const char** s1, const char** s2) {
187 return ::strcmp(*s1, *s2);
188 }
189
190 void HelpDCmd::execute(DCmdSource source, TRAPS) {
191 if (_all.value()) {
192 GrowableArray<const char*>* cmd_list = DCmdFactory::DCmd_list(source);
193 cmd_list->sort(compare_strings);
194 for (int i = 0; i < cmd_list->length(); i++) {
195 DCmdFactory* factory = DCmdFactory::factory(source, cmd_list->at(i),
196 strlen(cmd_list->at(i)));
197 output()->print_cr("%s%s", factory->name(),
198 factory->is_enabled() ? "" : " [disabled]");
199 output()->print_cr("\t%s", factory->description());
200 output()->cr();
201 factory = factory->next();
202 }
203 } else if (_cmd.has_value()) {
204 DCmd* cmd = nullptr;
205 DCmdFactory* factory = DCmdFactory::factory(source, _cmd.value(),
206 strlen(_cmd.value()));
207 if (factory != nullptr) {
208 output()->print_cr("%s%s", factory->name(),
209 factory->is_enabled() ? "" : " [disabled]");
210 output()->print_cr("%s", factory->description());
211 output()->print_cr("\nImpact: %s", factory->impact());
212 output()->cr();
213 cmd = factory->create_resource_instance(output());
214 if (cmd != nullptr) {
215 DCmdMark mark(cmd);
216 cmd->print_help(factory->name());
217 }
218 } else {
219 output()->print_cr("Help unavailable : '%s' : No such command", _cmd.value());
220 }
221 } else {
222 output()->print_cr("The following commands are available:");
223 GrowableArray<const char *>* cmd_list = DCmdFactory::DCmd_list(source);
224 cmd_list->sort(compare_strings);
225 for (int i = 0; i < cmd_list->length(); i++) {
226 DCmdFactory* factory = DCmdFactory::factory(source, cmd_list->at(i),
227 strlen(cmd_list->at(i)));
228 output()->print_cr("%s%s", factory->name(),
229 factory->is_enabled() ? "" : " [disabled]");
230 factory = factory->_next;
231 }
232 output()->print_cr("\nFor more information about a specific command use 'help <command>'.");
233 }
234 }
235
236 void VersionDCmd::execute(DCmdSource source, TRAPS) {
237 output()->print_cr("%s version %s", VM_Version::vm_name(),
238 VM_Version::vm_release());
239 JDK_Version jdk_version = JDK_Version::current();
240 if (jdk_version.patch_version() > 0) {
241 output()->print_cr("JDK %d.%d.%d.%d", jdk_version.major_version(),
242 jdk_version.minor_version(), jdk_version.security_version(),
243 jdk_version.patch_version());
244 } else {
245 output()->print_cr("JDK %d.%d.%d", jdk_version.major_version(),
246 jdk_version.minor_version(), jdk_version.security_version());
247 }
248 }
249
250 PrintVMFlagsDCmd::PrintVMFlagsDCmd(outputStream* output, bool heap) :
251 DCmdWithParser(output, heap),
252 _all("-all", "Print all flags supported by the VM", "BOOLEAN", false, "false") {
253 _dcmdparser.add_dcmd_option(&_all);
254 }
255
256 void PrintVMFlagsDCmd::execute(DCmdSource source, TRAPS) {
257 if (_all.value()) {
258 JVMFlag::printFlags(output(), true);
259 } else {
260 JVMFlag::printSetFlags(output());
261 }
262 }
263
264 SetVMFlagDCmd::SetVMFlagDCmd(outputStream* output, bool heap) :
265 DCmdWithParser(output, heap),
266 _flag("flag name", "The name of the flag we want to set",
267 "STRING", true),
268 _value("string value", "The value we want to set", "STRING", false) {
269 _dcmdparser.add_dcmd_argument(&_flag);
270 _dcmdparser.add_dcmd_argument(&_value);
271 }
272
273 void SetVMFlagDCmd::execute(DCmdSource source, TRAPS) {
274 const char* val = nullptr;
275 if (_value.value() != nullptr) {
276 val = _value.value();
277 }
278
279 FormatBuffer<80> err_msg("%s", "");
280 int ret = WriteableFlags::set_flag(_flag.value(), val, JVMFlagOrigin::MANAGEMENT, err_msg);
281
282 if (ret != JVMFlag::SUCCESS) {
283 output()->print_cr("%s", err_msg.buffer());
284 }
285 }
286
287 void JVMTIDataDumpDCmd::execute(DCmdSource source, TRAPS) {
288 if (JvmtiExport::should_post_data_dump()) {
289 JvmtiExport::post_data_dump();
290 }
291 }
292
293 #if INCLUDE_SERVICES
294 #if INCLUDE_JVMTI
295 JVMTIAgentLoadDCmd::JVMTIAgentLoadDCmd(outputStream* output, bool heap) :
296 DCmdWithParser(output, heap),
297 _libpath("library path", "Absolute path of the JVMTI agent to load.",
298 "STRING", true),
299 _option("agent option", "Option string to pass the agent.", "STRING", false) {
300 _dcmdparser.add_dcmd_argument(&_libpath);
301 _dcmdparser.add_dcmd_argument(&_option);
302 }
303
304 void JVMTIAgentLoadDCmd::execute(DCmdSource source, TRAPS) {
305
306 if (_libpath.value() == nullptr) {
307 output()->print_cr("JVMTI.agent_load dcmd needs library path.");
308 return;
309 }
310
311 char *suffix = strrchr(_libpath.value(), '.');
312 bool is_java_agent = (suffix != nullptr) && (strncmp(".jar", suffix, 4) == 0);
313
314 if (is_java_agent) {
315 if (_option.value() == nullptr) {
316 JvmtiAgentList::load_agent("instrument", false, _libpath.value(), output());
317 } else {
318 size_t opt_len = strlen(_libpath.value()) + strlen(_option.value()) + 2;
319 if (opt_len > 4096) {
320 output()->print_cr("JVMTI agent attach failed: Options is too long.");
321 return;
322 }
323
324 char *opt = (char *)os::malloc(opt_len, mtInternal);
325 if (opt == nullptr) {
326 output()->print_cr("JVMTI agent attach failed: "
327 "Could not allocate %zu bytes for argument.",
328 opt_len);
329 return;
330 }
331
332 jio_snprintf(opt, opt_len, "%s=%s", _libpath.value(), _option.value());
333 JvmtiAgentList::load_agent("instrument", false, opt, output());
334
335 os::free(opt);
336 }
337 } else {
338 JvmtiAgentList::load_agent(_libpath.value(), true, _option.value(), output());
339 }
340 }
341
342 #endif // INCLUDE_JVMTI
343 #endif // INCLUDE_SERVICES
344
345 void PrintSystemPropertiesDCmd::execute(DCmdSource source, TRAPS) {
346 // load VMSupport
347 Symbol* klass = vmSymbols::jdk_internal_vm_VMSupport();
348 Klass* k = SystemDictionary::resolve_or_fail(klass, true, CHECK);
349 InstanceKlass* ik = InstanceKlass::cast(k);
350 if (ik->should_be_initialized()) {
351 ik->initialize(THREAD);
352 }
353 if (HAS_PENDING_EXCEPTION) {
354 java_lang_Throwable::print(PENDING_EXCEPTION, output());
355 output()->cr();
356 CLEAR_PENDING_EXCEPTION;
357 return;
358 }
359
360 // invoke the serializePropertiesToByteArray method
361 JavaValue result(T_OBJECT);
362 JavaCallArguments args;
363
364 Symbol* signature = vmSymbols::void_byte_array_signature();
365 JavaCalls::call_static(&result,
366 ik,
367 vmSymbols::serializePropertiesToByteArray_name(),
368 signature,
369 &args,
370 THREAD);
371 if (HAS_PENDING_EXCEPTION) {
372 java_lang_Throwable::print(PENDING_EXCEPTION, output());
373 output()->cr();
374 CLEAR_PENDING_EXCEPTION;
375 return;
376 }
377
378 // The result should be a [B
379 oop res = result.get_oop();
380 assert(res->is_typeArray(), "just checking");
381 assert(TypeArrayKlass::cast(res->klass())->element_type() == T_BYTE, "just checking");
382
383 // copy the bytes to the output stream
384 typeArrayOop ba = typeArrayOop(res);
385 jbyte* addr = typeArrayOop(res)->byte_at_addr(0);
386 output()->print_raw((const char*)addr, ba->length());
387 }
388
389 VMUptimeDCmd::VMUptimeDCmd(outputStream* output, bool heap) :
390 DCmdWithParser(output, heap),
391 _date("-date", "Add a prefix with current date", "BOOLEAN", false, "false") {
392 _dcmdparser.add_dcmd_option(&_date);
393 }
394
395 void VMUptimeDCmd::execute(DCmdSource source, TRAPS) {
396 if (_date.value()) {
397 output()->date_stamp(true, "", ": ");
398 }
399 output()->time_stamp().update_to(tty->time_stamp().ticks());
400 output()->stamp();
401 output()->print_cr(" s");
402 }
403
404 void VMInfoDCmd::execute(DCmdSource source, TRAPS) {
405 VMError::print_vm_info(_output);
406 }
407
408 void SystemGCDCmd::execute(DCmdSource source, TRAPS) {
409 Universe::heap()->collect(GCCause::_dcmd_gc_run);
410 }
411
412 void RunFinalizationDCmd::execute(DCmdSource source, TRAPS) {
413 Klass* k = vmClasses::System_klass();
414 JavaValue result(T_VOID);
415 JavaCalls::call_static(&result, k,
416 vmSymbols::run_finalization_name(),
417 vmSymbols::void_method_signature(), CHECK);
418 }
419
420 void HeapInfoDCmd::execute(DCmdSource source, TRAPS) {
421 MutexLocker hl(THREAD, Heap_lock);
422 Universe::heap()->print_heap_on(output());
423 }
424
425 void FinalizerInfoDCmd::execute(DCmdSource source, TRAPS) {
426 ResourceMark rm(THREAD);
427
428 if (!InstanceKlass::is_finalization_enabled()) {
429 output()->print_cr("Finalization is disabled");
430 return;
431 }
432
433 Klass* k = SystemDictionary::resolve_or_fail(
434 vmSymbols::finalizer_histogram_klass(), true, CHECK);
435
436 JavaValue result(T_ARRAY);
437
438 // We are calling lang.ref.FinalizerHistogram.getFinalizerHistogram() method
439 // and expect it to return array of FinalizerHistogramEntry as Object[]
440
441 JavaCalls::call_static(&result, k,
442 vmSymbols::get_finalizer_histogram_name(),
443 vmSymbols::void_finalizer_histogram_entry_array_signature(), CHECK);
444
445 objArrayOop result_oop = (objArrayOop) result.get_oop();
446 if (result_oop->length() == 0) {
447 output()->print_cr("No instances waiting for finalization found");
448 return;
449 }
450
451 oop foop = result_oop->obj_at(0);
452 InstanceKlass* ik = InstanceKlass::cast(foop->klass());
453
454 fieldDescriptor count_fd, name_fd;
455
456 Klass* count_res = ik->find_field(
457 vmSymbols::finalizer_histogram_entry_count_field(), vmSymbols::int_signature(), &count_fd);
458
459 Klass* name_res = ik->find_field(
460 vmSymbols::finalizer_histogram_entry_name_field(), vmSymbols::string_signature(), &name_fd);
461
462 assert(count_res != nullptr && name_res != nullptr, "Unexpected layout of FinalizerHistogramEntry");
463
464 output()->print_cr("Unreachable instances waiting for finalization");
465 output()->print_cr("#instances class name");
466 output()->print_cr("-----------------------");
467
468 for (int i = 0; i < result_oop->length(); ++i) {
469 oop element_oop = result_oop->obj_at(i);
470 oop str_oop = element_oop->obj_field(name_fd.offset());
471 char *name = java_lang_String::as_utf8_string(str_oop);
472 int count = element_oop->int_field(count_fd.offset());
473 output()->print_cr("%10d %s", count, name);
474 }
475 }
476
477 #if INCLUDE_SERVICES // Heap dumping/inspection supported
478 HeapDumpDCmd::HeapDumpDCmd(outputStream* output, bool heap) :
479 DCmdWithParser(output, heap),
480 _filename("filename","Name of the dump file", "FILE",true),
481 _all("-all", "Dump all objects, including unreachable objects",
482 "BOOLEAN", false, "false"),
483 _gzip("-gz", "If specified, the heap dump is written in gzipped format "
484 "using the given compression level. 1 (recommended) is the fastest, "
485 "9 the strongest compression.", "INT", false, "1"),
486 _overwrite("-overwrite", "If specified, the dump file will be overwritten if it exists",
487 "BOOLEAN", false, "false"),
488 _parallel("-parallel", "Number of parallel threads to use for heap dump. The VM "
489 "will try to use the specified number of threads, but might use fewer.",
490 "INT", false, "1") {
491 _dcmdparser.add_dcmd_option(&_all);
492 _dcmdparser.add_dcmd_argument(&_filename);
493 _dcmdparser.add_dcmd_option(&_gzip);
494 _dcmdparser.add_dcmd_option(&_overwrite);
495 _dcmdparser.add_dcmd_option(&_parallel);
496 }
497
498 void HeapDumpDCmd::execute(DCmdSource source, TRAPS) {
499 jlong level = -1; // -1 means no compression.
500 jlong parallel = HeapDumper::default_num_of_dump_threads();
501
502 if (_gzip.is_set()) {
503 level = _gzip.value();
504
505 if (level < 1 || level > 9) {
506 output()->print_cr("Compression level out of range (1-9): " JLONG_FORMAT, level);
507 return;
508 }
509 }
510
511 if (_parallel.is_set()) {
512 parallel = _parallel.value();
513
514 if (parallel < 0) {
515 output()->print_cr("Invalid number of parallel dump threads.");
516 return;
517 } else if (parallel == 0) {
518 // 0 implies to disable parallel heap dump, in such case, we use serial dump instead
519 parallel = 1;
520 }
521 }
522
523 // Request a full GC before heap dump if _all is false
524 // This helps reduces the amount of unreachable objects in the dump
525 // and makes it easier to browse.
526 HeapDumper dumper(!_all.value() /* request GC if _all is false*/);
527 dumper.dump(_filename.value(), output(), (int) level, _overwrite.value(), (uint)parallel);
528 }
529
530 ClassHistogramDCmd::ClassHistogramDCmd(outputStream* output, bool heap) :
531 DCmdWithParser(output, heap),
532 _all("-all", "Inspect all objects, including unreachable objects",
533 "BOOLEAN", false, "false"),
534 _parallel_thread_num("-parallel",
535 "Number of parallel threads to use for heap inspection. "
536 "0 (the default) means let the VM determine the number of threads to use. "
537 "1 means use one thread (disable parallelism). "
538 "For any other value the VM will try to use the specified number of "
539 "threads, but might use fewer.",
540 "INT", false, "0") {
541 _dcmdparser.add_dcmd_option(&_all);
542 _dcmdparser.add_dcmd_option(&_parallel_thread_num);
543 }
544
545 void ClassHistogramDCmd::execute(DCmdSource source, TRAPS) {
546 jlong num = _parallel_thread_num.value();
547 if (num < 0) {
548 output()->print_cr("Parallel thread number out of range (>=0): " JLONG_FORMAT, num);
549 return;
550 }
551 uint parallel_thread_num = num == 0
552 ? MAX2<uint>(1, (uint)os::initial_active_processor_count() * 3 / 8)
553 : num;
554 VM_GC_HeapInspection heapop(output(),
555 !_all.value(), /* request full gc if false */
556 parallel_thread_num);
557 VMThread::execute(&heapop);
558 }
559
560 #endif // INCLUDE_SERVICES
561
562 ThreadDumpDCmd::ThreadDumpDCmd(outputStream* output, bool heap) :
563 DCmdWithParser(output, heap),
564 _locks("-l", "print java.util.concurrent locks", "BOOLEAN", false, "false"),
565 _extended("-e", "print extended thread information", "BOOLEAN", false, "false") {
566 _dcmdparser.add_dcmd_option(&_locks);
567 _dcmdparser.add_dcmd_option(&_extended);
568 }
569
570 void ThreadDumpDCmd::execute(DCmdSource source, TRAPS) {
571 // thread stacks and JNI global handles
572 VM_PrintThreads op1(output(), _locks.value(), _extended.value(), true /* print JNI handle info */);
573 VMThread::execute(&op1);
574
575 // Deadlock detection
576 VM_FindDeadlocks op2(output());
577 VMThread::execute(&op2);
578 }
579
580 // Enhanced JMX Agent support
581
582 JMXStartRemoteDCmd::JMXStartRemoteDCmd(outputStream *output, bool heap_allocated) :
583
584 DCmdWithParser(output, heap_allocated),
585
586 _config_file
587 ("config.file",
588 "set com.sun.management.config.file", "STRING", false),
589
590 _jmxremote_host
591 ("jmxremote.host",
592 "set com.sun.management.jmxremote.host", "STRING", false),
593
594 _jmxremote_port
595 ("jmxremote.port",
596 "set com.sun.management.jmxremote.port", "STRING", false),
597
598 _jmxremote_rmi_port
599 ("jmxremote.rmi.port",
600 "set com.sun.management.jmxremote.rmi.port", "STRING", false),
601
602 _jmxremote_ssl
603 ("jmxremote.ssl",
604 "set com.sun.management.jmxremote.ssl", "STRING", false),
605
606 _jmxremote_registry_ssl
607 ("jmxremote.registry.ssl",
608 "set com.sun.management.jmxremote.registry.ssl", "STRING", false),
609
610 _jmxremote_authenticate
611 ("jmxremote.authenticate",
612 "set com.sun.management.jmxremote.authenticate", "STRING", false),
613
614 _jmxremote_password_file
615 ("jmxremote.password.file",
616 "set com.sun.management.jmxremote.password.file", "STRING", false),
617
618 _jmxremote_access_file
619 ("jmxremote.access.file",
620 "set com.sun.management.jmxremote.access.file", "STRING", false),
621
622 _jmxremote_login_config
623 ("jmxremote.login.config",
624 "set com.sun.management.jmxremote.login.config", "STRING", false),
625
626 _jmxremote_ssl_enabled_cipher_suites
627 ("jmxremote.ssl.enabled.cipher.suites",
628 "set com.sun.management.jmxremote.ssl.enabled.cipher.suite", "STRING", false),
629
630 _jmxremote_ssl_enabled_protocols
631 ("jmxremote.ssl.enabled.protocols",
632 "set com.sun.management.jmxremote.ssl.enabled.protocols", "STRING", false),
633
634 _jmxremote_ssl_need_client_auth
635 ("jmxremote.ssl.need.client.auth",
636 "set com.sun.management.jmxremote.need.client.auth", "STRING", false),
637
638 _jmxremote_ssl_config_file
639 ("jmxremote.ssl.config.file",
640 "set com.sun.management.jmxremote.ssl.config.file", "STRING", false),
641
642 // JDP Protocol support
643 _jmxremote_autodiscovery
644 ("jmxremote.autodiscovery",
645 "set com.sun.management.jmxremote.autodiscovery", "STRING", false),
646
647 _jdp_port
648 ("jdp.port",
649 "set com.sun.management.jdp.port", "INT", false),
650
651 _jdp_address
652 ("jdp.address",
653 "set com.sun.management.jdp.address", "STRING", false),
654
655 _jdp_source_addr
656 ("jdp.source_addr",
657 "set com.sun.management.jdp.source_addr", "STRING", false),
658
659 _jdp_ttl
660 ("jdp.ttl",
661 "set com.sun.management.jdp.ttl", "INT", false),
662
663 _jdp_pause
664 ("jdp.pause",
665 "set com.sun.management.jdp.pause", "INT", false),
666
667 _jdp_name
668 ("jdp.name",
669 "set com.sun.management.jdp.name", "STRING", false)
670
671 {
672 _dcmdparser.add_dcmd_option(&_config_file);
673 _dcmdparser.add_dcmd_option(&_jmxremote_host);
674 _dcmdparser.add_dcmd_option(&_jmxremote_port);
675 _dcmdparser.add_dcmd_option(&_jmxremote_rmi_port);
676 _dcmdparser.add_dcmd_option(&_jmxremote_ssl);
677 _dcmdparser.add_dcmd_option(&_jmxremote_registry_ssl);
678 _dcmdparser.add_dcmd_option(&_jmxremote_authenticate);
679 _dcmdparser.add_dcmd_option(&_jmxremote_password_file);
680 _dcmdparser.add_dcmd_option(&_jmxremote_access_file);
681 _dcmdparser.add_dcmd_option(&_jmxremote_login_config);
682 _dcmdparser.add_dcmd_option(&_jmxremote_ssl_enabled_cipher_suites);
683 _dcmdparser.add_dcmd_option(&_jmxremote_ssl_enabled_protocols);
684 _dcmdparser.add_dcmd_option(&_jmxremote_ssl_need_client_auth);
685 _dcmdparser.add_dcmd_option(&_jmxremote_ssl_config_file);
686 _dcmdparser.add_dcmd_option(&_jmxremote_autodiscovery);
687 _dcmdparser.add_dcmd_option(&_jdp_port);
688 _dcmdparser.add_dcmd_option(&_jdp_address);
689 _dcmdparser.add_dcmd_option(&_jdp_source_addr);
690 _dcmdparser.add_dcmd_option(&_jdp_ttl);
691 _dcmdparser.add_dcmd_option(&_jdp_pause);
692 _dcmdparser.add_dcmd_option(&_jdp_name);
693 }
694
695 void JMXStartRemoteDCmd::execute(DCmdSource source, TRAPS) {
696 ResourceMark rm(THREAD);
697 HandleMark hm(THREAD);
698
699 // Load and initialize the jdk.internal.agent.Agent class
700 // invoke startRemoteManagementAgent(string) method to start
701 // the remote management server.
702 // throw java.lang.NoSuchMethodError if the method doesn't exist
703
704 loadAgentModule(CHECK);
705 Handle loader = Handle(THREAD, SystemDictionary::java_system_loader());
706 Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::jdk_internal_agent_Agent(), loader, true, CHECK);
707
708 JavaValue result(T_VOID);
709
710 // Pass all command line arguments to java as key=value,...
711 // All checks are done on java side
712
713 int len = 0;
714 stringStream options;
715 char comma[2] = {0,0};
716
717 // Leave default values on Agent.class side and pass only
718 // arguments explicitly set by user. All arguments passed
719 // to jcmd override properties with the same name set by
720 // command line with -D or by managmenent.properties
721 // file.
722 #define PUT_OPTION(a) \
723 do { \
724 if ( (a).is_set() ){ \
725 if ( *((a).type()) == 'I' ) { \
726 options.print("%scom.sun.management.%s=" JLONG_FORMAT, comma, (a).name(), (jlong)((a).value())); \
727 } else { \
728 options.print("%scom.sun.management.%s=%s", comma, (a).name(), (char*)((a).value())); \
729 } \
730 comma[0] = ','; \
731 }\
732 } while(0);
733
734
735 PUT_OPTION(_config_file);
736 PUT_OPTION(_jmxremote_host);
737 PUT_OPTION(_jmxremote_port);
738 PUT_OPTION(_jmxremote_rmi_port);
739 PUT_OPTION(_jmxremote_ssl);
740 PUT_OPTION(_jmxremote_registry_ssl);
741 PUT_OPTION(_jmxremote_authenticate);
742 PUT_OPTION(_jmxremote_password_file);
743 PUT_OPTION(_jmxremote_access_file);
744 PUT_OPTION(_jmxremote_login_config);
745 PUT_OPTION(_jmxremote_ssl_enabled_cipher_suites);
746 PUT_OPTION(_jmxremote_ssl_enabled_protocols);
747 PUT_OPTION(_jmxremote_ssl_need_client_auth);
748 PUT_OPTION(_jmxremote_ssl_config_file);
749 PUT_OPTION(_jmxremote_autodiscovery);
750 PUT_OPTION(_jdp_port);
751 PUT_OPTION(_jdp_address);
752 PUT_OPTION(_jdp_source_addr);
753 PUT_OPTION(_jdp_ttl);
754 PUT_OPTION(_jdp_pause);
755 PUT_OPTION(_jdp_name);
756
757 #undef PUT_OPTION
758
759 Handle str = java_lang_String::create_from_str(options.as_string(), CHECK);
760 JavaCalls::call_static(&result, k, vmSymbols::startRemoteAgent_name(), vmSymbols::string_void_signature(), str, CHECK);
761 }
762
763 JMXStartLocalDCmd::JMXStartLocalDCmd(outputStream *output, bool heap_allocated) :
764 DCmd(output, heap_allocated) {
765 // do nothing
766 }
767
768 void JMXStartLocalDCmd::execute(DCmdSource source, TRAPS) {
769 ResourceMark rm(THREAD);
770 HandleMark hm(THREAD);
771
772 // Load and initialize the jdk.internal.agent.Agent class
773 // invoke startLocalManagementAgent(void) method to start
774 // the local management server
775 // throw java.lang.NoSuchMethodError if method doesn't exist
776
777 loadAgentModule(CHECK);
778 Handle loader = Handle(THREAD, SystemDictionary::java_system_loader());
779 Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::jdk_internal_agent_Agent(), loader, true, CHECK);
780
781 JavaValue result(T_VOID);
782 JavaCalls::call_static(&result, k, vmSymbols::startLocalAgent_name(), vmSymbols::void_method_signature(), CHECK);
783 }
784
785 void JMXStopRemoteDCmd::execute(DCmdSource source, TRAPS) {
786 ResourceMark rm(THREAD);
787 HandleMark hm(THREAD);
788
789 // Load and initialize the jdk.internal.agent.Agent class
790 // invoke stopRemoteManagementAgent method to stop the
791 // management server
792 // throw java.lang.NoSuchMethodError if method doesn't exist
793
794 loadAgentModule(CHECK);
795 Handle loader = Handle(THREAD, SystemDictionary::java_system_loader());
796 Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::jdk_internal_agent_Agent(), loader, true, CHECK);
797
798 JavaValue result(T_VOID);
799 JavaCalls::call_static(&result, k, vmSymbols::stopRemoteAgent_name(), vmSymbols::void_method_signature(), CHECK);
800 }
801
802 JMXStatusDCmd::JMXStatusDCmd(outputStream *output, bool heap_allocated) :
803 DCmd(output, heap_allocated) {
804 // do nothing
805 }
806
807 void JMXStatusDCmd::execute(DCmdSource source, TRAPS) {
808 ResourceMark rm(THREAD);
809 HandleMark hm(THREAD);
810
811 // Load and initialize the jdk.internal.agent.Agent class
812 // invoke getManagementAgentStatus() method to generate the status info
813 // throw java.lang.NoSuchMethodError if method doesn't exist
814
815 loadAgentModule(CHECK);
816 Handle loader = Handle(THREAD, SystemDictionary::java_system_loader());
817 Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::jdk_internal_agent_Agent(), loader, true, CHECK);
818
819 JavaValue result(T_OBJECT);
820 JavaCalls::call_static(&result, k, vmSymbols::getAgentStatus_name(), vmSymbols::void_string_signature(), CHECK);
821
822 jvalue* jv = (jvalue*) result.get_value_addr();
823 oop str = cast_to_oop(jv->l);
824 if (str != nullptr) {
825 char* out = java_lang_String::as_utf8_string(str);
826 if (out) {
827 // Avoid using print_cr() because length maybe longer than O_BUFLEN
828 output()->print_raw_cr(out);
829 return;
830 }
831 }
832 output()->print_cr("Error obtaining management agent status");
833 }
834
835 VMDynamicLibrariesDCmd::VMDynamicLibrariesDCmd(outputStream *output, bool heap_allocated) :
836 DCmd(output, heap_allocated) {
837 // do nothing
838 }
839
840 void VMDynamicLibrariesDCmd::execute(DCmdSource source, TRAPS) {
841 os::print_dll_info(output());
842 output()->cr();
843 }
844
845 void CompileQueueDCmd::execute(DCmdSource source, TRAPS) {
846 VM_PrintCompileQueue printCompileQueueOp(output());
847 VMThread::execute(&printCompileQueueOp);
848 }
849
850 void CodeListDCmd::execute(DCmdSource source, TRAPS) {
851 CodeCache::print_codelist(output());
852 }
853
854 void CodeCacheDCmd::execute(DCmdSource source, TRAPS) {
855 CodeCache::print_layout(output());
856 }
857
858 #ifdef LINUX
859 PerfMapDCmd::PerfMapDCmd(outputStream* output, bool heap) :
860 DCmdWithParser(output, heap),
861 _filename("filename", "Name of the map file", "FILE", false, DEFAULT_PERFMAP_FILENAME)
862 {
863 _dcmdparser.add_dcmd_argument(&_filename);
864 }
865
866 void PerfMapDCmd::execute(DCmdSource source, TRAPS) {
867 CodeCache::write_perf_map(_filename.value(), output());
868 }
869 #endif // LINUX
870
871 //---< BEGIN >--- CodeHeap State Analytics.
872 CodeHeapAnalyticsDCmd::CodeHeapAnalyticsDCmd(outputStream* output, bool heap) :
873 DCmdWithParser(output, heap),
874 _function("function", "Function to be performed (aggregate, UsedSpace, FreeSpace, MethodCount, MethodSpace, MethodAge, MethodNames, discard", "STRING", false, "all"),
875 _granularity("granularity", "Detail level - smaller value -> more detail", "INT", false, "4096") {
876 _dcmdparser.add_dcmd_argument(&_function);
877 _dcmdparser.add_dcmd_argument(&_granularity);
878 }
879
880 void CodeHeapAnalyticsDCmd::execute(DCmdSource source, TRAPS) {
881 jlong granularity = _granularity.value();
882 if (granularity < 1) {
883 Exceptions::fthrow(THREAD_AND_LOCATION, vmSymbols::java_lang_IllegalArgumentException(),
884 "Invalid granularity value " JLONG_FORMAT ". Should be positive.\n", granularity);
885 return;
886 }
887
888 CompileBroker::print_heapinfo(output(), _function.value(), granularity);
889 }
890 //---< END >--- CodeHeap State Analytics.
891
892 EventLogDCmd::EventLogDCmd(outputStream* output, bool heap) :
893 DCmdWithParser(output, heap),
894 _log("log", "Name of log to be printed. If omitted, all logs are printed.", "STRING", false, nullptr),
895 _max("max", "Maximum number of events to be printed (newest first). If omitted or zero, all events are printed.", "INT", false, "0")
896 {
897 _dcmdparser.add_dcmd_option(&_log);
898 _dcmdparser.add_dcmd_option(&_max);
899 }
900
901 void EventLogDCmd::execute(DCmdSource source, TRAPS) {
902 int max = (int)_max.value();
903 if (max < 0) {
904 output()->print_cr("Invalid max option: \"%d\".", max);
905 return;
906 }
907 const char* log_name = _log.value();
908 if (log_name != nullptr) {
909 Events::print_one(output(), log_name, max);
910 } else {
911 Events::print_all(output(), max);
912 }
913 }
914
915 void CompilerDirectivesPrintDCmd::execute(DCmdSource source, TRAPS) {
916 DirectivesStack::print(output());
917 }
918
919 CompilerDirectivesAddDCmd::CompilerDirectivesAddDCmd(outputStream* output, bool heap) :
920 DCmdWithParser(output, heap),
921 _filename("filename","Name of the directives file", "STRING",true) {
922 _dcmdparser.add_dcmd_argument(&_filename);
923 }
924
925 void CompilerDirectivesAddDCmd::execute(DCmdSource source, TRAPS) {
926 DirectivesParser::parse_from_file(_filename.value(), output(), true);
927 }
928
929 void CompilerDirectivesRemoveDCmd::execute(DCmdSource source, TRAPS) {
930 DirectivesStack::pop(1);
931 }
932
933 void CompilerDirectivesClearDCmd::execute(DCmdSource source, TRAPS) {
934 DirectivesStack::clear();
935 }
936 #if INCLUDE_SERVICES
937 ClassHierarchyDCmd::ClassHierarchyDCmd(outputStream* output, bool heap) :
938 DCmdWithParser(output, heap),
939 _print_interfaces("-i", "Inherited interfaces should be printed.", "BOOLEAN", false, "false"),
940 _print_subclasses("-s", "If a classname is specified, print its subclasses "
941 "in addition to its superclasses. Without this option only the "
942 "superclasses will be printed.", "BOOLEAN", false, "false"),
943 _classname("classname", "Name of class whose hierarchy should be printed. "
944 "If not specified, all class hierarchies are printed.",
945 "STRING", false) {
946 _dcmdparser.add_dcmd_option(&_print_interfaces);
947 _dcmdparser.add_dcmd_option(&_print_subclasses);
948 _dcmdparser.add_dcmd_argument(&_classname);
949 }
950
951 void ClassHierarchyDCmd::execute(DCmdSource source, TRAPS) {
952 VM_PrintClassHierarchy printClassHierarchyOp(output(), _print_interfaces.value(),
953 _print_subclasses.value(), _classname.value());
954 VMThread::execute(&printClassHierarchyOp);
955 }
956 #endif
957
958 ClassesDCmd::ClassesDCmd(outputStream* output, bool heap) :
959 DCmdWithParser(output, heap),
960 _verbose("-verbose",
961 "Dump the detailed content of a Java class. "
962 "Some classes are annotated with flags: "
963 "F = has, or inherits, a non-empty finalize method, "
964 "f = has final method, "
965 "W = methods rewritten, "
966 "C = marked with @Contended annotation, "
967 "R = has been redefined, "
968 "S = is shared class",
969 "BOOLEAN", false, "false") {
970 _dcmdparser.add_dcmd_option(&_verbose);
971 }
972
973 class VM_PrintClasses : public VM_Operation {
974 private:
975 outputStream* _out;
976 bool _verbose;
977 public:
978 VM_PrintClasses(outputStream* out, bool verbose) : _out(out), _verbose(verbose) {}
979
980 virtual VMOp_Type type() const { return VMOp_PrintClasses; }
981
982 virtual void doit() {
983 PrintClassClosure closure(_out, _verbose);
984 ClassLoaderDataGraph::classes_do(&closure);
985 }
986 };
987
988 void ClassesDCmd::execute(DCmdSource source, TRAPS) {
989 VM_PrintClasses vmop(output(), _verbose.value());
990 VMThread::execute(&vmop);
991 }
992
993 #if INCLUDE_CDS
994 void AOTEndTrainingDCmd::execute(DCmdSource source, TRAPS) {
995 if (!CDSConfig::is_dumping_preimage_static_archive()) {
996 output()->print_cr("Error! Not a training run");
997 } else if (CDSEndTrainingUpcall::end_training(THREAD)) {
998 output()->print_cr("Training ended successfully");
999 } else {
1000 output()->print_cr("Error! Failed to end training");
1001 }
1002 }
1003 #endif // INCLUDE_CDS
1004
1005 #if INCLUDE_CDS
1006 #define DEFAULT_CDS_ARCHIVE_FILENAME "java_pid%p_<subcmd>.jsa"
1007
1008 DumpSharedArchiveDCmd::DumpSharedArchiveDCmd(outputStream* output, bool heap) :
1009 DCmdWithParser(output, heap),
1010 _suboption("subcmd", "static_dump | dynamic_dump", "STRING", true),
1011 _filename("filename", "Name of shared archive to be dumped", "FILE", false,
1012 DEFAULT_CDS_ARCHIVE_FILENAME)
1013 {
1014 _dcmdparser.add_dcmd_argument(&_suboption);
1015 _dcmdparser.add_dcmd_argument(&_filename);
1016 }
1017
1018 void DumpSharedArchiveDCmd::execute(DCmdSource source, TRAPS) {
1019 jboolean is_static;
1020 const char* scmd = _suboption.value();
1021
1022 // The check for _filename.is_set() is because we don't want to use
1023 // DEFAULT_CDS_ARCHIVE_FILENAME, since it is meant as a description
1024 // of the default, not the actual default.
1025 const char* file = _filename.is_set() ? _filename.value() : nullptr;
1026
1027 if (strcmp(scmd, "static_dump") == 0) {
1028 is_static = JNI_TRUE;
1029 output()->print("Static dump: ");
1030 } else if (strcmp(scmd, "dynamic_dump") == 0) {
1031 is_static = JNI_FALSE;
1032 output()->print("Dynamic dump: ");
1033 if (!CDSConfig::is_using_archive()) {
1034 output()->print_cr("Dynamic dump is unsupported when base CDS archive is not loaded");
1035 return;
1036 }
1037 if (!RecordDynamicDumpInfo) {
1038 output()->print_cr("Dump dynamic should run with -XX:+RecordDynamicDumpInfo");
1039 return;
1040 }
1041 } else {
1042 output()->print_cr("Invalid command for VM.cds, valid input is static_dump or dynamic_dump");
1043 return;
1044 }
1045
1046 // call CDS.dumpSharedArchive
1047 Handle fileh;
1048 if (file != nullptr) {
1049 fileh = java_lang_String::create_from_str(file, CHECK);
1050 }
1051 Symbol* cds_name = vmSymbols::jdk_internal_misc_CDS();
1052 Klass* cds_klass = SystemDictionary::resolve_or_fail(cds_name, true /*throw error*/, CHECK);
1053 JavaValue result(T_OBJECT);
1054 JavaCallArguments args;
1055 args.push_int(is_static);
1056 args.push_oop(fileh);
1057 JavaCalls::call_static(&result,
1058 cds_klass,
1059 vmSymbols::dumpSharedArchive(),
1060 vmSymbols::dumpSharedArchive_signature(),
1061 &args, CHECK);
1062 if (!HAS_PENDING_EXCEPTION) {
1063 assert(result.get_type() == T_OBJECT, "Sanity check");
1064 // result contains the archive name
1065 char* archive_name = java_lang_String::as_utf8_string(result.get_oop());
1066 output()->print_cr("%s", archive_name);
1067 }
1068 }
1069 #endif // INCLUDE_CDS
1070
1071 ThreadDumpToFileDCmd::ThreadDumpToFileDCmd(outputStream* output, bool heap) :
1072 DCmdWithParser(output, heap),
1073 _overwrite("-overwrite", "May overwrite existing file", "BOOLEAN", false, "false"),
1074 _format("-format", "Output format (\"plain\" or \"json\")", "STRING", false, "plain"),
1075 _filepath("filepath", "The file path to the output file", "FILE", true) {
1076 _dcmdparser.add_dcmd_option(&_overwrite);
1077 _dcmdparser.add_dcmd_option(&_format);
1078 _dcmdparser.add_dcmd_argument(&_filepath);
1079 }
1080
1081 void ThreadDumpToFileDCmd::execute(DCmdSource source, TRAPS) {
1082 bool json = (_format.value() != nullptr) && (strcmp(_format.value(), "json") == 0);
1083 char* path = _filepath.value();
1084 bool overwrite = _overwrite.value();
1085 Symbol* name = (json) ? vmSymbols::dumpThreadsToJson_name() : vmSymbols::dumpThreads_name();
1086 dumpToFile(name, vmSymbols::string_bool_byte_array_signature(), path, overwrite, CHECK);
1087 }
1088
1089 void ThreadDumpToFileDCmd::dumpToFile(Symbol* name, Symbol* signature, const char* path, bool overwrite, TRAPS) {
1090 ResourceMark rm(THREAD);
1091 HandleMark hm(THREAD);
1092
1093 Handle h_path = java_lang_String::create_from_str(path, CHECK);
1094
1095 Symbol* sym = vmSymbols::jdk_internal_vm_ThreadDumper();
1096 Klass* k = SystemDictionary::resolve_or_fail(sym, true, CHECK);
1097
1098 // invoke the ThreadDump method to dump to file
1099 JavaValue result(T_OBJECT);
1100 JavaCallArguments args;
1101 args.push_oop(h_path);
1102 args.push_int(overwrite ? JNI_TRUE : JNI_FALSE);
1103 JavaCalls::call_static(&result,
1104 k,
1105 name,
1106 signature,
1107 &args,
1108 THREAD);
1109 if (HAS_PENDING_EXCEPTION) {
1110 java_lang_Throwable::print(PENDING_EXCEPTION, output());
1111 output()->cr();
1112 CLEAR_PENDING_EXCEPTION;
1113 return;
1114 }
1115
1116 // check that result is byte array
1117 oop res = cast_to_oop(result.get_jobject());
1118 assert(res->is_typeArray(), "just checking");
1119 assert(TypeArrayKlass::cast(res->klass())->element_type() == T_BYTE, "just checking");
1120
1121 // copy the bytes to the output stream
1122 typeArrayOop ba = typeArrayOop(res);
1123 jbyte* addr = typeArrayOop(res)->byte_at_addr(0);
1124 output()->print_raw((const char*)addr, ba->length());
1125 }
1126
1127 // Calls a static no-arg method on jdk.internal.vm.JcmdVThreadCommands that returns a byte[] with
1128 // the output. If the method completes successfully then the bytes are copied to the output stream.
1129 // If the method fails then the exception is printed to the output stream.
1130 static void execute_vthread_command(Symbol* method_name, outputStream* output, TRAPS) {
1131 ResourceMark rm(THREAD);
1132 HandleMark hm(THREAD);
1133
1134 Klass* k = SystemDictionary::resolve_or_fail(vmSymbols::jdk_internal_vm_JcmdVThreadCommands(), true, CHECK);
1135
1136 JavaValue result(T_OBJECT);
1137 JavaCallArguments args;
1138 JavaCalls::call_static(&result,
1139 k,
1140 method_name,
1141 vmSymbols::void_byte_array_signature(),
1142 &args,
1143 THREAD);
1144 if (HAS_PENDING_EXCEPTION) {
1145 java_lang_Throwable::print(PENDING_EXCEPTION, output);
1146 output->cr();
1147 CLEAR_PENDING_EXCEPTION;
1148 return;
1149 }
1150
1151 // copy the bytes to the output stream
1152 oop res = cast_to_oop(result.get_jobject());
1153 typeArrayOop ba = typeArrayOop(res);
1154 jbyte* addr = typeArrayOop(res)->byte_at_addr(0);
1155 output->print_raw((const char*)addr, ba->length());
1156 }
1157
1158 void VThreadSchedulerDCmd::execute(DCmdSource source, TRAPS) {
1159 execute_vthread_command(vmSymbols::printScheduler_name(), output(), CHECK);
1160 }
1161
1162 void VThreadPollersDCmd::execute(DCmdSource source, TRAPS) {
1163 execute_vthread_command(vmSymbols::printPollers_name(), output(), CHECK);
1164 }
1165
1166 CompilationMemoryStatisticDCmd::CompilationMemoryStatisticDCmd(outputStream* output, bool heap) :
1167 DCmdWithParser(output, heap),
1168 _verbose("verbose", "Print detailed information", "BOOLEAN", false, "false"),
1169 _legend("legend", "Table mode: print legend", "BOOLEAN", false, "false"),
1170 _minsize("minsize", "Minimum memory size", "MEMORY SIZE", false, "0") {
1171 _dcmdparser.add_dcmd_option(&_verbose);
1172 _dcmdparser.add_dcmd_option(&_minsize);
1173 _dcmdparser.add_dcmd_option(&_legend);
1174 }
1175
1176 void CompilationMemoryStatisticDCmd::execute(DCmdSource source, TRAPS) {
1177 const size_t minsize = _minsize.has_value() ? _minsize.value()._size : 0;
1178 CompilationMemoryStatistic::print_jcmd_report(output(), _verbose.value(), _legend.value(), minsize);
1179 }
1180
1181 #if defined(LINUX) || defined(_WIN64) || defined(__APPLE__)
1182
1183 SystemMapDCmd::SystemMapDCmd(outputStream* output, bool heap) : DCmd(output, heap) {}
1184
1185 void SystemMapDCmd::execute(DCmdSource source, TRAPS) {
1186 MemMapPrinter::print_all_mappings(output());
1187 }
1188
1189 static constexpr char default_filename[] = "vm_memory_map_%p.txt";
1190
1191 SystemDumpMapDCmd::SystemDumpMapDCmd(outputStream* output, bool heap) :
1192 DCmdWithParser(output, heap),
1193 _filename("-F", "file path", "FILE", false, default_filename) {
1194 _dcmdparser.add_dcmd_option(&_filename);
1195 }
1196
1197 void SystemDumpMapDCmd::execute(DCmdSource source, TRAPS) {
1198 const char* name = _filename.value();
1199 if (name == nullptr || name[0] == 0) {
1200 output()->print_cr("filename is empty or not specified. No file written");
1201 return;
1202 }
1203 fileStream fs(name);
1204 if (fs.is_open()) {
1205 if (!MemTracker::enabled()) {
1206 output()->print_cr("(NMT is disabled, will not annotate mappings).");
1207 }
1208 MemMapPrinter::print_all_mappings(&fs);
1209 // For the readers convenience, resolve path name.
1210 char tmp[JVM_MAXPATHLEN];
1211 const char* absname = os::realpath(name, tmp, sizeof(tmp));
1212 name = absname != nullptr ? absname : name;
1213 output()->print_cr("Memory map dumped to \"%s\".", name);
1214 } else {
1215 output()->print_cr("Failed to open \"%s\" for writing (%s).", name, os::strerror(errno));
1216 }
1217 }
1218
1219 #endif // LINUX