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