1 /* 2 * Copyright (c) 1997, 2025, Oracle and/or its affiliates. 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 #include "classfile/javaClasses.hpp" 26 #include "classfile/symbolTable.hpp" 27 #include "classfile/systemDictionary.hpp" 28 #include "classfile/vmClasses.hpp" 29 #include "classfile/vmSymbols.hpp" 30 #include "logging/log.hpp" 31 #include "logging/logTag.hpp" 32 #include "memory/oopFactory.hpp" 33 #include "memory/resourceArea.hpp" 34 #include "oops/instanceKlass.hpp" 35 #include "oops/klass.inline.hpp" 36 #include "oops/method.hpp" 37 #include "oops/oop.inline.hpp" 38 #include "oops/symbol.hpp" 39 #include "prims/jvm_misc.hpp" 40 #include "prims/jvmtiAgentList.hpp" 41 #include "prims/jvmtiExport.hpp" 42 #include "prims/nativeLookup.hpp" 43 #include "prims/scopedMemoryAccess.hpp" 44 #include "prims/shipilevMagic.hpp" 45 #include "prims/unsafe.hpp" 46 #include "runtime/arguments.hpp" 47 #include "runtime/handles.inline.hpp" 48 #include "runtime/interfaceSupport.inline.hpp" 49 #include "runtime/javaCalls.hpp" 50 #include "runtime/os.hpp" 51 #include "runtime/sharedRuntime.hpp" 52 #include "runtime/signature.hpp" 53 #include "utilities/macros.hpp" 54 #include "utilities/utf8.hpp" 55 #if INCLUDE_JFR 56 #include "jfr/jfr.hpp" 57 #endif 58 59 /* 60 61 The JNI specification defines the mapping from a Java native method name to 62 a C native library implementation function name as follows: 63 64 The mapping produces a native method name by concatenating the following components 65 derived from a `native` method declaration: 66 67 1. the prefix Java_ 68 2. given the binary name, in internal form, of the class which declares the native method: 69 the result of escaping the name. 70 3. an underscore ("_") 71 4. the escaped method name 72 5. if the native method declaration is overloaded: two underscores ("__") followed by the 73 escaped parameter descriptor (JVMS 4.3.3) of the method declaration. 74 75 Escaping leaves every alphanumeric ASCII character (A-Za-z0-9) unchanged, and replaces each 76 UTF-16 code unit n the table below with the corresponding escape sequence. If the name to be 77 escaped contains a surrogate pair, then the high-surrogate code unit and the low-surrogate code 78 unit are escaped separately. The result of escaping is a string consisting only of the ASCII 79 characters A-Za-z0-9 and underscore. 80 81 ------------------------------ ------------------------------------ 82 UTF-16 code unit Escape sequence 83 ------------------------------ ------------------------------------ 84 Forward slash (/, U+002F) _ 85 Underscore (_, U+005F) _1 86 Semicolon (;, U+003B) _2 87 Left square bracket ([, U+005B) _3 88 Any UTF-16 code unit \u_WXYZ_ that does not _0wxyz where w, x, y, and z are the lower-case 89 represent alphanumeric ASCII (A-Za-z0-9), forms of the hexadecimal digits W, X, Y, and Z. 90 forward slash, underscore, semicolon, (For example, U+ABCD becomes _0abcd.) 91 or left square bracket 92 ------------------------------ ------------------------------------ 93 94 Note that escape sequences can safely begin _0, _1, etc, because class and method 95 names in Java source code never begin with a number. However, that is not the case in 96 class files that were not generated from Java source code. 97 98 To preserve the 1:1 mapping to a native method name, the VM checks the resulting name as 99 follows. If the process of escaping any precursor string from the native method declaration 100 (class or method name, or argument type) causes a "0", "1", "2", or "3" character 101 from the precursor string to appear unchanged in the result *either* immediately after an 102 underscore *or* at the beginning of the escaped string (where it will follow an underscore 103 in the fully assembled name), then the escaping process is said to have "failed". 104 In such cases, no native library search is performed, and the attempt to link the native 105 method invocation will throw UnsatisfiedLinkError. 106 107 108 For example: 109 110 package/my_class/method 111 112 and 113 114 package/my/1class/method 115 116 both map to 117 118 Java_package_my_1class_method 119 120 To address this potential conflict we need only check if the character after 121 / is a digit 0..3, or if the first character after an injected '_' separator 122 is a digit 0..3. If we encounter an invalid identifier we reset the 123 stringStream and return false. Otherwise the stringStream contains the mapped 124 name and we return true. 125 126 */ 127 static bool map_escaped_name_on(stringStream* st, Symbol* name, int begin, int end) { 128 char* bytes = (char*)name->bytes() + begin; 129 char* end_bytes = (char*)name->bytes() + end; 130 bool check_escape_char = true; // initially true as first character here follows '_' 131 while (bytes < end_bytes) { 132 jchar c; 133 bytes = UTF8::next(bytes, &c); 134 if (c <= 0x7f && isalnum(c)) { 135 if (check_escape_char && (c >= '0' && c <= '3')) { 136 // This is a non-Java identifier and we won't escape it to 137 // ensure no name collisions with a Java identifier. 138 if (log_is_enabled(Debug, jni, resolve)) { 139 ResourceMark rm; 140 log_debug(jni, resolve)("[Lookup of native method with non-Java identifier rejected: %s]", 141 name->as_C_string()); 142 } 143 st->reset(); // restore to "" on error 144 return false; 145 } 146 st->put((char) c); 147 check_escape_char = false; 148 } else { 149 check_escape_char = false; 150 if (c == '_') st->print("_1"); 151 else if (c == '/') { 152 st->print("_"); 153 // Following a / we must have non-escape character 154 check_escape_char = true; 155 } 156 else if (c == ';') st->print("_2"); 157 else if (c == '[') st->print("_3"); 158 else st->print("_%.5x", c); 159 } 160 } 161 return true; 162 } 163 164 165 static bool map_escaped_name_on(stringStream* st, Symbol* name) { 166 return map_escaped_name_on(st, name, 0, name->utf8_length()); 167 } 168 169 170 char* NativeLookup::pure_jni_name(const methodHandle& method) { 171 stringStream st; 172 // Prefix 173 st.print("Java_"); 174 // Klass name 175 if (!map_escaped_name_on(&st, method->klass_name())) { 176 return nullptr; 177 } 178 st.print("_"); 179 // Method name 180 if (!map_escaped_name_on(&st, method->name())) { 181 return nullptr; 182 } 183 return st.as_string(); 184 } 185 186 char* NativeLookup::long_jni_name(const methodHandle& method) { 187 // Signatures ignore the wrapping parentheses and the trailing return type 188 stringStream st; 189 Symbol* signature = method->signature(); 190 st.print("__"); 191 // find ')' 192 int end; 193 for (end = 0; end < signature->utf8_length() && signature->char_at(end) != JVM_SIGNATURE_ENDFUNC; end++); 194 // skip first '(' 195 if (!map_escaped_name_on(&st, signature, 1, end)) { 196 return nullptr; 197 } 198 199 return st.as_string(); 200 } 201 202 extern "C" { 203 void JNICALL JVM_RegisterMethodHandleMethods(JNIEnv *env, jclass unsafecls); 204 void JNICALL JVM_RegisterReferencesMethods(JNIEnv *env, jclass unsafecls); 205 void JNICALL JVM_RegisterUpcallHandlerMethods(JNIEnv *env, jclass unsafecls); 206 void JNICALL JVM_RegisterUpcallLinkerMethods(JNIEnv *env, jclass unsafecls); 207 void JNICALL JVM_RegisterNativeEntryPointMethods(JNIEnv *env, jclass unsafecls); 208 void JNICALL JVM_RegisterPerfMethods(JNIEnv *env, jclass perfclass); 209 void JNICALL JVM_RegisterWhiteBoxMethods(JNIEnv *env, jclass wbclass); 210 void JNICALL JVM_RegisterVectorSupportMethods(JNIEnv *env, jclass vsclass); 211 #if INCLUDE_JVMCI 212 jobject JNICALL JVM_GetJVMCIRuntime(JNIEnv *env, jclass c); 213 jlong JNICALL JVM_ReadSystemPropertiesInfo(JNIEnv *env, jclass c, jintArray offsets); 214 void JNICALL JVM_RegisterJVMCINatives(JNIEnv *env, jclass compilerToVMClass); 215 #endif 216 } 217 218 #define CC (char*) /* cast a literal from (const char*) */ 219 #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f) 220 221 static JNINativeMethod lookup_special_native_methods[] = { 222 { CC"Java_jdk_internal_misc_Unsafe_registerNatives", nullptr, FN_PTR(JVM_RegisterJDKInternalMiscUnsafeMethods) }, 223 { CC"Java_java_lang_invoke_MethodHandleNatives_registerNatives", nullptr, FN_PTR(JVM_RegisterMethodHandleMethods) }, 224 { CC"Java_jdk_internal_foreign_abi_UpcallStubs_registerNatives", nullptr, FN_PTR(JVM_RegisterUpcallHandlerMethods) }, 225 { CC"Java_jdk_internal_foreign_abi_UpcallLinker_registerNatives", nullptr, FN_PTR(JVM_RegisterUpcallLinkerMethods) }, 226 { CC"Java_jdk_internal_foreign_abi_NativeEntryPoint_registerNatives", nullptr, FN_PTR(JVM_RegisterNativeEntryPointMethods) }, 227 { CC"Java_jdk_internal_perf_Perf_registerNatives", nullptr, FN_PTR(JVM_RegisterPerfMethods) }, 228 { CC"Java_sun_hotspot_WhiteBox_registerNatives", nullptr, FN_PTR(JVM_RegisterWhiteBoxMethods) }, 229 { CC"Java_jdk_test_whitebox_WhiteBox_registerNatives", nullptr, FN_PTR(JVM_RegisterWhiteBoxMethods) }, 230 { CC"Java_jdk_internal_vm_vector_VectorSupport_registerNatives", nullptr, FN_PTR(JVM_RegisterVectorSupportMethods)}, 231 #if INCLUDE_JVMCI 232 { CC"Java_jdk_vm_ci_runtime_JVMCI_initializeRuntime", nullptr, FN_PTR(JVM_GetJVMCIRuntime) }, 233 { CC"Java_jdk_vm_ci_services_Services_readSystemPropertiesInfo", nullptr, FN_PTR(JVM_ReadSystemPropertiesInfo) }, 234 { CC"Java_jdk_vm_ci_hotspot_CompilerToVM_registerNatives", nullptr, FN_PTR(JVM_RegisterJVMCINatives) }, 235 #endif 236 #if INCLUDE_JFR 237 { CC"Java_jdk_jfr_internal_JVM_registerNatives", nullptr, FN_PTR(jfr_register_natives) }, 238 #endif 239 { CC"Java_jdk_internal_misc_ScopedMemoryAccess_registerNatives", nullptr, FN_PTR(JVM_RegisterJDKInternalMiscScopedMemoryAccessMethods) }, 240 { CC"Java_net_shipilev_Magic_registerNatives", nullptr, FN_PTR(JVM_RegisterNetShipilevMagicMethods) }, 241 }; 242 243 static address lookup_special_native(const char* jni_name) { 244 int count = sizeof(lookup_special_native_methods) / sizeof(JNINativeMethod); 245 for (int i = 0; i < count; i++) { 246 // NB: To ignore the jni prefix and jni postfix strstr is used matching. 247 if (strstr(jni_name, lookup_special_native_methods[i].name) != nullptr) { 248 return CAST_FROM_FN_PTR(address, lookup_special_native_methods[i].fnPtr); 249 } 250 } 251 return nullptr; 252 } 253 254 address NativeLookup::lookup_style(const methodHandle& method, char* pure_name, const char* long_name, int args_size, TRAPS) { 255 address entry; 256 const char* jni_name = compute_complete_jni_name(pure_name, long_name, args_size); 257 258 259 // If the loader is null we have a system class, so we attempt a lookup in 260 // the native Java library. This takes care of any bootstrapping problems. 261 // Note: It is critical for bootstrapping that Java_java_lang_ClassLoader_findNative 262 // gets found the first time around - otherwise an infinite loop can occur. This is 263 // another VM/library dependency 264 Handle loader(THREAD, method->method_holder()->class_loader()); 265 if (loader.is_null()) { 266 entry = lookup_special_native(jni_name); 267 if (entry == nullptr) { 268 entry = (address) os::dll_lookup(os::native_java_library(), jni_name); 269 } 270 if (entry != nullptr) { 271 return entry; 272 } 273 } 274 275 // Otherwise call static method findNative in ClassLoader 276 Klass* klass = vmClasses::ClassLoader_klass(); 277 Handle jni_class(THREAD, method->method_holder()->java_mirror()); 278 Handle jni_name_arg = java_lang_String::create_from_str(jni_name, CHECK_NULL); 279 Handle java_name_arg = java_lang_String::create_from_str(method->name()->as_C_string(), CHECK_NULL); 280 281 JavaCallArguments args; 282 args.push_oop(loader); 283 args.push_oop(jni_class); 284 args.push_oop(jni_name_arg); 285 args.push_oop(java_name_arg); 286 287 JavaValue result(T_LONG); 288 JavaCalls::call_static(&result, 289 klass, 290 vmSymbols::findNative_name(), 291 vmSymbols::classloader_class_string_string_long_signature(), 292 &args, 293 CHECK_NULL); 294 entry = (address) (intptr_t) result.get_jlong(); 295 296 if (entry == nullptr) { 297 // findNative didn't find it, if there are any agent libraries look in them 298 JvmtiAgentList::Iterator it = JvmtiAgentList::agents(); 299 while (it.has_next()) { 300 entry = (address)os::dll_lookup(it.next()->os_lib(), jni_name); 301 if (entry != nullptr) { 302 return entry; 303 } 304 } 305 } 306 307 return entry; 308 } 309 310 const char* NativeLookup::compute_complete_jni_name(const char* pure_name, const char* long_name, int args_size) { 311 stringStream st; 312 st.print_raw(pure_name); 313 st.print_raw(long_name); 314 315 return st.as_string(); 316 } 317 318 // Check all the formats of native implementation name to see if there is one 319 // for the specified method. 320 address NativeLookup::lookup_entry(const methodHandle& method, TRAPS) { 321 address entry = nullptr; 322 // Compute pure name 323 char* pure_name = pure_jni_name(method); 324 if (pure_name == nullptr) { 325 // JNI name mapping rejected this method so return 326 // null to indicate UnsatisfiedLinkError should be thrown. 327 return nullptr; 328 } 329 330 // Compute argument size 331 int args_size = 1 // JNIEnv 332 + (method->is_static() ? 1 : 0) // class for static methods 333 + method->size_of_parameters(); // actual parameters 334 335 // 1) Try JNI short style 336 entry = lookup_style(method, pure_name, "", args_size, CHECK_NULL); 337 if (entry != nullptr) return entry; 338 339 // Compute long name 340 char* long_name = long_jni_name(method); 341 if (long_name == nullptr) { 342 // JNI name mapping rejected this method so return 343 // null to indicate UnsatisfiedLinkError should be thrown. 344 return nullptr; 345 } 346 347 // 2) Try JNI long style 348 entry = lookup_style(method, pure_name, long_name, args_size, CHECK_NULL); 349 350 return entry; // null indicates not found 351 } 352 353 // Check if there are any JVM TI prefixes which have been applied to the native method name. 354 // If any are found, remove them before attempting the look up of the 355 // native implementation again. 356 // See SetNativeMethodPrefix in the JVM TI Spec for more details. 357 address NativeLookup::lookup_entry_prefixed(const methodHandle& method, TRAPS) { 358 #if INCLUDE_JVMTI 359 ResourceMark rm(THREAD); 360 361 int prefix_count; 362 char** prefixes = JvmtiExport::get_all_native_method_prefixes(&prefix_count); 363 char* in_name = method->name()->as_C_string(); 364 char* wrapper_name = in_name; 365 // last applied prefix will be first -- go backwards 366 for (int i = prefix_count-1; i >= 0; i--) { 367 char* prefix = prefixes[i]; 368 size_t prefix_len = strlen(prefix); 369 if (strncmp(prefix, wrapper_name, prefix_len) == 0) { 370 // has this prefix remove it 371 wrapper_name += prefix_len; 372 } 373 } 374 if (wrapper_name != in_name) { 375 // we have a name for a wrapping method 376 int wrapper_name_len = (int)strlen(wrapper_name); 377 TempNewSymbol wrapper_symbol = SymbolTable::probe(wrapper_name, wrapper_name_len); 378 if (wrapper_symbol != nullptr) { 379 Klass* k = method->method_holder(); 380 Method* wrapper_method = k->lookup_method(wrapper_symbol, method->signature()); 381 if (wrapper_method != nullptr && !wrapper_method->is_native()) { 382 // we found a wrapper method, use its native entry 383 method->set_is_prefixed_native(); 384 return lookup_entry(methodHandle(THREAD, wrapper_method), THREAD); 385 } 386 } 387 } 388 #endif // INCLUDE_JVMTI 389 return nullptr; 390 } 391 392 address NativeLookup::lookup_base(const methodHandle& method, TRAPS) { 393 address entry = nullptr; 394 ResourceMark rm(THREAD); 395 396 entry = lookup_entry(method, CHECK_NULL); 397 if (entry != nullptr) return entry; 398 399 // standard native method resolution has failed. Check if there are any 400 // JVM TI prefixes which have been applied to the native method name. 401 entry = lookup_entry_prefixed(method, CHECK_NULL); 402 if (entry != nullptr) return entry; 403 404 if (THREAD->has_pending_exception()) { 405 oop exception = THREAD->pending_exception(); 406 if (exception->is_a(vmClasses::IllegalCallerException_klass())) { 407 // we already have a pending exception from the restricted method check, just return 408 return nullptr; 409 } 410 } 411 412 // Native function not found, throw UnsatisfiedLinkError 413 stringStream ss; 414 ss.print("'"); 415 method->print_external_name(&ss); 416 ss.print("'"); 417 THROW_MSG_NULL(vmSymbols::java_lang_UnsatisfiedLinkError(), ss.as_string()); 418 } 419 420 421 address NativeLookup::lookup(const methodHandle& method, TRAPS) { 422 if (!method->has_native_function()) { 423 address entry = lookup_base(method, CHECK_NULL); 424 method->set_native_function(entry, 425 Method::native_bind_event_is_interesting); 426 // -verbose:jni printing 427 if (log_is_enabled(Debug, jni, resolve)) { 428 ResourceMark rm(THREAD); 429 log_debug(jni, resolve)("[Dynamic-linking native method %s.%s ... JNI]", 430 method->method_holder()->external_name(), 431 method->name()->as_C_string()); 432 } 433 } 434 return method->native_function(); 435 } --- EOF ---