From 6ce88730f15ab3a86f2bd84e2b48978734dc8b8d Mon Sep 17 00:00:00 2001 From: Larry Cable Date: Mon, 5 Jan 2026 11:21:39 -0800 Subject: [PATCH] JDK-8327246: Add a jcmd diagnostic command to list the jar files loaded by a process --- src/hotspot/share/oops/instanceKlass.cpp | 40 ++++++++++++++++++- src/hotspot/share/oops/instanceKlass.hpp | 3 +- .../share/services/diagnosticCommand.cpp | 11 +++-- .../share/services/diagnosticCommand.hpp | 3 +- 4 files changed, 49 insertions(+), 8 deletions(-) diff --git a/src/hotspot/share/oops/instanceKlass.cpp b/src/hotspot/share/oops/instanceKlass.cpp index 56a80daed60..2b1b279bfac 100644 --- a/src/hotspot/share/oops/instanceKlass.cpp +++ b/src/hotspot/share/oops/instanceKlass.cpp @@ -35,6 +35,7 @@ #include "classfile/classLoaderData.inline.hpp" #include "classfile/javaClasses.hpp" #include "classfile/moduleEntry.hpp" +#include "classfile/symbolTable.hpp" #include "classfile/systemDictionary.hpp" #include "classfile/systemDictionaryShared.hpp" #include "classfile/verifier.hpp" @@ -2336,8 +2337,8 @@ Method* InstanceKlass::lookup_method_in_all_interfaces(Symbol* name, return nullptr; } -PrintClassClosure::PrintClassClosure(outputStream* st, bool verbose) - :_st(st), _verbose(verbose) { +PrintClassClosure::PrintClassClosure(outputStream* st, bool verbose, bool location) + :_st(st), _verbose(verbose), _location(location) { ResourceMark rm; _st->print("%-18s ", "KlassAddr"); _st->print("%-4s ", "Size"); @@ -2375,6 +2376,41 @@ void PrintClassClosure::do_klass(Klass* k) { _st->print("%-7s ", buf); // klass name _st->print("%-5s ", k->external_name()); + + if (k->is_instance_klass() && _location) { + + oop pd = java_lang_Class::protection_domain(k->java_mirror()); + + InstanceKlass* ik; + + if (pd != nullptr && (ik = InstanceKlass::cast(pd->klass()))->is_instance_klass()) { + + TempNewSymbol css = SymbolTable::new_symbol("codesource"); + TempNewSymbol csss = SymbolTable::new_symbol("Ljava/security/CodeSource;"); + + fieldDescriptor csfd; + + if (ik->find_field(css, csss, &csfd)) { + + oop cs = pd->obj_field(csfd.offset()); + + if (cs != nullptr && (ik = InstanceKlass::cast(cs->klass()))->is_instance_klass()) { + fieldDescriptor locfd; + + TempNewSymbol csls = SymbolTable::new_symbol("locationNoFragString"); + TempNewSymbol cslss = SymbolTable::new_symbol("Ljava/lang/String;"); + + if (ik->find_field(csls, cslss, &locfd)) { + oop loc = cs->obj_field(locfd.offset()); + + if (loc != nullptr && loc->klass() == vmClasses::String_klass()) { + java_lang_String::print(loc, _st, MAXPATHLEN); + } + } + } + } + } + } // end _st->cr(); if (_verbose) { diff --git a/src/hotspot/share/oops/instanceKlass.hpp b/src/hotspot/share/oops/instanceKlass.hpp index 23a59d26093..865fe4d58fa 100644 --- a/src/hotspot/share/oops/instanceKlass.hpp +++ b/src/hotspot/share/oops/instanceKlass.hpp @@ -1209,8 +1209,9 @@ class PrintClassClosure : public KlassClosure { private: outputStream* _st; bool _verbose; + bool _location; public: - PrintClassClosure(outputStream* st, bool verbose); + PrintClassClosure(outputStream* st, bool verbose, bool location); void do_klass(Klass* k); }; diff --git a/src/hotspot/share/services/diagnosticCommand.cpp b/src/hotspot/share/services/diagnosticCommand.cpp index 0846f339227..755192c23fa 100644 --- a/src/hotspot/share/services/diagnosticCommand.cpp +++ b/src/hotspot/share/services/diagnosticCommand.cpp @@ -958,27 +958,30 @@ ClassesDCmd::ClassesDCmd(outputStream* output, bool heap) : "C = marked with @Contended annotation, " "R = has been redefined, " "S = is shared class", - "BOOLEAN", false, "false") { + "BOOLEAN", false, "false"), + _location("-location", "print class file location url (if available)", "BOOLEAN", false, "false") { _dcmdparser.add_dcmd_option(&_verbose); + _dcmdparser.add_dcmd_option(&_location); } class VM_PrintClasses : public VM_Operation { private: outputStream* _out; bool _verbose; + bool _location; public: - VM_PrintClasses(outputStream* out, bool verbose) : _out(out), _verbose(verbose) {} + VM_PrintClasses(outputStream* out, bool verbose, bool location) : _out(out), _verbose(verbose), _location(location) {} virtual VMOp_Type type() const { return VMOp_PrintClasses; } virtual void doit() { - PrintClassClosure closure(_out, _verbose); + PrintClassClosure closure(_out, _verbose, _location); ClassLoaderDataGraph::classes_do(&closure); } }; void ClassesDCmd::execute(DCmdSource source, TRAPS) { - VM_PrintClasses vmop(output(), _verbose.value()); + VM_PrintClasses vmop(output(), _verbose.value(), _location.value()); VMThread::execute(&vmop); } diff --git a/src/hotspot/share/services/diagnosticCommand.hpp b/src/hotspot/share/services/diagnosticCommand.hpp index c41e7bf2e2e..d0c3473535f 100644 --- a/src/hotspot/share/services/diagnosticCommand.hpp +++ b/src/hotspot/share/services/diagnosticCommand.hpp @@ -737,8 +737,9 @@ public: class ClassesDCmd : public DCmdWithParser { protected: DCmdArgument _verbose; + DCmdArgument _location; public: - static int num_arguments() { return 1; } + static int num_arguments() { return 2; } ClassesDCmd(outputStream* output, bool heap); static const char* name() { return "VM.classes";