Skip to content

Commit 55062a5

Browse files
schmelter-sapRealCLanger
authored andcommitted
SapMachine #2023: Add suport for SAP JMC agent
1 parent 99c05d5 commit 55062a5

File tree

10 files changed

+212
-0
lines changed

10 files changed

+212
-0
lines changed

make/TestImage.gmk

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,14 @@ $(README):
4646

4747
TARGETS += $(BUILD_INFO_PROPERTIES) $(README)
4848

49+
# SapMachine 2025-08-11: Copy test jar for SAP JMC agent if needed.
50+
ifeq ($(SAP_JMC_AGENT_ENABLED), true)
51+
$(TEST_IMAGE_DIR)/jars/agent-tests.jar: $(SAP_JMC_AGENT_PATH)/agent-$(SAP_JMC_AGENT_VERSION)-tests.jar
52+
$(call install-file)
53+
54+
TARGETS += $(TEST_IMAGE_DIR)/jars/agent-tests.jar
55+
endif
56+
4957
################################################################################
5058

5159
prepare-test-image: $(TARGETS)

make/autoconf/configure.ac

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,9 @@ JDKOPT_SETUP_CODE_COVERAGE
215215
# AddressSanitizer
216216
JDKOPT_SETUP_ADDRESS_SANITIZER
217217

218+
# SapMachine 2024-12-05: Setup SAP JMC agent if requested
219+
JDKOPT_SETUP_SAP_JMC_AGENT
220+
218221
###############################################################################
219222
#
220223
# Check dependencies for external and internal libraries.

make/autoconf/jdk-options.m4

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -373,6 +373,30 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_SYMBOLS],
373373
AC_SUBST(SHIP_DEBUG_SYMBOLS)
374374
])
375375

376+
################################################################################
377+
# SapMachine 2025-08-11: import JMC agent jars
378+
AC_DEFUN_ONCE([JDKOPT_SETUP_SAP_JMC_AGENT],
379+
[
380+
AC_ARG_WITH(sap-jmc-agent, [AS_HELP_STRING([--with-sap-jmc-agent],
381+
[Set import path for the SAP JMC agent jars])])
382+
SAP_JMC_AGENT_ENABLED=false
383+
if test "x$with_sap_jmc_agent" != x; then
384+
SAP_JMC_AGENT_PATH="$with_sap_jmc_agent"
385+
UTIL_FIXUP_PATH(SAP_JMC_AGENT_PATH)
386+
if test -f "$SAP_JMC_AGENT_PATH"/agent-*-boot.jar; then
387+
SAP_JMC_AGENT_VERSION=$($BASENAME "$SAP_JMC_AGENT_PATH"/agent-*-boot.jar | $SED -e 's/^agent-//' -e 's/-boot.jar$//')
388+
SAP_JMC_AGENT_ENABLED=true
389+
JVM_CFLAGS="$JVM_CFLAGS -DWITH_SAP_JMC_AGENT=1"
390+
AC_MSG_NOTICE([SAP JMC agent found at $SAP_JMC_AGENT_PATH, version $SAP_JMC_AGENT_VERSION])
391+
else
392+
AC_MSG_ERROR([SAP JMC agent was set, but the agent jars were not found])
393+
fi
394+
fi
395+
AC_SUBST(SAP_JMC_AGENT_PATH)
396+
AC_SUBST(SAP_JMC_AGENT_VERSION)
397+
AC_SUBST(SAP_JMC_AGENT_ENABLED)
398+
])
399+
376400
################################################################################
377401
#
378402
# Native and Java code coverage

make/autoconf/spec.gmk.in

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -422,6 +422,11 @@ UNLIMITED_CRYPTO=@UNLIMITED_CRYPTO@
422422
ASYNC_PROFILER_IMPORT_PATH=@ASYNC_PROFILER_IMPORT_PATH@
423423
ASYNC_PROFILER_IMPORT_ENABLED=@ASYNC_PROFILER_IMPORT_ENABLED@
424424

425+
# SapMachine 2025-08-11: import SAP JMC agent jars
426+
SAP_JMC_AGENT_PATH=@SAP_JMC_AGENT_PATH@
427+
SAP_JMC_AGENT_VERSION=@SAP_JMC_AGENT_VERSION@
428+
SAP_JMC_AGENT_ENABLED=@SAP_JMC_AGENT_ENABLED@
429+
425430
GCOV_ENABLED=@GCOV_ENABLED@
426431
JCOV_ENABLED=@JCOV_ENABLED@
427432
JCOV_HOME=@JCOV_HOME@

make/modules/java.base/Copy.gmk

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,3 +279,14 @@ ifeq ($(call isTargetOs, linux macosx), true)
279279
endif
280280

