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 "prims/shipilevMagic.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 void JNICALL JVM_RegisterJVMCINatives(JNIEnv *env, jclass compilerToVMClass); 214 #endif 215 } 216 217 #define CC (char*) /* cast a literal from (const char*) */ 218 #define FN_PTR(f) CAST_FROM_FN_PTR(void*, &f) 219 220 static JNINativeMethod lookup_special_native_methods[] = { 221 { CC"Java_jdk_internal_misc_Unsafe_registerNatives", nullptr, FN_PTR(JVM_RegisterJDKInternalMiscUnsafeMethods) }, 222 { CC"Java_java_lang_invoke_MethodHandleNatives_registerNatives", nullptr, FN_PTR(JVM_RegisterMethodHandleMethods) }, 223 { CC"Java_jdk_internal_foreign_abi_UpcallStubs_registerNatives", nullptr, FN_PTR(JVM_RegisterUpcallHandlerMethods) }, 224 { CC"Java_jdk_internal_foreign_abi_UpcallLinker_registerNatives", nullptr, FN_PTR(JVM_RegisterUpcallLinkerMethods) }, 225 { CC"Java_jdk_internal_foreign_abi_NativeEntryPoint_registerNatives", nullptr, FN_PTR(JVM_RegisterNativeEntryPointMethods) }, 226 { CC"Java_jdk_internal_perf_Perf_registerNatives", nullptr, FN_PTR(JVM_RegisterPerfMethods) }, 227 { CC"Java_sun_hotspot_WhiteBox_registerNatives", nullptr, FN_PTR(JVM_RegisterWhiteBoxMethods) }, 228 { CC"Java_jdk_test_whitebox_WhiteBox_registerNatives", nullptr, FN_PTR(JVM_RegisterWhiteBoxMethods) }, 229 { CC"Java_jdk_internal_vm_vector_VectorSupport_registerNatives", nullptr, FN_PTR(JVM_RegisterVectorSupportMethods)}, 230 #if INCLUDE_JVMCI 231 { CC"Java_jdk_vm_ci_runtime_JVMCI_initializeRuntime", nullptr, FN_PTR(JVM_GetJVMCIRuntime) }, 232 { CC"Java_jdk_vm_ci_hotspot_CompilerToVM_registerNatives", nullptr, FN_PTR(JVM_RegisterJVMCINatives) }, 233 #endif 234 #if INCLUDE_JFR 235 { CC"Java_jdk_jfr_internal_JVM_registerNatives", nullptr, FN_PTR(jfr_register_natives) }, 236 #endif 237 { CC"Java_jdk_internal_misc_ScopedMemoryAccess_registerNatives", nullptr, FN_PTR(JVM_RegisterJDKInternalMiscScopedMemoryAccessMethods) }, 238 { CC"Java_net_shipilev_Magic_registerNatives", nullptr, FN_PTR(JVM_RegisterNetShipilevMagicMethods) }, 239 }; 240 241 static address lookup_special_native(const char* jni_name) { 242 int count = sizeof(lookup_special_native_methods) / sizeof(JNINativeMethod); 243 for (int i = 0; i < count; i++) { 244 // NB: To ignore the jni prefix and jni postfix strstr is used matching. 245 if (strstr(jni_name, lookup_special_native_methods[i].name) != nullptr) { 246 return CAST_FROM_FN_PTR(address, lookup_special_native_methods[i].fnPtr); 247 } 248 } 249 return nullptr; 250 } 251 252 address NativeLookup::lookup_style(const methodHandle& method, char* pure_name, const char* long_name, int args_size, bool os_style, TRAPS) { 253 address entry; 254 const char* jni_name = compute_complete_jni_name(pure_name, long_name, args_size, os_style); 255 256 257 // If the loader is null we have a system class, so we attempt a lookup in 258 // the native Java library. This takes care of any bootstrapping problems. 259 // Note: It is critical for bootstrapping that Java_java_lang_ClassLoader_findNative 260 // gets found the first time around - otherwise an infinite loop can occur. This is 261 // another VM/library dependency 262 Handle loader(THREAD, method->method_holder()->class_loader()); 263 if (loader.is_null()) { 264 entry = lookup_special_native(jni_name); 265 if (entry == nullptr) { 266 entry = (address) os::dll_lookup(os::native_java_library(), jni_name); 267 } 268 if (entry != nullptr) { 269 return entry; 270 } 271 } 272 273 // Otherwise call static method findNative in ClassLoader 274 Klass* klass = vmClasses::ClassLoader_klass(); 275 Handle name_arg = java_lang_String::create_from_str(jni_name, CHECK_NULL); 276 277 JavaValue result(T_LONG); 278 JavaCalls::call_static(&result, 279 klass, 280 vmSymbols::findNative_name(), 281 vmSymbols::classloader_string_long_signature(), 282 // Arguments 283 loader, 284 name_arg, 285 CHECK_NULL); 286 entry = (address) (intptr_t) result.get_jlong(); 287 288 if (entry == nullptr) { 289 // findNative didn't find it, if there are any agent libraries look in them 290 AgentLibrary* agent; 291 for (agent = Arguments::agents(); agent != nullptr; agent = agent->next()) { 292 entry = (address) os::dll_lookup(agent->os_lib(), jni_name); 293 if (entry != nullptr) { 294 return entry; 295 } 296 } 297 } 298 299 return entry; 300 } 301 302 const char* NativeLookup::compute_complete_jni_name(const char* pure_name, const char* long_name, int args_size, bool os_style) { 303 stringStream st; 304 if (os_style) { 305 os::print_jni_name_prefix_on(&st, args_size); 306 } 307 308 st.print_raw(pure_name); 309 st.print_raw(long_name); 310 if (os_style) { 311 os::print_jni_name_suffix_on(&st, args_size); 312 } 313 314 return st.as_string(); 315 } 316 317 // Check all the formats of native implementation name to see if there is one 318 // for the specified method. 319 address NativeLookup::lookup_entry(const methodHandle& method, TRAPS) { 320 address entry = nullptr; 321 // Compute pure name 322 char* pure_name = pure_jni_name(method); 323 if (pure_name == nullptr) { 324 // JNI name mapping rejected this method so return 325 // null to indicate UnsatisfiedLinkError should be thrown. 326 return nullptr; 327 } 328 329 // Compute argument size 330 int args_size = 1 // JNIEnv 331 + (method->is_static() ? 1 : 0) // class for static methods 332 + method->size_of_parameters(); // actual parameters 333 334 // 1) Try JNI short style 335 entry = lookup_style(method, pure_name, "", args_size, true, CHECK_NULL); 336 if (entry != nullptr) return entry; 337 338 // Compute long name 339 char* long_name = long_jni_name(method); 340 if (long_name == nullptr) { 341 // JNI name mapping rejected this method so return 342 // null to indicate UnsatisfiedLinkError should be thrown. 343 return nullptr; 344 } 345 346 // 2) Try JNI long style 347 entry = lookup_style(method, pure_name, long_name, args_size, true, CHECK_NULL); 348 if (entry != nullptr) return entry; 349 350 // 3) Try JNI short style without os prefix/suffix 351 entry = lookup_style(method, pure_name, "", args_size, false, CHECK_NULL); 352 if (entry != nullptr) return entry; 353 354 // 4) Try JNI long style without os prefix/suffix 355 entry = lookup_style(method, pure_name, long_name, args_size, false, CHECK_NULL); 356 357 return entry; // null indicates not found 358 } 359 360 // Check if there are any JVM TI prefixes which have been applied to the native method name. 361 // If any are found, remove them before attempting the look up of the 362 // native implementation again. 363 // See SetNativeMethodPrefix in the JVM TI Spec for more details. 364 address NativeLookup::lookup_entry_prefixed(const methodHandle& method, TRAPS) { 365 #if INCLUDE_JVMTI 366 ResourceMark rm(THREAD); 367 368 int prefix_count; 369 char** prefixes = JvmtiExport::get_all_native_method_prefixes(&prefix_count); 370 char* in_name = method->name()->as_C_string(); 371 char* wrapper_name = in_name; 372 // last applied prefix will be first -- go backwards 373 for (int i = prefix_count-1; i >= 0; i--) { 374 char* prefix = prefixes[i]; 375 size_t prefix_len = strlen(prefix); 376 if (strncmp(prefix, wrapper_name, prefix_len) == 0) { 377 // has this prefix remove it 378 wrapper_name += prefix_len; 379 } 380 } 381 if (wrapper_name != in_name) { 382 // we have a name for a wrapping method 383 int wrapper_name_len = (int)strlen(wrapper_name); 384 TempNewSymbol wrapper_symbol = SymbolTable::probe(wrapper_name, wrapper_name_len); 385 if (wrapper_symbol != nullptr) { 386 Klass* k = method->method_holder(); 387 Method* wrapper_method = k->lookup_method(wrapper_symbol, method->signature()); 388 if (wrapper_method != nullptr && !wrapper_method->is_native()) { 389 // we found a wrapper method, use its native entry 390 method->set_is_prefixed_native(); 391 return lookup_entry(methodHandle(THREAD, wrapper_method), THREAD); 392 } 393 } 394 } 395 #endif // INCLUDE_JVMTI 396 return nullptr; 397 } 398 399 address NativeLookup::lookup_base(const methodHandle& method, TRAPS) { 400 address entry = nullptr; 401 ResourceMark rm(THREAD); 402 403 entry = lookup_entry(method, CHECK_NULL); 404 if (entry != nullptr) return entry; 405 406 // standard native method resolution has failed. Check if there are any 407 // JVM TI prefixes which have been applied to the native method name. 408 entry = lookup_entry_prefixed(method, CHECK_NULL); 409 if (entry != nullptr) return entry; 410 411 // Native function not found, throw UnsatisfiedLinkError 412 stringStream ss; 413 ss.print("'"); 414 method->print_external_name(&ss); 415 ss.print("'"); 416 THROW_MSG_0(vmSymbols::java_lang_UnsatisfiedLinkError(), ss.as_string()); 417 } 418 419 420 address NativeLookup::lookup(const methodHandle& method, TRAPS) { 421 if (!method->has_native_function()) { 422 address entry = lookup_base(method, CHECK_NULL); 423 method->set_native_function(entry, 424 Method::native_bind_event_is_interesting); 425 // -verbose:jni printing 426 if (log_is_enabled(Debug, jni, resolve)) { 427 ResourceMark rm(THREAD); 428 log_debug(jni, resolve)("[Dynamic-linking native method %s.%s ... JNI]", 429 method->method_holder()->external_name(), 430 method->name()->as_C_string()); 431 } 432 } 433 return method->native_function(); 434 }