1
1
/*
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.
3
3
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4
4
*
5
5
* 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
317
317
return handleGetClasses (jni , thread , bp , state );
318
318
}
319
319
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 ) {
322
321
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 ();
323
327
traceReflectBreakpoint (jni , self , nullHandle (), callerClass , bp .specification .methodName , null , state .getFullStackTraceOrNull ());
324
328
return true ;
325
329
}
@@ -366,10 +370,10 @@ private interface AllocateInstanceFunctionPointer extends CFunctionPointer {
366
370
@ CEntryPoint
367
371
@ CEntryPointOptions (prologue = AgentIsolate .Prologue .class )
368
372
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" );
371
375
372
- AllocateInstanceFunctionPointer original = (AllocateInstanceFunctionPointer ) NATIVE_ALLOCATE_INSTANCE_BREAKPOINT_SPEC . installed .replacedFunction ;
376
+ AllocateInstanceFunctionPointer original = (AllocateInstanceFunctionPointer ) breakpoint .replacedFunction ;
373
377
long result = original .invoke (jni , self , clazz );
374
378
if (!Support .isInitialized ()) { // in case of a (very) late call
375
379
return result ;
@@ -392,6 +396,36 @@ private static void traceAllocateInstance(JNIEnvironment jni, JNIObjectHandle cl
392
396
}
393
397
}
394
398
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
+
395
429
private static boolean objectFieldOffsetByName (JNIEnvironment jni , JNIObjectHandle thread , Breakpoint bp , InterceptedState state ) {
396
430
JNIObjectHandle callerClass = state .getDirectCallerClass ();
397
431
JNIObjectHandle self = getReceiver (thread );
@@ -1326,17 +1360,13 @@ public static void onLoad(JvmtiEnv jvmti, JvmtiEventCallbacks callbacks, Tracer
1326
1360
BreakpointInterceptor .experimentalClassDefineSupport = exptlClassDefineSupport ;
1327
1361
BreakpointInterceptor .experimentalUnsafeAllocationSupport = exptlUnsafeAllocationSupport ;
1328
1362
BreakpointInterceptor .trackReflectionMetadata = trackReflectionData ;
1363
+ BreakpointInterceptor .boundNativeMethods = new HashMap <>();
1329
1364
1330
1365
JvmtiCapabilities capabilities = UnmanagedMemory .calloc (SizeOf .get (JvmtiCapabilities .class ));
1331
1366
check (jvmti .getFunctions ().GetCapabilities ().invoke (jvmti , capabilities ));
1332
1367
capabilities .setCanGenerateBreakpointEvents (1 );
1333
1368
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 );
1340
1370
1341
1371
if (exptlClassLoaderSupport ) {
1342
1372
capabilities .setCanGetBytecodes (1 );
@@ -1348,8 +1378,10 @@ public static void onLoad(JvmtiEnv jvmti, JvmtiEventCallbacks callbacks, Tracer
1348
1378
}
1349
1379
check (jvmti .getFunctions ().AddCapabilities ().invoke (jvmti , capabilities ));
1350
1380
UnmanagedMemory .free (capabilities );
1381
+ check (jvmti .getFunctions ().SetEventNotificationMode ().invoke (jvmti , JvmtiEventMode .JVMTI_ENABLE , JVMTI_EVENT_NATIVE_METHOD_BIND , nullHandle ()));
1351
1382
1352
1383
callbacks .setBreakpoint (onBreakpointLiteral .getFunctionPointer ());
1384
+ callbacks .setNativeMethodBind (onNativeMethodBindLiteral .getFunctionPointer ());
1353
1385
1354
1386
if (exptlClassDefineSupport ) {
1355
1387
callbacks .setClassFileLoadHook (onClassFileLoadHookLiteral .getFunctionPointer ());
@@ -1359,9 +1391,6 @@ public static void onLoad(JvmtiEnv jvmti, JvmtiEventCallbacks callbacks, Tracer
1359
1391
callbacks .setClassPrepare (onClassPrepareLiteral .getFunctionPointer ());
1360
1392
}
1361
1393
1362
- if (exptlUnsafeAllocationSupport ) {
1363
- Support .check (jvmti .getFunctions ().SetEventNotificationMode ().invoke (jvmti , JvmtiEventMode .JVMTI_ENABLE , JVMTI_EVENT_NATIVE_METHOD_BIND , nullHandle ()));
1364
- }
1365
1394
}
1366
1395
1367
1396
public static void onVMInit (JvmtiEnv jvmti , JNIEnvironment jni ) {
@@ -1412,9 +1441,7 @@ public static void onVMInit(JvmtiEnv jvmti, JNIEnvironment jni) {
1412
1441
}
1413
1442
installedBreakpoints = breakpoints ;
1414
1443
1415
- if (experimentalUnsafeAllocationSupport ) {
1416
- setupNativeBreakpoints (jni , lastClass , lastClassName );
1417
- }
1444
+ setupNativeBreakpoints (jni , lastClass , lastClassName );
1418
1445
1419
1446
if (experimentalClassDefineSupport ) {
1420
1447
setupClassLoadEvent (jvmti , jni );
@@ -1431,8 +1458,12 @@ private static void setupNativeBreakpoints(JNIEnvironment jni, JNIObjectHandle p
1431
1458
String lastClassName = previousClassName ;
1432
1459
nativeBreakpointsInitLock .lock ();
1433
1460
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 ) {
1436
1467
JNIObjectHandle clazz ;
1437
1468
if (lastClassName != null && lastClassName .equals (br .className )) {
1438
1469
clazz = lastClass ;
@@ -1446,7 +1477,8 @@ private static void setupNativeBreakpoints(JNIEnvironment jni, JNIObjectHandle p
1446
1477
NativeBreakpoint bp = new NativeBreakpoint (br , clazz , method );
1447
1478
nativeBreakpoints .put (method .rawValue (), bp );
1448
1479
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 ) {
1450
1482
bindNativeBreakpoint (jni , bp , WordFactory .pointer (original ), nullPointer ());
1451
1483
}
1452
1484
}
@@ -1710,7 +1742,7 @@ private interface BreakpointHandler {
1710
1742
optionalBrk ("java/lang/Class" , "getNestMembers" , "()[Ljava/lang/Class;" ,
1711
1743
BreakpointInterceptor ::getNestMembers ),
1712
1744
optionalBrk ("java/lang/Class" , "getSigners" , "()[Ljava/lang/Object;" ,
1713
- BreakpointInterceptor ::getSigners )
1745
+ BreakpointInterceptor ::getSigners ),
1714
1746
};
1715
1747
1716
1748
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
1724
1756
"(Ljava/lang/String;)Ljava/lang/Class;" , BreakpointInterceptor ::loadClass );
1725
1757
1726
1758
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 = {
1727
1763
NATIVE_ALLOCATE_INSTANCE_BREAKPOINT_SPEC
1728
1764
};
1729
1765
0 commit comments