Skip to content

Commit 99969a6

Browse files
SapMachine #2023: Add suport for SAP JMC agent
1 parent 8fd3095 commit 99969a6

File tree

10 files changed

+206
-0
lines changed

10 files changed

+206
-0
lines changed

make/TestImage.gmk

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

4444
TARGETS += $(BUILD_INFO_PROPERTIES) $(README)
4545

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

4856
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
# UndefinedBehaviorSanitizer
219222
JDKOPT_SETUP_UNDEFINED_BEHAVIOR_SANITIZER
220223

make/autoconf/jdk-options.m4

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -355,6 +355,29 @@ AC_DEFUN_ONCE([JDKOPT_SETUP_DEBUG_SYMBOLS],
355355
AC_SUBST(SHIP_DEBUG_SYMBOLS)
356356
])
357357

358+
# SapMachine 2025-08-11: import JMC agent jars
359+
AC_DEFUN_ONCE([JDKOPT_SETUP_SAP_JMC_AGENT],
360+
[
361+
AC_ARG_WITH(sap-jmc-agent, [AS_HELP_STRING([--with-sap-jmc-agent],
362+
[Set import path for the SAP JMC agent jars])])
363+
SAP_JMC_AGENT_ENABLED=false
364+
if test "x$with_sap_jmc_agent" != x; then
365+
SAP_JMC_AGENT_PATH="$with_sap_jmc_agent"
366+
UTIL_FIXUP_PATH(SAP_JMC_AGENT_PATH)
367+
if test -f "$SAP_JMC_AGENT_PATH"/agent-*-boot.jar; then
368+
SAP_JMC_AGENT_VERSION=$($BASENAME "$SAP_JMC_AGENT_PATH"/agent-*-boot.jar | $SED -e 's/^agent-//' -e 's/-boot.jar$//')
369+
SAP_JMC_AGENT_ENABLED=true
370+
JVM_CFLAGS="$JVM_CFLAGS -DWITH_SAP_JMC_AGENT=1"
371+
AC_MSG_NOTICE([SAP JMC agent found at $SAP_JMC_AGENT_PATH, version $SAP_JMC_AGENT_VERSION])
372+
else
373+
AC_MSG_ERROR([SAP JMC agent was set, but the agent jars were not found])
374+
fi
375+
fi
376+
AC_SUBST(SAP_JMC_AGENT_PATH)
377+
AC_SUBST(SAP_JMC_AGENT_VERSION)
378+
AC_SUBST(SAP_JMC_AGENT_ENABLED)
379+
])
380+
358381
################################################################################
359382
#
360383
# Native and Java code coverage

make/autoconf/spec.gmk.template

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -453,6 +453,11 @@ UNLIMITED_CRYPTO := @UNLIMITED_CRYPTO@
453453
ASYNC_PROFILER_IMPORT_PATH=@ASYNC_PROFILER_IMPORT_PATH@
454454
ASYNC_PROFILER_IMPORT_ENABLED=@ASYNC_PROFILER_IMPORT_ENABLED@
455455

456+
# SapMachine 2025-08-11: import SAP JMC agent jars
457+
SAP_JMC_AGENT_PATH=@SAP_JMC_AGENT_PATH@
458+
SAP_JMC_AGENT_VERSION=@SAP_JMC_AGENT_VERSION@
459+
SAP_JMC_AGENT_ENABLED=@SAP_JMC_AGENT_ENABLED@
460+
456461
GCOV_ENABLED := @GCOV_ENABLED@
457462
JCOV_ENABLED := @JCOV_ENABLED@
458463
JCOV_HOME := @JCOV_HOME@

make/modules/java.base/Copy.gmk

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

259259
################################################################################
260+
# SapMachine 2025-08-11: Copy jmc agent jars
261+
ifeq ($(SAP_JMC_AGENT_ENABLED), true)
262+
$(LIB_DST_DIR)/agent.jar: $(SAP_JMC_AGENT_PATH)/agent-$(SAP_JMC_AGENT_VERSION).jar
263+
$(call install-file)
264+
$(LIB_DST_DIR)/agent-boot.jar: $(SAP_JMC_AGENT_PATH)/agent-$(SAP_JMC_AGENT_VERSION)-boot.jar
265+
$(call install-file)
266+
267+
TARGETS += $(LIB_DST_DIR)/agent.jar $(LIB_DST_DIR)/agent-boot.jar
268+
endif
269+
270+
################################################################################