281281
################################################################################
282+
# SapMachine 2025-08-11: Copy jmc agent jars
283+
ifeq ($(SAP_JMC_AGENT_ENABLED), true)
284+
$(LIB_DST_DIR)/agent.jar: $(SAP_JMC_AGENT_PATH)/agent-$(SAP_JMC_AGENT_VERSION).jar
285+
$(call install-file)
286+
$(LIB_DST_DIR)/agent-boot.jar: $(SAP_JMC_AGENT_PATH)/agent-$(SAP_JMC_AGENT_VERSION)-boot.jar
287+
$(call install-file)
288+
289+
TARGETS += $(LIB_DST_DIR)/agent.jar $(LIB_DST_DIR)/agent-boot.jar
290+
endif
291+
292+
################################################################################

src/hotspot/share/runtime/arguments.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2478,6 +2478,29 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, bool* patch_m
24782478
}
24792479
}
24802480
#endif // !INCLUDE_JVMTI
2481+
// SapMachine 2025-08-11: Handle jmc agent if requested.
2482+
} else if (match_option(option, "-jmcagent:", &tail)) {
2483+
#if !defined(WITH_SAP_JMC_AGENT)
2484+
jio_fprintf(defaultStream::error_stream(),
2485+
"SAP JMC agent is not included in this VM\n");
2486+
return JNI_ERR;
2487+
#else
2488+
#if !INCLUDE_JVMTI
2489+
#error "Must have JVMTI enabled with SAP JMC agent"
2490+
#endif
2491+
char const* agent_jar = "agent.jar";
2492+
if (tail != nullptr) {
2493+
size_t length = strlen(tail) + strlen(_java_home->value()) + strlen(agent_jar) + 7;
2494+
char* options = NEW_C_HEAP_ARRAY(char, length, mtArguments);
2495+
jio_snprintf(options, length, "%s/lib/%s=%s", _java_home->value(), agent_jar, tail);
2496+
add_instrument_agent("instrument", options, false);
2497+
2498+
// java agents need module java.instrument
2499+
if (!create_numbered_module_property("jdk.module.addmods", "java.instrument", addmods_count++)) {
2500+
return JNI_ENOMEM;
2501+
}
2502+
}
2503+
#endif // !WITH_SAP_JMC_AGENT
24812504
// --enable_preview
24822505
} else if (match_option(option, "--enable-preview")) {
24832506
set_enable_preview();

src/hotspot/share/services/diagnosticCommand.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,10 @@ void DCmdRegistrant::register_dcmds(){
122122
#endif // INCLUDE_SERVICES
123123
#if INCLUDE_JVMTI
124124
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JVMTIDataDumpDCmd>(full_export, true, false));
125+
// SapMachine 2025-08-11: Add support for SAP JMC agent if requested.
126+
#if defined(WITH_SAP_JMC_AGENT)
127+
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JVMTIJmcAgentLoadDCmd>(full_export, true, false));
128+
#endif // WITH_SAP_JMC_AGENT
125129
#endif // INCLUDE_JVMTI
126130
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ThreadDumpDCmd>(full_export, true, false));
127131
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<ClassLoaderStatsDCmd>(full_export, true, false));
@@ -354,6 +358,36 @@ void JVMTIAgentLoadDCmd::execute(DCmdSource source, TRAPS) {
354358
}
355359
}
356360

361+
// SapMachine 2025-08-11
362+
#if defined(WITH_SAP_JMC_AGENT)
363+
JVMTIJmcAgentLoadDCmd::JVMTIJmcAgentLoadDCmd(outputStream* output, bool heap) :
364+
DCmdWithParser(output, heap),
365+
_option("agent option", "Option string to pass the JMC agent.", "STRING", false) {
366+
_dcmdparser.add_dcmd_argument(&_option);
367+
}
368+
369+
void JVMTIJmcAgentLoadDCmd::execute(DCmdSource source, TRAPS) {
370+
char const* java_home = Arguments::get_java_home();
371+
char const* agent_jar = "agent.jar";
372+
char const* option = _option.value();
373+
size_t len = strlen(java_home) + strlen(agent_jar) + (option == nullptr ? 0 : 1 + strlen(option)) + 7;
374+
char* agent_line = (char*)os::malloc(len, mtInternal);
375+
376+
if (agent_line == nullptr) {
377+
output()->print_cr("JVMTI JMC agent attach failed: "
378+
"Could not allocate " SIZE_FORMAT " bytes for argument.",
379+
len);
380+
return;
381+
}
382+
383+
jio_snprintf(agent_line, len, "%s/lib/%s%s%s", java_home, agent_jar, option == nullptr ? "" : "=",
384+
option == nullptr ? "" : option);
385+
JvmtiExport::load_agent_library("instrument", "false", agent_line, output());
386+
387+
os::free(agent_line);
388+
}
389+
#endif // WITH_SAP_JMC_AGENT
390+
357391
#endif // INCLUDE_JVMTI
358392
#endif // INCLUDE_SERVICES
359393

