Skip to content

Commit 514eb40

Browse files
committed
Define both native and Java breakpoints to trace Class#getSigners.
1 parent 261c38a commit 514eb40

File tree

1 file changed

+58
-22
lines changed

1 file changed

+58
-22
lines changed

substratevm/src/com.oracle.svm.agent/src/com/oracle/svm/agent/BreakpointInterceptor.java

+58-22
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2019, 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2019, 2025, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -317,9 +317,13 @@ private static boolean getSigners(JNIEnvironment jni, JNIObjectHandle thread, Br
317317
return handleGetClasses(jni, thread, bp, state);
318318
}
319319

320-
private static boolean handleGetClasses(JNIEnvironment jni, JNIObjectHandle thread, Breakpoint bp, InterceptedState state) {
321-
JNIObjectHandle callerClass = state.getDirectCallerClass();
320+
private static boolean handleGetClasses(JNIEnvironment jni, JNIObjectHandle thread, AbstractBreakpoint<?> bp, InterceptedState state) {
322321
JNIObjectHandle self = getReceiver(thread);
322+
return handleGetClassesWithReceiver(jni, self, bp, state);
323+
}
324+
325+
private static boolean handleGetClassesWithReceiver(JNIEnvironment jni, JNIObjectHandle self, AbstractBreakpoint<?> bp, InterceptedState state) {
326+
JNIObjectHandle callerClass = state.getDirectCallerClass();
323327
traceReflectBreakpoint(jni, self, nullHandle(), callerClass, bp.specification.methodName, null, state.getFullStackTraceOrNull());
324328
return true;
325329
}
@@ -366,10 +370,10 @@ private interface AllocateInstanceFunctionPointer extends CFunctionPointer {
366370
@CEntryPoint
367371
@CEntryPointOptions(prologue = AgentIsolate.Prologue.class)
368372
static long nativeAllocateInstance(JNIEnvironment jni, JNIObjectHandle self, JNIObjectHandle clazz) {
369-
VMError.guarantee(NATIVE_ALLOCATE_INSTANCE_BREAKPOINT_SPEC.installed != null &&
370-
NATIVE_ALLOCATE_INSTANCE_BREAKPOINT_SPEC.installed.replacedFunction.isNonNull(), "incompletely installed");
373+
NativeBreakpoint breakpoint = NATIVE_ALLOCATE_INSTANCE_BREAKPOINT_SPEC.installed;
374+
VMError.guarantee(breakpoint != null && breakpoint.replacedFunction.isNonNull(), "incompletely installed");
371375

372-
AllocateInstanceFunctionPointer original = (AllocateInstanceFunctionPointer) NATIVE_ALLOCATE_INSTANCE_BREAKPOINT_SPEC.installed.replacedFunction;
376+
AllocateInstanceFunctionPointer original = (AllocateInstanceFunctionPointer) breakpoint.replacedFunction;
373377
long result = original.invoke(jni, self, clazz);
374378
if (!Support.isInitialized()) { // in case of a (very) late call
375379
return result;
@@ -392,6 +396,36 @@ private static void traceAllocateInstance(JNIEnvironment jni, JNIObjectHandle cl
392396
}
393397
}
394398

399+
private static final CEntryPointLiteral<AllocateInstanceFunctionPointer> nativeGetSigners = CEntryPointLiteral.create(
400+
BreakpointInterceptor.class, "nativeGetSigners", JNIEnvironment.class, JNIObjectHandle.class);
401+
private static final NativeBreakpointSpecification NATIVE_GET_SIGNERS_BREAKPOINT_SPEC = new NativeBreakpointSpecification(
402+
"java/lang/Class", "getSigners", "()[Ljava/lang/Object;", nativeGetSigners);
403+
404+
private interface GetSignersFunctionPointer extends CFunctionPointer {
405+
@InvokeCFunctionPointer
406+
JNIObjectHandle invoke(JNIEnvironment jni, JNIObjectHandle self);
407+
}
408+
409+
/**
410+
* Before Java 24, {@code java/lang/Class#getSigners} was declared as a native method, so we use
411+
* a native breakpoint to trace it. Either this breakpoint or the Java breakpoint will be set
412+
* (but not both).
413+
*/
414+
@CEntryPoint
415+
@CEntryPointOptions(prologue = AgentIsolate.Prologue.class)
416+
static JNIObjectHandle nativeGetSigners(JNIEnvironment jni, JNIObjectHandle self) {
417+
NativeBreakpoint breakpoint = NATIVE_GET_SIGNERS_BREAKPOINT_SPEC.installed;
418+
VMError.guarantee(breakpoint != null && breakpoint.replacedFunction.isNonNull(), "incompletely installed");
419+
GetSignersFunctionPointer original = (GetSignersFunctionPointer) breakpoint.replacedFunction;
420+
JNIObjectHandle result = original.invoke(jni, self);
421+
if (!Support.isInitialized()) {
422+
return result;
423+
}
424+
InterceptedState state = interceptedStateSupplier.get();
425+
handleGetClassesWithReceiver(jni, self, breakpoint, state);
426+
return result;
427+
}
428+
395429
private static boolean objectFieldOffsetByName(JNIEnvironment jni, JNIObjectHandle thread, Breakpoint bp, InterceptedState state) {
396430
JNIObjectHandle callerClass = state.getDirectCallerClass();
397431
JNIObjectHandle self = getReceiver(thread);
@@ -1326,17 +1360,13 @@ public static void onLoad(JvmtiEnv jvmti, JvmtiEventCallbacks callbacks, Tracer
13261360
BreakpointInterceptor.experimentalClassDefineSupport = exptlClassDefineSupport;
13271361
BreakpointInterceptor.experimentalUnsafeAllocationSupport = exptlUnsafeAllocationSupport;
13281362
BreakpointInterceptor.trackReflectionMetadata = trackReflectionData;
1363+
BreakpointInterceptor.boundNativeMethods = new HashMap<>();
13291364

13301365
JvmtiCapabilities capabilities = UnmanagedMemory.calloc(SizeOf.get(JvmtiCapabilities.class));
13311366
check(jvmti.getFunctions().GetCapabilities().invoke(jvmti, capabilities));
13321367
capabilities.setCanGenerateBreakpointEvents(1);
13331368
capabilities.setCanAccessLocalVariables(1);
1334-
1335-
if (exptlUnsafeAllocationSupport) {
1336-
capabilities.setCanGenerateNativeMethodBindEvents(1);
1337-
callbacks.setNativeMethodBind(onNativeMethodBindLiteral.getFunctionPointer());
1338-
BreakpointInterceptor.boundNativeMethods = new HashMap<>();
1339-
}
1369+
capabilities.setCanGenerateNativeMethodBindEvents(1);
13401370

13411371
if (exptlClassLoaderSupport) {
13421372
capabilities.setCanGetBytecodes(1);
@@ -1348,8 +1378,10 @@ public static void onLoad(JvmtiEnv jvmti, JvmtiEventCallbacks callbacks, Tracer
13481378
}
13491379
check(jvmti.getFunctions().AddCapabilities().invoke(jvmti, capabilities));
13501380
UnmanagedMemory.free(capabilities);
1381+
check(jvmti.getFunctions().SetEventNotificationMode().invoke(jvmti, JvmtiEventMode.JVMTI_ENABLE, JVMTI_EVENT_NATIVE_METHOD_BIND, nullHandle()));
13511382

13521383
callbacks.setBreakpoint(onBreakpointLiteral.getFunctionPointer());
1384+
callbacks.setNativeMethodBind(onNativeMethodBindLiteral.getFunctionPointer());
13531385

13541386
if (exptlClassDefineSupport) {
13551387
callbacks.setClassFileLoadHook(onClassFileLoadHookLiteral.getFunctionPointer());
@@ -1359,9 +1391,6 @@ public static void onLoad(JvmtiEnv jvmti, JvmtiEventCallbacks callbacks, Tracer
13591391
callbacks.setClassPrepare(onClassPrepareLiteral.getFunctionPointer());
13601392
}
13611393

1362-
if (exptlUnsafeAllocationSupport) {
1363-
Support.check(jvmti.getFunctions().SetEventNotificationMode().invoke(jvmti, JvmtiEventMode.JVMTI_ENABLE, JVMTI_EVENT_NATIVE_METHOD_BIND, nullHandle()));
1364-
}
13651394
}
13661395

13671396
public static void onVMInit(JvmtiEnv jvmti, JNIEnvironment jni) {
@@ -1412,9 +1441,7 @@ public static void onVMInit(JvmtiEnv jvmti, JNIEnvironment jni) {
14121441
}
14131442
installedBreakpoints = breakpoints;
14141443

1415-
if (experimentalUnsafeAllocationSupport) {
1416-
setupNativeBreakpoints(jni, lastClass, lastClassName);
1417-
}
1444+
setupNativeBreakpoints(jni, lastClass, lastClassName);
14181445

14191446
if (experimentalClassDefineSupport) {
14201447
setupClassLoadEvent(jvmti, jni);
@@ -1431,8 +1458,12 @@ private static void setupNativeBreakpoints(JNIEnvironment jni, JNIObjectHandle p
14311458
String lastClassName = previousClassName;
14321459
nativeBreakpointsInitLock.lock();
14331460
try {
1434-
nativeBreakpoints = new HashMap<>(NATIVE_BREAKPOINT_SPECIFICATIONS.length);
1435-
for (NativeBreakpointSpecification br : NATIVE_BREAKPOINT_SPECIFICATIONS) {
1461+
List<NativeBreakpointSpecification> nativeBreakpointsList = new ArrayList<>(Arrays.asList(NATIVE_BREAKPOINT_SPECIFICATIONS));
1462+
if (experimentalUnsafeAllocationSupport) {
1463+
nativeBreakpointsList.addAll(Arrays.asList(EXPERIMENTAL_UNSAFE_ALLOCATION_NATIVE_BREAKPOINT_SPECIFICATIONS));
1464+
}
1465+
nativeBreakpoints = new HashMap<>(nativeBreakpointsList.size());
1466+
for (NativeBreakpointSpecification br : nativeBreakpointsList) {
14361467
JNIObjectHandle clazz;
14371468
if (lastClassName != null && lastClassName.equals(br.className)) {
14381469
clazz = lastClass;
@@ -1446,7 +1477,8 @@ private static void setupNativeBreakpoints(JNIEnvironment jni, JNIObjectHandle p
14461477
NativeBreakpoint bp = new NativeBreakpoint(br, clazz, method);
14471478
nativeBreakpoints.put(method.rawValue(), bp);
14481479
Long original = boundNativeMethods.get(method.rawValue());
1449-
if (original != null) { // already bound, replace
1480+
// only bind a native breakpoint if method was bound as a native method
1481+
if (original != null) {
14501482
bindNativeBreakpoint(jni, bp, WordFactory.pointer(original), nullPointer());
14511483
}
14521484
}
@@ -1710,7 +1742,7 @@ private interface BreakpointHandler {
17101742
optionalBrk("java/lang/Class", "getNestMembers", "()[Ljava/lang/Class;",
17111743
BreakpointInterceptor::getNestMembers),
17121744
optionalBrk("java/lang/Class", "getSigners", "()[Ljava/lang/Object;",
1713-
BreakpointInterceptor::getSigners)
1745+
BreakpointInterceptor::getSigners),
17141746
};
17151747

17161748
private static boolean allocateInstance(JNIEnvironment jni, JNIObjectHandle thread, @SuppressWarnings("unused") Breakpoint bp, InterceptedState state) {
@@ -1724,6 +1756,10 @@ private static boolean allocateInstance(JNIEnvironment jni, JNIObjectHandle thre
17241756
"(Ljava/lang/String;)Ljava/lang/Class;", BreakpointInterceptor::loadClass);
17251757

17261758
private static final NativeBreakpointSpecification[] NATIVE_BREAKPOINT_SPECIFICATIONS = {
1759+
NATIVE_GET_SIGNERS_BREAKPOINT_SPEC,
1760+
};
1761+
1762+
private static final NativeBreakpointSpecification[] EXPERIMENTAL_UNSAFE_ALLOCATION_NATIVE_BREAKPOINT_SPECIFICATIONS = {
17271763
NATIVE_ALLOCATE_INSTANCE_BREAKPOINT_SPEC
17281764
};
17291765

0 commit comments

Comments
 (0)