1 /* 2 * Copyright (c) 2021, 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. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 26 package jdk.internal.foreign; 27 28 import jdk.incubator.foreign.MemoryAccess; 29 import jdk.incubator.foreign.MemorySegment; 30 import jdk.incubator.foreign.ResourceScope; 31 import jdk.incubator.foreign.SymbolLookup; 32 import jdk.incubator.foreign.MemoryAddress; 33 import jdk.internal.loader.NativeLibraries; 34 import jdk.internal.loader.NativeLibrary; 35 36 import java.nio.file.Files; 37 import java.nio.file.Path; 38 import java.util.Objects; 39 import java.util.Optional; 40 import java.util.function.Function; 41 42 import static jdk.incubator.foreign.CLinker.C_POINTER; 43 44 public class SystemLookup implements SymbolLookup { 45 SystemLookup()46 private SystemLookup() { } 47 48 final static SystemLookup INSTANCE = new SystemLookup(); 49 50 /* 51 * On POSIX systems, dlsym will allow us to lookup symbol in library dependencies; the same trick doesn't work 52 * on Windows. For this reason, on Windows we do not generate any side-library, and load msvcrt.dll directly instead. 53 */ 54 private static final SymbolLookup syslookup = switch (CABI.current()) { 55 case SysV, LinuxAArch64, MacOsAArch64 -> libLookup(libs -> libs.loadLibrary("syslookup")); 56 case Win64 -> makeWindowsLookup(); // out of line to workaround javac crash 57 }; 58 makeWindowsLookup()59 private static SymbolLookup makeWindowsLookup() { 60 Path system32 = Path.of(System.getenv("SystemRoot"), "System32"); 61 Path ucrtbase = system32.resolve("ucrtbase.dll"); 62 Path msvcrt = system32.resolve("msvcrt.dll"); 63 64 boolean useUCRT = Files.exists(ucrtbase); 65 Path stdLib = useUCRT ? ucrtbase : msvcrt; 66 SymbolLookup lookup = libLookup(libs -> libs.loadLibrary(null, stdLib.toFile())); 67 68 if (useUCRT) { 69 // use a fallback lookup to look up inline functions from fallback lib 70 71 SymbolLookup fallbackLibLookup = libLookup(libs -> libs.loadLibrary("WinFallbackLookup")); 72 73 int numSymbols = WindowsFallbackSymbols.values().length; 74 MemorySegment funcs = fallbackLibLookup.lookup("funcs").orElseThrow() 75 .asSegment(C_POINTER.byteSize() * numSymbols, ResourceScope.newImplicitScope()); 76 77 SymbolLookup fallbackLookup = name -> Optional.ofNullable(WindowsFallbackSymbols.valueOfOrNull(name)) 78 .map(symbol -> MemoryAccess.getAddressAtIndex(funcs, symbol.ordinal())); 79 80 final SymbolLookup finalLookup = lookup; 81 lookup = name -> finalLookup.lookup(name).or(() -> fallbackLookup.lookup(name)); 82 } 83 84 return lookup; 85 } 86 libLookup(Function<NativeLibraries, NativeLibrary> loader)87 private static SymbolLookup libLookup(Function<NativeLibraries, NativeLibrary> loader) { 88 NativeLibrary lib = loader.apply(NativeLibraries.rawNativeLibraries(SystemLookup.class, false)); 89 return name -> { 90 Objects.requireNonNull(name); 91 try { 92 long addr = lib.lookup(name); 93 return addr == 0 ? 94 Optional.empty() : Optional.of(MemoryAddress.ofLong(addr)); 95 } catch (NoSuchMethodException e) { 96 return Optional.empty(); 97 } 98 }; 99 } 100 101 @Override lookup(String name)102 public Optional<MemoryAddress> lookup(String name) { 103 return syslookup.lookup(name); 104 } 105 getInstance()106 public static SystemLookup getInstance() { 107 return INSTANCE; 108 } 109 110 // fallback symbols missing from ucrtbase.dll 111 // this list has to be kept in sync with the table in the companion native library 112 private enum WindowsFallbackSymbols { 113 // stdio 114 fprintf, 115 fprintf_s, 116 fscanf, 117 fscanf_s, 118 fwprintf, 119 fwprintf_s, 120 fwscanf, 121 fwscanf_s, 122 printf, 123 printf_s, 124 scanf, 125 scanf_s, 126 snprintf, 127 sprintf, 128 sprintf_s, 129 sscanf, 130 sscanf_s, 131 swprintf, 132 swprintf_s, 133 swscanf, 134 swscanf_s, 135 vfprintf, 136 vfprintf_s, 137 vfscanf, 138 vfscanf_s, 139 vfwprintf, 140 vfwprintf_s, 141 vfwscanf, 142 vfwscanf_s, 143 vprintf, 144 vprintf_s, 145 vscanf, 146 vscanf_s, 147 vsnprintf, 148 vsnprintf_s, 149 vsprintf, 150 vsprintf_s, 151 vsscanf, 152 vsscanf_s, 153 vswprintf, 154 vswprintf_s, 155 vswscanf, 156 vswscanf_s, 157 vwprintf, 158 vwprintf_s, 159 vwscanf, 160 vwscanf_s, 161 wprintf, 162 wprintf_s, 163 wscanf, 164 wscanf_s, 165 166 // time 167 gmtime 168 ; 169 valueOfOrNull(String name)170 static WindowsFallbackSymbols valueOfOrNull(String name) { 171 try { 172 return valueOf(name); 173 } catch (IllegalArgumentException e) { 174 return null; 175 } 176 } 177 } 178 } 179