src/hotspot/share/services/diagnosticCommand.hpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,31 @@ class JVMTIAgentLoadDCmd : public DCmdWithParser {
189189
}
190190
virtual void execute(DCmdSource source, TRAPS);
191191
};
192+
193+
// SapMachine 2025-08-11
194+
#if defined(WITH_SAP_JMC_AGENT)
195+
class JVMTIJmcAgentLoadDCmd : public DCmdWithParser {
196+
protected:
197+
DCmdArgument<char*> _option;
198+
public:
199+
JVMTIJmcAgentLoadDCmd(outputStream* output, bool heap);
200+
static int num_arguments() { return 1; }
201+
static const char* name() { return "JVMTI.jmc_agent_load"; }
202+
static const char* description() {
203+
return "Load the SAP jmc agent.";
204+
}
205+
static const char* impact() {
206+
return "Medium: Depends on the command or trace";
207+
}
208+
static const JavaPermission permission() {
209+
JavaPermission p = { "java.lang.management.ManagementPermission",
210+
"control", nullptr };
211+
return p;
212+
}
213+
virtual void execute(DCmdSource source, TRAPS);
214+
};
215+
#endif // WITH_SAP_JMC_AGENT
216+
192217
#endif // INCLUDE_JVMTI
193218
#endif // INCLUDE_SERVICES
194219

test/jdk/TEST.groups

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ tier1_sapmachine = \
6363
java/net/Socket/ExceptionText.java \
6464
java/util/jar/Manifest/IncludeInExceptionsTest.java \
6565
jdk/security/JavaDotSecurity/TestJDKIncludeInExceptions.java \
66+
sap \
6667
sun/security/lib/cacerts/VerifyCACerts.java \
6768
tools/jlink/plugins/AddSapMachineToolsTest.java \
6869
tools/launcher/HelpFlagsTest.java \
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
/*
2+
* Copyright (c) 2025 SAP SE. 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+
/**
26+
* @test
27+
* @summary Runs the test for the jmc agent integration.
28+
*
29+
* @run main/othervm JmcAgentIntegrationTest
30+
*/
31+
32+
import java.lang.reflect.Method;
33+
import java.io.File;
34+
import java.net.URL;
35+
import java.net.URLClassLoader;
36+
import java.nio.file.DirectoryStream;
37+
import java.nio.file.Files;
38+
import java.nio.file.Path;
39+
import java.util.ArrayList;
40+
41+
public class JmcAgentIntegrationTest {
42+
43+
public static void main(String[] args) throws Exception {
44+
File jar = new File(System.getenv("TEST_IMAGE_DIR") + "/jars/agent-tests.jar");
45+
46+
if (!jar.exists()) {
47+
return; // Feature was not enabled.
48+
}
49+
50+
ArrayList<String> testOptions = new ArrayList<>();
51+
testOptions.add("-dump");
52+
53+
// Only run VM-agnostic tests if the ASM version we are using cannot handle the class file spec of this VM.
54+
int spec = Integer.getInteger("java.vm.specification.version", 99999);
55+
String javaHome = System.getProperty("java.home");
56+
File agentJar = new File(javaHome + "/lib/agent.jar");
57+
ClassLoader parentLoader = JmcAgentIntegrationTest.class.getClassLoader();
58+
URLClassLoader agentLoader = new URLClassLoader(new URL[] {agentJar.toURI().toURL()}, parentLoader);
59+
try {
60+
Class.forName("org.openjdk.jmc.internal.org.objectweb.asm.Opcodes", true, agentLoader).getDeclaredField("V" + spec);
61+
} catch (NoSuchFieldException e) {
62+
System.out.println("Incompatible class file version. Skipping VM specific tests.");
63+
testOptions.add("-vm-agnostic-tests");
64+
}
65+
66+
URL url = jar.toURI().toURL();
67+
String classPath = System.getProperty("java.class.path", ".");
68+
69+
System.setProperty("java.class.path", classPath + System.getProperty("path.separator") + jar.toString());
70+
System.setProperty("useJmcAgentOption", "true");
71+
System.setProperty("traceExecs", "true");
72+
73+
URLClassLoader cl = new URLClassLoader(new URL[] {url}, parentLoader);
74+
Class<?> testClass = Class.forName("org.openjdk.jmc.agent.sap.test.TestRunner", true, cl);
75+
Method mainMethod = testClass.getDeclaredMethod("main", String[].class, String[].class);
76+
mainMethod.invoke(null, new Object[] {testOptions.toArray(new String[0]), new String[] {"-XX:+EnableDynamicAgentLoading"}});
77+
}
78+
}

0 commit comments

Comments
 (0)