1 /* 2 * Copyright (c) 1997, 2023, 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 "precompiled.hpp" 26 #include "classfile/javaClasses.hpp" 27 #include "classfile/symbolTable.hpp" 28 #include "classfile/systemDictionary.hpp" 29 #include "classfile/vmClasses.hpp" 30 #include "classfile/vmSymbols.hpp" 31 #include "logging/log.hpp" 32 #include "logging/logTag.hpp" 33 #include "memory/oopFactory.hpp" 34 #include "memory/resourceArea.hpp" 35 #include "oops/instanceKlass.hpp" 36 #include "oops/klass.inline.hpp" 37 #include "oops/method.hpp" 38 #include "oops/oop.inline.hpp" 39 #include "oops/symbol.hpp" 40 #include "prims/jvmtiAgentList.hpp" 41 #include "prims/jvm_misc.hpp" 42 #include "prims/jvmtiExport.hpp" 43 #include "prims/nativeLookup.hpp" 44 #include "prims/unsafe.hpp" 45 #include "prims/scopedMemoryAccess.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 }; 241 242 static address lookup_special_native(const char* jni_name) { 243 int count = sizeof(lookup_special_native_methods) / sizeof(JNINativeMethod); 244 for (int i = 0; i < count; i++) { 245 // NB: To ignore the jni prefix and jni postfix strstr is used matching. 246 if (strstr(jni_name, lookup_special_native_methods[i].name) != nullptr) { 247 return CAST_FROM_FN_PTR(address, lookup_special_native_methods[i].fnPtr); 248 } 249 } 250 return nullptr; 251 } 252 253 address NativeLookup::lookup_style(const methodHandle& method, char* pure_name, const char* long_name, int args_size, bool os_style, TRAPS) { 254 address entry; 255 const char* jni_name = compute_complete_jni_name(pure_name, long_name, args_size, os_style); 256 257 258 // If the loader is null we have a system class, so we attempt a lookup in 259 // the native Java library. This takes care of any bootstrapping problems. 260 // Note: It is critical for bootstrapping that Java_java_lang_ClassLoader_findNative 261 // gets found the first time around - otherwise an infinite loop can occur. This is 262 // another VM/library dependency 263 Handle loader(THREAD, method->method_holder()->class_loader()); 264 if (loader.is_null()) { 265 entry = lookup_special_native(jni_name); 266 if (entry == nullptr) { 267 entry = (address) os::dll_lookup(os::native_java_library(), jni_name); 268 } 269 if (entry != nullptr) { 270 return entry; 271 } 272 } 273 274 // Otherwise call static method findNative in ClassLoader 275 Klass* klass = vmClasses::ClassLoader_klass(); 276 Handle name_arg = java_lang_String::create_from_str(jni_name, CHECK_NULL); 277 278 JavaValue result(T_LONG); 279 JavaCalls::call_static(&result, 280 klass, 281 vmSymbols::findNative_name(), 282 vmSymbols::classloader_string_long_signature(), 283 // Arguments 284 loader, 285 name_arg, 286 CHECK_NULL); 287 entry = (address) (intptr_t) result.get_jlong(); 288 289 if (entry == nullptr) { 290 // findNative didn't find it, if there are any agent libraries look in them 291 JvmtiAgentList::Iterator it = JvmtiAgentList::agents(); 292 while (it.has_next()) { 293 entry = (address)os::dll_lookup(it.next()->os_lib(), jni_name); 294 if (entry != nullptr) { 295 return entry; 296 } 297 } 298 } 299 300 return entry; 301 } 302 303 const char* NativeLookup::compute_complete_jni_name(const char* pure_name, const char* long_name, int args_size, bool os_style) { 304 stringStream st; 305 if (os_style) { 306 os::print_jni_name_prefix_on(&st, args_size); 307 } 308 309 st.print_raw(pure_name); 310 st.print_raw(long_name); 311 if (os_style) { 312 os::print_jni_name_suffix_on(&st, args_size); 313 } 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, true, 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, true, CHECK_NULL); 349 if (entry != nullptr) return entry; 350 351 // 3) Try JNI short style without os prefix/suffix 352 entry = lookup_style(method, pure_name, "", args_size, false, CHECK_NULL); 353 if (entry != nullptr) return entry; 354 355 // 4) Try JNI long style without os prefix/suffix 356 entry = lookup_style(method, pure_name, long_name, args_size, false, CHECK_NULL); 357 358 return entry; // null indicates not found 359 } 360 361 // Check if there are any JVM TI prefixes which have been applied to the native method name. 362 // If any are found, remove them before attempting the look up of the 363 // native implementation again. 364 // See SetNativeMethodPrefix in the JVM TI Spec for more details. 365 address NativeLookup::lookup_entry_prefixed(const methodHandle& method, TRAPS) { 366 #if INCLUDE_JVMTI 367 ResourceMark rm(THREAD); 368 369 int prefix_count; 370 char** prefixes = JvmtiExport::get_all_native_method_prefixes(&prefix_count); 371 char* in_name = method->name()->as_C_string(); 372 char* wrapper_name = in_name; 373 // last applied prefix will be first -- go backwards 374 for (int i = prefix_count-1; i >= 0; i--) { 375 char* prefix = prefixes[i]; 376 size_t prefix_len = strlen(prefix); 377 if (strncmp(prefix, wrapper_name, prefix_len) == 0) { 378 // has this prefix remove it 379 wrapper_name += prefix_len; 380 } 381 } 382 if (wrapper_name != in_name) { 383 // we have a name for a wrapping method 384 int wrapper_name_len = (int)strlen(wrapper_name); 385 TempNewSymbol wrapper_symbol = SymbolTable::probe(wrapper_name, wrapper_name_len); 386 if (wrapper_symbol != nullptr) { 387 Klass* k = method->method_holder(); 388 Method* wrapper_method = k->lookup_method(wrapper_symbol, method->signature()); 389 if (wrapper_method != nullptr && !wrapper_method->is_native()) { 390 // we found a wrapper method, use its native entry 391 method->set_is_prefixed_native(); 392 return lookup_entry(methodHandle(THREAD, wrapper_method), THREAD); 393 } 394 } 395 } 396 #endif // INCLUDE_JVMTI 397 return nullptr; 398 } 399 400 address NativeLookup::lookup_base(const methodHandle& method, TRAPS) { 401 address entry = nullptr; 402 ResourceMark rm(THREAD); 403 404 entry = lookup_entry(method, CHECK_NULL); 405 if (entry != nullptr) return entry; 406 407 // standard native method resolution has failed. Check if there are any 408 // JVM TI prefixes which have been applied to the native method name. 409 entry = lookup_entry_prefixed(method, CHECK_NULL); 410 if (entry != nullptr) return entry; 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_0(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 }