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