src/hotspot/share/runtime/arguments.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2349,6 +2349,29 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args, JVMFlagOrigin
23492349
}
23502350
}
23512351
#endif // !INCLUDE_JVMTI
2352+
// SapMachine 2025-08-11: Handle jmc agent if requested.
2353+
} else if (match_option(option, "-jmcagent:", &tail)) {
2354+
#if !defined(WITH_SAP_JMC_AGENT)
2355+
jio_fprintf(defaultStream::error_stream(),
2356+
"SAP JMC agent is not included in this VM\n");
2357+
return JNI_ERR;
2358+
#else
2359+
#if !INCLUDE_JVMTI
2360+
#error "Must have JVMTI enabled with SAP JVM agent"
2361+
#endif
2362+
char const* agent_jar = "agent.jar";
2363+
if (tail != nullptr) {
2364+
size_t length = strlen(tail) + strlen(_java_home->value()) + strlen(agent_jar) + 7;
2365+
char* options = NEW_C_HEAP_ARRAY(char, length, mtArguments);
2366+
jio_snprintf(options, length, "%s/lib/%s=%s", _java_home->value(), agent_jar, tail);
2367+
JvmtiAgentList::add("instrument", options, false);
2368+
2369+
// java agents need module java.instrument
2370+
if (!create_numbered_module_property("jdk.module.addmods", "java.instrument", _addmods_count++)) {
2371+
return JNI_ENOMEM;
2372+
}
2373+
}
2374+
#endif // !WITH_SAP_JMC_AGENT
23522375
// --enable_preview
23532376
} else if (match_option(option, "--enable-preview")) {
23542377
set_enable_preview();

src/hotspot/share/services/diagnosticCommand.cpp

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,10 @@ void DCmd::register_dcmds(){
131131
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<EventLogDCmd>(full_export, true, false));
132132
#if INCLUDE_JVMTI // Both JVMTI and SERVICES have to be enabled to have this dcmd
133133
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JVMTIAgentLoadDCmd>(full_export, true, false));
134+
// SapMachine 2025-08-11: Add support for SAP JMC agent if requested.
135+
#if defined(WITH_SAP_JMC_AGENT)
136+
DCmdFactory::register_DCmdFactory(new DCmdFactoryImpl<JVMTIJmcAgentLoadDCmd>(full_export, true, false));
137+
#endif
134138
#endif // INCLUDE_JVMTI
135139
#endif // INCLUDE_SERVICES
136140
#if INCLUDE_JVMTI
@@ -350,6 +354,36 @@ void JVMTIAgentLoadDCmd::execute(DCmdSource source, TRAPS) {
350354
}
351355
}
352356

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

src/hotspot/share/services/diagnosticCommand.hpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,26 @@ class JVMTIAgentLoadDCmd : public DCmdWithParser {
158158
static const char* impact() { return "Low"; }
159159
virtual void execute(DCmdSource source, TRAPS);
160160
};
161+
162+
// SapMachine 2025-08-11
163+
#if defined(WITH_SAP_JMC_AGENT)
164+
class JVMTIJmcAgentLoadDCmd : public DCmdWithParser {
165+
protected:
166+
DCmdArgument<char*> _option;
167+
public:
168+
JVMTIJmcAgentLoadDCmd(outputStream* output, bool heap);
169+
static int num_arguments() { return 1; }
170+
static const char* name() { return "JVMTI.jmc_agent_load"; }
171+
static const char* description() {
172+
return "Load the SAP jmc agent.";
173+
}
174+
static const char* impact() {
175+
return "Medium: Depends on the command or trace";
176+
}
177+
virtual void execute(DCmdSource source, TRAPS);
178+
};
179+
#endif // WITH_SAP_JMC_AGENT
180+
161181
#endif // INCLUDE_JVMTI
162182
#endif // INCLUDE_SERVICES
163183

test/jdk/TEST.groups

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ tier1_sapmachine = \
6565
java/net/Socket/ExceptionText.java \
6666
java/util/jar/Manifest/IncludeInExceptionsTest.java \
6767
jdk/security/JavaDotSecurity/TestJDKIncludeInExceptions.java \
68+
sap \
6869
sun/net/www/http/KeepAliveCache/TestConnectionIDFeature.java \
6970
sun/security/lib/cacerts/VerifyCACerts.java \
7071
tools/jlink/plugins/AddSapMachineToolsTest.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)