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