├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── bin ├── c6-shim-env ├── c6-shim-run-exe └── nv-sglrun ├── icds ├── ocl │ └── nv.icd └── vk │ └── nv.json ├── src ├── fakecxxrt.map ├── futexes.c ├── glibc-symbols.32 ├── glibc-symbols.64 ├── globals.c ├── libc │ ├── ctype.c │ ├── dirent.c │ ├── dirent.h │ ├── dlfcn.c │ ├── errno.c │ ├── fcntl.c │ ├── fcntl.h │ ├── ftw.c │ ├── glob.c │ ├── glob.h │ ├── iconv.c │ ├── ifaddrs.c │ ├── langinfo.c │ ├── libgen.c │ ├── libintl.c │ ├── locale.c │ ├── locale.h │ ├── malloc.c │ ├── netdb.c │ ├── netdb.h │ ├── poll.c │ ├── pwd.c │ ├── sched.c │ ├── sched.h │ ├── semaphore.c │ ├── setjmp.c │ ├── signal.c │ ├── signal.h │ ├── spawn.c │ ├── stdio.c │ ├── stdlib.c │ ├── string.c │ ├── sys │ │ ├── epoll.c │ │ ├── eventfd.c │ │ ├── inotify.c │ │ ├── ioctl.c │ │ ├── mman.c │ │ ├── mount.c │ │ ├── mount.h │ │ ├── prctl.c │ │ ├── resource.c │ │ ├── select.c │ │ ├── sem.c │ │ ├── socket.c │ │ ├── socket.h │ │ ├── stat.c │ │ ├── stat.h │ │ ├── statvfs.c │ │ ├── syscall.c │ │ ├── sysctl.c │ │ ├── sysinfo.c │ │ ├── utsname.c │ │ └── utsname.h │ ├── termios.c │ ├── termios.h │ ├── time.c │ ├── time.h │ ├── ucontext.c │ ├── unistd.c │ └── wctype.c ├── libexecinfo │ └── execinfo.c ├── libm │ ├── fenv.c │ └── math.c ├── libthr │ ├── pthread.c │ └── pthread.h ├── main.c ├── prototypes.rb ├── shim.h ├── shim.map └── util.c └── utils ├── find_glibc_symbols.rb ├── prototype-check.rb ├── symver.rb ├── wrappers.rb ├── wrappers_c.rb └── wrappers_h.rb /.gitignore: -------------------------------------------------------------------------------- 1 | /.* 2 | /_* 3 | /build 4 | /lib32 5 | /lib64 6 | /nvidia 7 | /todo.txt 8 | *.core 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 shkhln 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | .PHONY: all clean check-prototypes 3 | 4 | BUILD_DIR = build 5 | SOURCES = ${:!find src -name \*.c | sort!} 6 | 7 | LIBS = $(BUILD_DIR)/lib64/libc6.so \ 8 | $(BUILD_DIR)/lib64/libc6-debug.so \ 9 | $(BUILD_DIR)/lib32/libc6.so \ 10 | $(BUILD_DIR)/lib32/libc6-debug.so 11 | 12 | CFLAGS = -std=c99 -Wall -Wextra -Wno-unused-parameter -Wno-incompatible-pointer-types-discards-qualifiers \ 13 | -shared -fPIC -Wl,-soname,librt.so.1 -Wl,--version-script=src/shim.map -Wl,--no-undefined -I/usr/local/include/libepoll-shim 14 | 15 | CCTYPE != $(CC) --version | grep -q clang && echo clang || true 16 | .if $(CCTYPE) == "clang" 17 | CFLAGS32 = -mstack-alignment=16 -mstackrealign # helps with movaps (?) crashes in steamclient.so a bit 18 | .endif 19 | 20 | LDFLAGS64 = -lexecinfo -lm -pthread 21 | LDFLAGS32 = -lexecinfo -lm -pthread -Wl,-z,notext # "relocation R_386_PC32 cannot be used against symbol _setjmp" 22 | 23 | GCC_VER ?= 9 24 | 25 | .if exists(/usr/local/lib/gcc${GCC_VER}) 26 | LIBS += $(BUILD_DIR)/lib64/fakecxxrt.so 27 | LIBS += $(BUILD_DIR)/lib32/fakecxxrt.so 28 | .endif 29 | 30 | all: $(LIBS) lib32 lib64 31 | 32 | .for b in 32 64 33 | 34 | lib$(b): 35 | ln -s $(BUILD_DIR)/lib$(b) lib$(b) 36 | 37 | $(BUILD_DIR)/versions$(b).h: 38 | mkdir -p $(BUILD_DIR) 39 | ./utils/symver.rb src/glibc-symbols.$(b) > $(.TARGET).tmp && mv $(.TARGET).tmp $(.TARGET) 40 | 41 | $(BUILD_DIR)/wrappers$(b).h: src/prototypes.rb $(SOURCES) 42 | mkdir -p $(BUILD_DIR) 43 | ./utils/wrappers_h.rb -I/usr/local/include/libepoll-shim -m$(b) $(SOURCES) > $(.TARGET).tmp && mv $(.TARGET).tmp $(.TARGET) 44 | 45 | $(BUILD_DIR)/wrappers$(b).c: src/prototypes.rb 46 | mkdir -p $(BUILD_DIR) 47 | ./utils/wrappers_c.rb src/glibc-symbols.$(b) > $(.TARGET).tmp && mv $(.TARGET).tmp $(.TARGET) 48 | 49 | $(BUILD_DIR)/lib$(b)/libc6.so: $(SOURCES) $(BUILD_DIR)/wrappers$(b).c $(BUILD_DIR)/wrappers$(b).h $(BUILD_DIR)/versions$(b).h $(BUILD_DIR)/lib$(b)/dummy-librt.so 50 | mkdir -p $(BUILD_DIR)/lib$(b) 51 | $(CC) -O2 -m$(b) $(CFLAGS) ${CFLAGS$(b)} -o $(.TARGET) $(SOURCES) \ 52 | -include $(BUILD_DIR)/versions$(b).h \ 53 | -include $(BUILD_DIR)/wrappers$(b).h \ 54 | $(BUILD_DIR)/wrappers$(b).c \ 55 | $(BUILD_DIR)/lib$(b)/dummy-librt.so \ 56 | ${LDFLAGS$(b)} 57 | 58 | $(BUILD_DIR)/lib$(b)/libc6-debug.so: $(BUILD_DIR)/lib$(b)/libc6.so $(BUILD_DIR)/lib$(b)/dummy-librt.so 59 | mkdir -p $(BUILD_DIR)/lib$(b) 60 | $(CC) -DDEBUG -m$(b) $(CFLAGS) ${CFLAGS$(b)} -o $(.TARGET) $(SOURCES) \ 61 | -include $(BUILD_DIR)/versions$(b).h \ 62 | -include $(BUILD_DIR)/wrappers$(b).h \ 63 | $(BUILD_DIR)/wrappers$(b).c \ 64 | $(BUILD_DIR)/lib$(b)/dummy-librt.so \ 65 | ${LDFLAGS$(b)} 66 | 67 | $(BUILD_DIR)/lib$(b)/dummy-librt.so: 68 | mkdir -p $(BUILD_DIR)/lib$(b) 69 | $(CC) -m$(b) -shared -fPIC -Wl,-soname,bsd-librt.so.1 -o $(.TARGET) 70 | 71 | $(BUILD_DIR)/lib$(b)/fakecxxrt.so: 72 | mkdir -p $(BUILD_DIR)/lib$(b) 73 | gcc${GCC_VER} -m$(b) -shared -fPIC \ 74 | -Wl,--version-script=src/fakecxxrt.map \ 75 | -Wl,-soname,libcxxrt.so.1 \ 76 | -Wl,-rpath=/usr/local/lib${b:S/64//}/gcc${GCC_VER} \ 77 | -L/usr/local/lib${b:S/64//}/gcc${GCC_VER} \ 78 | -lstdc++ \ 79 | -o $(.TARGET) 80 | 81 | .endfor 82 | 83 | check-prototypes: 84 | ./utils/prototype-check.rb | /compat/linux/bin/gcc -x c -std=c99 --sysroot=/compat/linux -o /dev/null - 85 | 86 | clean: 87 | .for f in $(LIBS) lib32 lib64 88 | . if exists($f) 89 | rm $f 90 | . endif 91 | .endfor 92 | .for b in 32 64 93 | . for f in $(BUILD_DIR)/wrappers$(b).c $(BUILD_DIR)/wrappers$(b).h $(BUILD_DIR)/versions$(b).h $(BUILD_DIR)/lib$(b)/dummy-librt.so 94 | . if exists($f) 95 | rm $f 96 | . endif 97 | . if exists($f.tmp) 98 | rm $f.tmp 99 | . endif 100 | . endfor 101 | .endfor 102 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | This repository contains a shim library providing limited glibc ABI compatibility on top of FreeBSD libc. 2 | 3 | The library is intended to allow loading shared objects compiled on Linux and dynamically linked to glibc 4 | into native FreeBSD processes for a few use cases that warrant such a hack. Although FreeBSD already has 5 | a very useful Linux compatibility feature, this kind of ad hoc ABI mixing is out of scope for it. 6 | 7 | The implementation consists of const/struct conversions and stubs for functionality not existing in FreeBSD. 8 | It's not particularly robust. Please, don't use this in a security-sensitive context. 9 | 10 | For better stability make sure that your Linux objects: 11 | - do not do direct syscalls (vs using libc syscall wrapper); 12 | - do not poke opaque data structures; 13 | - do not pass libc constants or structs to FreeBSD objects they are linked with. 14 | 15 | Only i386/amd64 binaries are supported. 16 | 17 | ## Dependencies 18 | 19 | FreeBSD, *ruby*. *libepoll-shim*, *libiconv*, *libinotify* will be used if installed. 20 | Additionally, `bin/nv-sglrun` requires *nvidia-driver* and *linux-nvidia-libs*. 21 | 22 | ## Usage 23 | 24 | ``` 25 | % make 26 | % [env SHIM_DEBUG=1] ./bin/ 27 | ``` 28 | -------------------------------------------------------------------------------- /bin/c6-shim-env: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: UTF-8 3 | 4 | if ARGV.length == 0 5 | STDERR.puts "Run application with libc6-shim:\n\s\s[env SHIM_DEBUG=1] #{File.basename($PROGRAM_NAME)} [application args]" 6 | exit(0) 7 | end 8 | 9 | SHIM_LIB64_DIR = File.join(__dir__, '../lib64') 10 | SHIM_LIB32_DIR = File.join(__dir__, '../lib32') 11 | 12 | def libmap(target_dir, libdir_suffix) 13 | 14 | shim_path = File.expand_path(ENV['SHIM_DEBUG'] == '1' ? 'libc6-debug.so' : 'libc6.so', target_dir) 15 | 16 | lmap = { 17 | 'ld-linux.so.2' => shim_path, 18 | 'ld-linux-x86-64.so.2' => shim_path, 19 | 'libc.so.6' => shim_path, 20 | 'libdl.so.2' => shim_path, 21 | 'libm.so.6 ' => shim_path, 22 | 'libpthread.so.0' => shim_path, 23 | 'libresolv.so.2' => shim_path, 24 | 'librt.so.1' => shim_path, 25 | 'libcxxrt.so.1' => (File.expand_path('fakecxxrt.so', target_dir) if ENV['SHIM_FAKECXXRT'] == '1') 26 | } 27 | 28 | if libdir_suffix == '' && File.exist?("/lib/librt.so.1") 29 | lmap['bsd-librt.so.1'] = "/lib/librt.so.1" 30 | else 31 | lmap['bsd-librt.so.1'] = "/usr/lib#{libdir_suffix}/librt.so.1" 32 | end 33 | 34 | lmap.compact.map{|k, v| '%-40s %s' % [k, v]}.join("\n") 35 | end 36 | 37 | ENV['LD_LIBMAP'] = [libmap(SHIM_LIB64_DIR, ''), ENV['LD_LIBMAP'] ].compact.join("\n") 38 | ENV['LD_32_LIBMAP'] = [libmap(SHIM_LIB32_DIR, '32'), ENV['LD_32_LIBMAP']].compact.join("\n") 39 | 40 | exec([ARGV[0]] * 2, *ARGV[1..-1]) 41 | -------------------------------------------------------------------------------- /bin/c6-shim-run-exe: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: UTF-8 3 | 4 | if ARGV.length == 0 5 | STDERR.puts "Launch a Linux executable through libc6-shim:\n\s\s[env SHIM_LINUX_LIB64_DIR=] #{File.basename($PROGRAM_NAME)} [application args]" 6 | exit(1) 7 | end 8 | 9 | launcher_args = [] 10 | while ARGV[0].start_with?('-') 11 | launcher_args << ARGV.shift 12 | end 13 | 14 | target = begin 15 | File.realpath(ARGV[0]) 16 | rescue Errno::ENOENT 17 | STDERR.puts "#{File.expand_path(ARGV[0])} doesn't exist" 18 | exit(1) 19 | end 20 | 21 | target_args = ARGV[1..-1] 22 | 23 | if !(`file '#{target}'` =~ /ELF 64-bit LSB (pie |)executable, x86-64, [^,]+, dynamically linked, interpreter \/lib64\/ld-linux-x86-64\.so\.2/) 24 | STDERR.puts "#{target} is not an executable of expected type" 25 | exit(1) 26 | end 27 | 28 | LIB64_DIR = ENV['SHIM_LINUX_LIB64_DIR'] || '/compat/linux/usr/lib64' 29 | 30 | libmap = <<~LIBMAP 31 | [#{target}] # doesn't work with spaces in the file name 32 | libstdc++.so.6 #{LIB64_DIR}/libstdc++.so.6 33 | libGLU.so.1 #{LIB64_DIR}/libGLU.so.1 34 | libz.so.1 #{LIB64_DIR}/libz.so.1 35 | libbz2.so.1 #{LIB64_DIR}/libbz2.so.1 36 | libuuid.so.1 #{LIB64_DIR}/libuuid.so.1 37 | LIBMAP 38 | 39 | ENV['SHIM_PROC_SELF_EXE'] = target 40 | ENV['LD_LIBMAP'] = [libmap, ENV['LD_LIBMAP']].compact.join("\n") 41 | 42 | if launcher_args.include?('-d') 43 | 44 | checksum = `sha256 -q "#{target}"`.chomp 45 | 46 | debug_target = File.join(File.dirname(target), checksum) 47 | if !File.exist?(debug_target) 48 | headers = `readelf --sections --wide "#{target}"` 49 | 50 | obj = IO.binread(target) 51 | headers.each_line do |line| 52 | if line =~ /(?:.interp|.note.(?:ABI-tag|gnu.build-id))\s+(?:PROGBITS|NOTE)\s+[0-9a-f]+\s+([0-9a-f]+)\s([0-9a-f]+)/ 53 | offset = $1.to_i(16) 54 | size = $2.to_i(16) 55 | str = obj[offset..(offset + size)] 56 | str.gsub!('/lib64/ld-linux-x86-6'.b, "/libexec/ld-elf.so.1\x00".b) 57 | str.gsub!('GNU'.b, "xxx".b) 58 | obj[offset..(offset + size)] = str 59 | end 60 | end 61 | 62 | IO.binwrite("#{debug_target}.temp", obj) 63 | File.chmod(0700, "#{debug_target}.temp") 64 | system('brandelf', '-t', 'FreeBSD', "#{debug_target}.temp") || raise 65 | system('mv', "#{debug_target}.temp", debug_target) || raise 66 | end 67 | 68 | lldb_args = [ 69 | '--one-line', "pro hand -p true -s false SIGUSR1", 70 | '--one-line', "pro hand -p true -s false SIGXCPU", 71 | ] 72 | 73 | system('mount', '-t', 'nullfs', '-o', 'nocover', debug_target, target) || raise 74 | system(File.join(__dir__, 'c6-shim-env'), 'lldb', *lldb_args, target, '--', *target_args) 75 | system('umount', target) 76 | else 77 | exec(File.join(__dir__, 'c6-shim-env'), '/libexec/ld-elf.so.1', target, *target_args) 78 | end 79 | -------------------------------------------------------------------------------- /bin/nv-sglrun: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: UTF-8 3 | 4 | if ARGV.length == 0 5 | STDERR.puts "Substitute Nvidia's Linux OpenGL/Vulkan libraries:\n\s\s[env SHIM_DEBUG=1] #{File.basename($PROGRAM_NAME)} [application args]" 6 | exit(1) 7 | end 8 | 9 | `sysctl hw.nvidia.version` =~ /^hw.nvidia.version: NVIDIA UNIX x86_64 Kernel Module ([\d\.+]+)/ 10 | DRIVER_VERSION = $1 11 | 12 | raise "No NVIDIA kernel module found" if not DRIVER_VERSION 13 | 14 | NVIDIA_LIB64_DIR = ENV['NVIDIA_LIB64_DIR'] || '/compat/linux/usr/lib64' 15 | NVIDIA_LIB32_DIR = ENV['NVIDIA_LIB32_DIR'] || '/compat/linux/usr/lib' 16 | 17 | def libmap(target_dir) 18 | 19 | libglx_path = File.join(target_dir, "libGLX_nvidia.so.#{DRIVER_VERSION}") 20 | 21 | lmap = { 22 | 'libgl_nvidia' => libglx_path 23 | } 24 | 25 | for path in Dir[File.join(target_dir, 'lib{cuda.so*,nvcuvid.so*,nvidia-*.so*,{EGL,GLX}_nvidia*.so*}')] 26 | lmap[File.basename(path)] = path 27 | end 28 | 29 | lmap.map{|k, v| '%-40s %s' % [k, v]}.sort.join("\n") 30 | end 31 | 32 | ENV['LD_LIBMAP'] = [libmap(NVIDIA_LIB64_DIR), ENV['LD_LIBMAP'] ].compact.join("\n") 33 | ENV['LD_32_LIBMAP'] = [libmap(NVIDIA_LIB32_DIR), ENV['LD_32_LIBMAP']].compact.join("\n") 34 | 35 | ENV['__GLX_VENDOR_LIBRARY_NAME'] = 'nvidia' 36 | ENV['OCL_ICD_VENDORS'] = File.join(__dir__, '../icds/ocl') 37 | ENV['VK_ICD_FILENAMES'] = File.join(__dir__, '../icds/vk/nv.json') 38 | 39 | exec(File.join(__dir__, 'c6-shim-env'), *ARGV) 40 | -------------------------------------------------------------------------------- /icds/ocl/nv.icd: -------------------------------------------------------------------------------- 1 | libnvidia-opencl.so.1 2 | -------------------------------------------------------------------------------- /icds/vk/nv.json: -------------------------------------------------------------------------------- 1 | { 2 | "file_format_version" : "1.0.0", 3 | "ICD": { 4 | "library_path": "libgl_nvidia", 5 | "api_version" : "0.0.0" 6 | } 7 | } 8 | -------------------------------------------------------------------------------- /src/fakecxxrt.map: -------------------------------------------------------------------------------- 1 | # this is just a dummy libcxxrt.so.1 2 | # to assist with libcxxrt.so.1 -> libstdc++.so (libsupc++) substitution 3 | 4 | CXXRT_1.0 {}; 5 | 6 | CXXABI_1.3 {}; 7 | CXXABI_1.3.1 {}; 8 | CXXABI_1.3.5 {}; 9 | CXXABI_1.3.6 {}; 10 | CXXABI_1.3.9 {}; 11 | 12 | GLIBCXX_3.4 {}; 13 | GLIBCXX_3.4.9 {}; 14 | GLIBCXX_3.4.20 {}; 15 | GLIBCXX_3.4.22 {}; 16 | -------------------------------------------------------------------------------- /src/futexes.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /* 6 | * Just enough stuff to keep Steam from complaining. 7 | */ 8 | 9 | #ifdef __i386__ 10 | #define FUTEX_OFFSET -20 11 | #endif 12 | 13 | #ifdef __x86_64__ 14 | #define FUTEX_OFFSET -32 15 | #endif 16 | 17 | struct robust_list_head { 18 | void* list; 19 | long futex_offset; 20 | void* list_op_pending; 21 | }; 22 | 23 | struct fake_pthread { 24 | void* robust_prev; 25 | struct robust_list_head list; 26 | }; 27 | 28 | static __thread struct fake_pthread pthread = {}; 29 | 30 | long get_robust_list(int pid, struct robust_list_head** list_head, size_t* struct_len) { 31 | 32 | if (!(list_head && struct_len)) 33 | return -1; 34 | 35 | assert(pid == 0); 36 | 37 | pthread.robust_prev = &pthread.list; 38 | pthread.list.list = &pthread.list; 39 | pthread.list.futex_offset = FUTEX_OFFSET; 40 | pthread.list.list_op_pending = NULL; 41 | 42 | *list_head = &pthread.list; 43 | *struct_len = sizeof(struct robust_list_head); 44 | 45 | return 0; 46 | } 47 | -------------------------------------------------------------------------------- /src/globals.c: -------------------------------------------------------------------------------- 1 | #include "shim.h" 2 | 3 | FILE* shim_stdin = NULL; 4 | FILE* shim_stdout = NULL; 5 | FILE* shim_stderr = NULL; 6 | 7 | SHIM_EXPORT(stdin); 8 | SHIM_EXPORT(stdout); 9 | SHIM_EXPORT(stderr); 10 | 11 | #ifdef __i386__ 12 | 13 | FILE* shim__IO_stdin_ = NULL; 14 | FILE* shim__IO_stdout_ = NULL; 15 | FILE* shim__IO_stderr_ = NULL; 16 | 17 | SHIM_EXPORT(_IO_stdin_); 18 | SHIM_EXPORT(_IO_stdout_); 19 | SHIM_EXPORT(_IO_stderr_); 20 | 21 | #endif 22 | 23 | FILE* shim__IO_2_1_stdin_ = NULL; 24 | FILE* shim__IO_2_1_stdout_ = NULL; 25 | FILE* shim__IO_2_1_stderr_ = NULL; 26 | 27 | SHIM_EXPORT(_IO_2_1_stdin_); 28 | SHIM_EXPORT(_IO_2_1_stdout_); 29 | SHIM_EXPORT(_IO_2_1_stderr_); 30 | 31 | char** shim_environ = NULL; 32 | 33 | SHIM_EXPORT(environ); 34 | 35 | char** shim___environ = NULL; 36 | char** shim__environ = NULL; 37 | 38 | SHIM_EXPORT(__environ); 39 | SHIM_EXPORT(_environ); 40 | 41 | char* shim___progname = "???"; 42 | char* shim___progname_full = "???"; 43 | char* shim_program_invocation_name = "???"; 44 | char* shim_program_invocation_short_name = "???"; 45 | 46 | SHIM_EXPORT(__progname); 47 | SHIM_EXPORT(__progname_full); 48 | SHIM_EXPORT(program_invocation_name); 49 | SHIM_EXPORT(program_invocation_short_name); 50 | 51 | char* shim_optarg = NULL; 52 | int shim_optind = 1; 53 | int shim_optopt = 0; 54 | int shim_opterr = 1; 55 | 56 | SHIM_EXPORT(optarg); 57 | SHIM_EXPORT(optind); 58 | SHIM_EXPORT(optopt); 59 | SHIM_EXPORT(opterr); 60 | 61 | #include 62 | 63 | const struct in6_addr shim_in6addr_any = IN6ADDR_ANY_INIT; 64 | const struct in6_addr shim_in6addr_loopback = IN6ADDR_LOOPBACK_INIT; 65 | 66 | SHIM_EXPORT(in6addr_any); 67 | SHIM_EXPORT(in6addr_loopback); 68 | 69 | char shim___libc_single_threaded = 0; 70 | 71 | SHIM_EXPORT(__libc_single_threaded); 72 | -------------------------------------------------------------------------------- /src/libc/ctype.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "../shim.h" 6 | #include "locale.h" 7 | 8 | // TODO: __ctype32_b, __ctype32_tolower, __ctype32_toupper? 9 | 10 | static uint16_t shim_ctype_b_table[384] = { 11 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 12 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 13 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 14 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 15 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 16 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 17 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 18 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 19 | 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x2003, 0x2002, 0x2002, 0x2002, 0x2002, 0x0002, 0x0002, 20 | 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 0x0002, 21 | 0x6001, 0xc004, 0xc004, 0xc004, 0xc004, 0xc004, 0xc004, 0xc004, 0xc004, 0xc004, 0xc004, 0xc004, 0xc004, 0xc004, 0xc004, 0xc004, 22 | 0xd808, 0xd808, 0xd808, 0xd808, 0xd808, 0xd808, 0xd808, 0xd808, 0xd808, 0xd808, 0xc004, 0xc004, 0xc004, 0xc004, 0xc004, 0xc004, 23 | 0xc004, 0xd508, 0xd508, 0xd508, 0xd508, 0xd508, 0xd508, 0xc508, 0xc508, 0xc508, 0xc508, 0xc508, 0xc508, 0xc508, 0xc508, 0xc508, 24 | 0xc508, 0xc508, 0xc508, 0xc508, 0xc508, 0xc508, 0xc508, 0xc508, 0xc508, 0xc508, 0xc508, 0xc004, 0xc004, 0xc004, 0xc004, 0xc004, 25 | 0xc004, 0xd608, 0xd608, 0xd608, 0xd608, 0xd608, 0xd608, 0xc608, 0xc608, 0xc608, 0xc608, 0xc608, 0xc608, 0xc608, 0xc608, 0xc608, 26 | 0xc608, 0xc608, 0xc608, 0xc608, 0xc608, 0xc608, 0xc608, 0xc608, 0xc608, 0xc608, 0xc608, 0xc004, 0xc004, 0xc004, 0xc004, 0x0002, 27 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 28 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 29 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 30 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 31 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 32 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 33 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 34 | 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 35 | }; 36 | 37 | const uint16_t* shim___ctype_b = &shim_ctype_b_table[128]; 38 | 39 | SHIM_EXPORT(__ctype_b); 40 | 41 | static const unsigned short** shim___ctype_b_loc_impl() { 42 | return &shim___ctype_b; 43 | } 44 | 45 | static size_t shim___ctype_get_mb_cur_max_impl() { 46 | return MB_CUR_MAX; 47 | } 48 | 49 | static int32_t shim_ctype_tolower_table[384]; 50 | static int32_t shim_ctype_toupper_table[384]; 51 | 52 | __attribute__((constructor)) 53 | static void ctype_init() { 54 | // TODO: set locale to C here? 55 | for (int i = 0; i < 384; i++) { 56 | shim_ctype_tolower_table[i] = (i == 127 ? -1 : tolower((uint8_t)(i + 128))); 57 | shim_ctype_toupper_table[i] = (i == 127 ? -1 : toupper((uint8_t)(i + 128))); 58 | } 59 | } 60 | 61 | int32_t* shim___ctype_tolower = &shim_ctype_tolower_table[128]; 62 | int32_t* shim___ctype_toupper = &shim_ctype_toupper_table[128]; 63 | 64 | SHIM_EXPORT(__ctype_tolower); 65 | SHIM_EXPORT(__ctype_toupper); 66 | 67 | static int32_t** shim___ctype_tolower_loc_impl() { 68 | return &shim___ctype_tolower; 69 | } 70 | 71 | static int32_t** shim___ctype_toupper_loc_impl() { 72 | return &shim___ctype_toupper; 73 | } 74 | 75 | SHIM_WRAP(__ctype_b_loc); 76 | SHIM_WRAP(__ctype_get_mb_cur_max); 77 | SHIM_WRAP(__ctype_tolower_loc); 78 | SHIM_WRAP(__ctype_toupper_loc); 79 | 80 | static int shim_isalnum_l_impl(int c, linux_locale_t loc) { 81 | return isalnum_l(c, loc->native_locale); 82 | } 83 | 84 | static int shim_isalpha_l_impl(int c, linux_locale_t loc) { 85 | return isalpha_l(c, loc->native_locale); 86 | } 87 | 88 | static int shim_isblank_l_impl(int c, linux_locale_t loc) { 89 | return isblank_l(c, loc->native_locale); 90 | } 91 | 92 | static int shim_iscntrl_l_impl(int c, linux_locale_t loc) { 93 | return iscntrl_l(c, loc->native_locale); 94 | } 95 | 96 | static int shim_isdigit_l_impl(int c, linux_locale_t loc) { 97 | return isdigit_l(c, loc->native_locale); 98 | } 99 | 100 | static int shim_isgraph_l_impl(int c, linux_locale_t loc) { 101 | return isgraph_l(c, loc->native_locale); 102 | } 103 | 104 | static int shim_islower_l_impl(int c, linux_locale_t loc) { 105 | return islower_l(c, loc->native_locale); 106 | } 107 | 108 | static int shim_isprint_l_impl(int c, linux_locale_t loc) { 109 | return isprint_l(c, loc->native_locale); 110 | } 111 | 112 | static int shim_ispunct_l_impl(int c, linux_locale_t loc) { 113 | return ispunct_l(c, loc->native_locale); 114 | } 115 | 116 | static int shim_isspace_l_impl(int c, linux_locale_t loc) { 117 | return isspace_l(c, loc->native_locale); 118 | } 119 | 120 | static int shim_isupper_l_impl(int c, linux_locale_t loc) { 121 | return isupper_l(c, loc->native_locale); 122 | } 123 | 124 | static int shim_isxdigit_l_impl(int c, linux_locale_t loc) { 125 | return isxdigit_l(c, loc->native_locale); 126 | } 127 | 128 | SHIM_WRAP(isalnum_l); 129 | SHIM_WRAP(isalpha_l); 130 | SHIM_WRAP(isblank_l); 131 | SHIM_WRAP(iscntrl_l); 132 | SHIM_WRAP(isdigit_l); 133 | SHIM_WRAP(isgraph_l); 134 | SHIM_WRAP(islower_l); 135 | SHIM_WRAP(isprint_l); 136 | SHIM_WRAP(ispunct_l); 137 | SHIM_WRAP(isspace_l); 138 | SHIM_WRAP(isupper_l); 139 | SHIM_WRAP(isxdigit_l); 140 | 141 | static int shim_tolower_l_impl(int c, linux_locale_t loc) { 142 | return tolower_l(c, loc->native_locale); 143 | } 144 | 145 | static int shim_toupper_l_impl(int c, linux_locale_t loc) { 146 | return toupper_l(c, loc->native_locale); 147 | } 148 | 149 | SHIM_WRAP(tolower_l); 150 | SHIM_WRAP(toupper_l); 151 | -------------------------------------------------------------------------------- /src/libc/dirent.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "../shim.h" 10 | #include "dirent.h" 11 | 12 | struct shim_directory { 13 | DIR* dir; 14 | SLIST_HEAD(shim_dir_entry_list, shim_dir_entry) head; 15 | pthread_mutex_t mutex; 16 | }; 17 | 18 | struct shim_dir_entry { 19 | SLIST_ENTRY(shim_dir_entry) entries; 20 | struct linux_dirent* linux_entry; 21 | struct linux_dirent64* linux_entry64; 22 | }; 23 | 24 | static struct shim_directory* create_shim_dir(DIR* dir) { 25 | 26 | struct shim_directory* shim_dir = malloc(sizeof(struct shim_directory)); 27 | 28 | shim_dir->dir = dir; 29 | 30 | SLIST_INIT(&shim_dir->head); 31 | 32 | int err = pthread_mutex_init(&shim_dir->mutex, NULL); 33 | assert(err == 0); 34 | 35 | return shim_dir; 36 | } 37 | 38 | static void destroy_shim_dir(struct shim_directory* shim_dir) { 39 | 40 | pthread_mutex_lock(&shim_dir->mutex); 41 | 42 | struct shim_dir_entry *shim_entry, *temp; 43 | SLIST_FOREACH_SAFE(shim_entry, &shim_dir->head, entries, temp) { 44 | 45 | SLIST_REMOVE(&shim_dir->head, shim_entry, shim_dir_entry, entries); 46 | 47 | if (shim_entry->linux_entry != NULL) { 48 | free(shim_entry->linux_entry); 49 | } 50 | 51 | if (shim_entry->linux_entry64 != NULL) { 52 | free(shim_entry->linux_entry64); 53 | } 54 | 55 | free(shim_entry); 56 | } 57 | 58 | pthread_mutex_unlock(&shim_dir->mutex); 59 | 60 | int err = pthread_mutex_destroy(&shim_dir->mutex); 61 | assert(err == 0); 62 | 63 | free(shim_dir); 64 | } 65 | 66 | static void copy_direntry(linux_dirent* dst, const struct dirent* src) { 67 | 68 | dst->d_ino = src->d_ino; 69 | dst->d_off = src->d_off; 70 | dst->d_reclen = src->d_reclen; 71 | dst->d_type = src->d_type; 72 | 73 | strlcpy(dst->d_name, src->d_name, sizeof(dst->d_name)); 74 | } 75 | 76 | static void copy_direntry64(linux_dirent64* dst, const struct dirent* src) { 77 | 78 | dst->d_ino = src->d_ino; 79 | dst->d_off = src->d_off; 80 | dst->d_reclen = src->d_reclen; 81 | dst->d_type = src->d_type; 82 | 83 | strlcpy(dst->d_name, src->d_name, sizeof(dst->d_name)); 84 | } 85 | 86 | static struct linux_dirent* insert_entry(struct shim_directory* shim_dir, struct dirent* entry) { 87 | 88 | struct linux_dirent* linux_entry = malloc(sizeof(linux_dirent)); 89 | copy_direntry(linux_entry, entry); 90 | 91 | struct shim_dir_entry* shim_entry = malloc(sizeof(struct shim_dir_entry)); 92 | shim_entry->linux_entry = linux_entry; 93 | shim_entry->linux_entry64 = NULL; 94 | 95 | pthread_mutex_lock(&shim_dir->mutex); 96 | 97 | SLIST_INSERT_HEAD(&shim_dir->head, shim_entry, entries); 98 | 99 | pthread_mutex_unlock(&shim_dir->mutex); 100 | 101 | return linux_entry; 102 | } 103 | 104 | static struct linux_dirent64* insert_entry64(struct shim_directory* shim_dir, struct dirent* entry) { 105 | 106 | struct linux_dirent64* linux_entry64 = malloc(sizeof(linux_dirent64)); 107 | copy_direntry64(linux_entry64, entry); 108 | 109 | struct shim_dir_entry* shim_entry = malloc(sizeof(struct shim_dir_entry)); 110 | shim_entry->linux_entry = NULL; 111 | shim_entry->linux_entry64 = linux_entry64; 112 | 113 | pthread_mutex_lock(&shim_dir->mutex); 114 | 115 | SLIST_INSERT_HEAD(&shim_dir->head, shim_entry, entries); 116 | 117 | pthread_mutex_unlock(&shim_dir->mutex); 118 | 119 | return linux_entry64; 120 | } 121 | 122 | static struct shim_directory* shim_fdopendir_impl(int fd) { 123 | DIR* dir = fdopendir(fd); 124 | return dir != NULL ? create_shim_dir(dir) : NULL; 125 | } 126 | 127 | static struct shim_directory* shim_opendir_impl(const char* filename) { 128 | 129 | // some code in Unity (?) assumes this dir always exists 130 | if (strcmp(filename, "/sys/devices/") == 0) { 131 | return create_shim_dir(opendir("/libexec")); 132 | } 133 | 134 | DIR* dir = opendir(filename); 135 | return dir != NULL ? create_shim_dir(dir) : NULL; 136 | } 137 | 138 | static struct linux_dirent* shim_readdir_impl(struct shim_directory* shim_dir) { 139 | struct dirent* entry = readdir(shim_dir->dir); 140 | return entry != NULL ? insert_entry(shim_dir, entry) : NULL; 141 | } 142 | 143 | static struct linux_dirent64* shim_readdir64_impl(struct shim_directory* shim_dir) { 144 | struct dirent* entry = readdir(shim_dir->dir); 145 | return entry != NULL ? insert_entry64(shim_dir, entry) : NULL; 146 | } 147 | 148 | static int shim_closedir_impl(struct shim_directory* shim_dir) { 149 | int err = closedir(shim_dir->dir); 150 | destroy_shim_dir(shim_dir); 151 | return err; 152 | } 153 | 154 | static int shim_dirfd_impl(struct shim_directory* shim_dir) { 155 | return dirfd(shim_dir->dir); 156 | } 157 | 158 | static void shim_rewinddir_impl(struct shim_directory* shim_dir) { 159 | rewinddir(shim_dir->dir); 160 | } 161 | 162 | static void shim_seekdir_impl(struct shim_directory* shim_dir, long loc) { 163 | seekdir(shim_dir->dir, loc); 164 | } 165 | 166 | static long shim_telldir_impl(struct shim_directory* shim_dir) { 167 | return telldir(shim_dir->dir); 168 | } 169 | 170 | static int shim_alphasort_impl(const struct linux_dirent** d1, const struct linux_dirent** d2) { 171 | return strcoll((*d1)->d_name, (*d2)->d_name); 172 | } 173 | 174 | static int shim_alphasort64_impl(const struct linux_dirent64** d1, const struct linux_dirent64** d2) { 175 | return strcoll((*d1)->d_name, (*d2)->d_name); 176 | } 177 | 178 | static int shim_readdir_r_impl(struct shim_directory* shim_dir, struct linux_dirent* linux_entry, struct linux_dirent** result) { 179 | 180 | struct dirent* e = readdir(shim_dir->dir); 181 | if (e != NULL) { 182 | copy_direntry(linux_entry, e); 183 | *result = linux_entry; 184 | } else { 185 | *result = NULL; 186 | } 187 | 188 | return 0; 189 | } 190 | 191 | static int shim_readdir64_r_impl(struct shim_directory* shim_dir, struct linux_dirent64* linux_entry, struct linux_dirent64** result) { 192 | 193 | struct dirent* e = readdir(shim_dir->dir); 194 | if (e != NULL) { 195 | copy_direntry64(linux_entry, e); 196 | *result = linux_entry; 197 | } else { 198 | *result = NULL; 199 | } 200 | 201 | return 0; 202 | } 203 | 204 | static int shim_scandir_impl( 205 | const char* dirname, 206 | linux_dirent*** linux_namelist, 207 | int (*select)(const struct linux_dirent*), 208 | int (*compar)(const struct linux_dirent**, const struct linux_dirent**) 209 | ) { 210 | 211 | DIR* dir = opendir(dirname); 212 | if (dir == NULL) { 213 | return -1; 214 | } 215 | 216 | struct { linux_dirent** arr; int len; } out; 217 | 218 | out.len = 32; 219 | out.arr = malloc(sizeof(linux_dirent*) * out.len); 220 | 221 | int nitems = 0; 222 | 223 | struct dirent* e; 224 | while ((e = readdir(dir)) != NULL) { 225 | 226 | linux_dirent* linux_entry = malloc(sizeof(linux_dirent)); 227 | copy_direntry(linux_entry, e); 228 | 229 | if (select != NULL ? select(linux_entry) : 1) { 230 | 231 | if (nitems >= out.len) { 232 | out.len = out.len * 2; 233 | out.arr = realloc(out.arr, sizeof(linux_dirent*) * out.len); 234 | } 235 | 236 | out.arr[nitems] = linux_entry; 237 | nitems++; 238 | 239 | } else { 240 | free(linux_entry); 241 | } 242 | } 243 | 244 | closedir(dir); 245 | 246 | if (nitems > 0 && compar != NULL) { 247 | qsort(out.arr, nitems, sizeof(linux_dirent*), (int (*)(const void*, const void*))compar); 248 | } 249 | 250 | *linux_namelist = out.arr; 251 | 252 | return nitems; 253 | } 254 | 255 | //TODO: do something about code duplication? 256 | static int shim_scandir64_impl( 257 | const char* dirname, 258 | linux_dirent64*** linux_namelist, 259 | int (*select)(const struct linux_dirent64*), 260 | int (*compar)(const struct linux_dirent64**, const struct linux_dirent64**) 261 | ) { 262 | 263 | DIR* dir = opendir(dirname); 264 | if (dir == NULL) { 265 | return -1; 266 | } 267 | 268 | struct { linux_dirent64** arr; int len; } out; 269 | 270 | out.len = 32; 271 | out.arr = malloc(sizeof(linux_dirent64*) * out.len); 272 | 273 | int nitems = 0; 274 | 275 | struct dirent* e; 276 | while ((e = readdir(dir)) != NULL) { 277 | 278 | linux_dirent64* linux_entry = malloc(sizeof(linux_dirent64)); 279 | copy_direntry64(linux_entry, e); 280 | 281 | if (select != NULL ? select(linux_entry) : 1) { 282 | 283 | if (nitems >= out.len) { 284 | out.len = out.len * 2; 285 | out.arr = realloc(out.arr, sizeof(linux_dirent64*) * out.len); 286 | } 287 | 288 | out.arr[nitems] = linux_entry; 289 | nitems++; 290 | 291 | } else { 292 | free(linux_entry); 293 | } 294 | } 295 | 296 | closedir(dir); 297 | 298 | if (nitems > 0 && compar != NULL) { 299 | qsort(out.arr, nitems, sizeof(linux_dirent64*), (int (*)(const void*, const void*))compar); 300 | } 301 | 302 | *linux_namelist = out.arr; 303 | 304 | return nitems; 305 | } 306 | 307 | typedef struct shim_directory linux_DIR; 308 | 309 | SHIM_WRAP(alphasort); 310 | SHIM_WRAP(alphasort64); 311 | SHIM_WRAP(closedir); 312 | SHIM_WRAP(dirfd); 313 | SHIM_WRAP(fdopendir); 314 | SHIM_WRAP(opendir); 315 | SHIM_WRAP(readdir); 316 | SHIM_WRAP(readdir64); 317 | SHIM_WRAP(readdir_r); 318 | SHIM_WRAP(readdir64_r); 319 | SHIM_WRAP(rewinddir); 320 | SHIM_WRAP(scandir); 321 | SHIM_WRAP(scandir64); 322 | SHIM_WRAP(seekdir); 323 | SHIM_WRAP(telldir); 324 | -------------------------------------------------------------------------------- /src/libc/dirent.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifdef __i386__ 4 | 5 | struct linux_dirent { 6 | uint32_t d_ino; 7 | uint32_t d_off; //TODO: lseek? 8 | uint16_t d_reclen; 9 | uint8_t d_type; 10 | char d_name[256]; 11 | }; 12 | 13 | struct linux_dirent64 { 14 | uint64_t d_ino; 15 | uint64_t d_off; 16 | uint16_t d_reclen; 17 | uint8_t d_type; 18 | char d_name[256]; 19 | }; 20 | 21 | #endif 22 | 23 | #ifdef __x86_64__ 24 | 25 | struct linux_dirent { 26 | uint64_t d_ino; 27 | uint64_t d_off; 28 | uint16_t d_reclen; 29 | uint8_t d_type; 30 | char d_name[256]; 31 | }; 32 | 33 | struct linux_dirent64 { 34 | uint64_t d_ino; 35 | uint64_t d_off; 36 | uint16_t d_reclen; 37 | uint8_t d_type; 38 | char d_name[256]; 39 | }; 40 | 41 | #endif 42 | 43 | typedef struct linux_dirent linux_dirent; 44 | typedef struct linux_dirent64 linux_dirent64; 45 | -------------------------------------------------------------------------------- /src/libc/dlfcn.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "../shim.h" 8 | 9 | #define LINUX_RTLD_LOCAL RTLD_LOCAL 10 | #define LINUX_RTLD_LAZY RTLD_LAZY 11 | #define LINUX_RTLD_NOW RTLD_NOW 12 | #define LINUX_RTLD_NOLOAD 0x4 13 | #define LINUX_RTLD_GLOBAL RTLD_GLOBAL 14 | #define LINUX_RTLD_NODELETE RTLD_NODELETE 15 | #define LINUX_RTLD_DEEPBIND 0x00008 16 | 17 | #define KNOWN_LINUX_DLOPEN_MODE_FLAGS ( \ 18 | LINUX_RTLD_LOCAL | \ 19 | LINUX_RTLD_LAZY | \ 20 | LINUX_RTLD_NOW | \ 21 | LINUX_RTLD_NOLOAD | \ 22 | LINUX_RTLD_GLOBAL | \ 23 | LINUX_RTLD_NODELETE | \ 24 | LINUX_RTLD_DEEPBIND \ 25 | ) 26 | 27 | #define LINUX_RTLD_DI_LINKMAP 2 28 | 29 | static int shim_dladdr1_impl(void* address, Dl_info* info, void** extra_info, int extra_info_type) { 30 | 31 | int dladdr_err = dladdr(address, info); 32 | if (dladdr_err != 0) { 33 | 34 | LOG("%s: \"%s\", %p, \"%s\", %p", __func__, info->dli_fname, info->dli_fbase, info->dli_sname, info->dli_saddr); 35 | 36 | switch (extra_info_type) { 37 | case LINUX_RTLD_DI_LINKMAP: 38 | 39 | assert(info->dli_fname != NULL); 40 | 41 | void* handle = dlopen(info->dli_fname, RTLD_NOLOAD); 42 | if (handle != NULL) { 43 | int dlinfo_err = dlinfo(handle, RTLD_DI_LINKMAP, extra_info); 44 | dlclose(handle); // ? 45 | if (dlinfo_err != 0) { 46 | return 0; 47 | } 48 | } else { 49 | *extra_info = NULL; // ? 50 | } 51 | 52 | break; 53 | 54 | default: 55 | assert(0); 56 | } 57 | } 58 | 59 | return dladdr_err; 60 | } 61 | 62 | static void* shim_dlopen_impl(const char* path, int linux_mode) { 63 | 64 | assert((linux_mode & KNOWN_LINUX_DLOPEN_MODE_FLAGS) == linux_mode); 65 | 66 | int mode = linux_mode & ~(LINUX_RTLD_NOLOAD | LINUX_RTLD_DEEPBIND); 67 | 68 | if (linux_mode & LINUX_RTLD_NOLOAD) { 69 | mode |= RTLD_NOLOAD; 70 | } 71 | 72 | if (linux_mode & LINUX_RTLD_DEEPBIND) { 73 | mode |= RTLD_DEEPBIND; 74 | } 75 | 76 | void* p = dlopen(path, mode); 77 | 78 | #ifdef DEBUG 79 | if (p == NULL) { 80 | LOG("%s: %s", __func__, dlerror()); 81 | } 82 | #endif 83 | 84 | return p; 85 | } 86 | 87 | typedef long int Lmid_t; 88 | 89 | static void* shim_dlmopen_impl(Lmid_t lmid, const char* path, int mode) { 90 | return shim_dlopen_impl(path, mode); 91 | } 92 | 93 | #define GLIBC_RTLD_NEXT ((void*)-1) 94 | #define GLIBC_RTLD_DEFAULT ((void*) 0) 95 | 96 | static void* _shim_dlvsym(void* linux_handle, const char* symbol, const char* version) { 97 | 98 | char buf[100]; 99 | snprintf(buf, sizeof(buf), "shim_%s", symbol); 100 | 101 | void* shim_fn = dlsym(NULL, buf); 102 | if (shim_fn) { 103 | LOG("%s: substituting %s with %s", __func__, symbol, buf); 104 | return shim_fn; 105 | } 106 | 107 | // ? 108 | if (strcmp(symbol, "__malloc_hook") == 0) return NULL; 109 | if (strcmp(symbol, "__realloc_hook") == 0) return NULL; 110 | if (strcmp(symbol, "__free_hook") == 0) return NULL; 111 | if (strcmp(symbol, "__memalign_hook") == 0) return NULL; 112 | 113 | void* handle; 114 | switch ((uintptr_t)linux_handle) { 115 | case (uintptr_t)GLIBC_RTLD_DEFAULT: handle = RTLD_DEFAULT; break; 116 | case (uintptr_t)GLIBC_RTLD_NEXT: handle = RTLD_NEXT; break; 117 | default: 118 | handle = linux_handle; 119 | } 120 | 121 | dlerror(); // reset error 122 | 123 | if (version == NULL) { 124 | return dlsym(handle, symbol); 125 | } else { 126 | return dlvsym(handle, symbol, version); 127 | } 128 | } 129 | 130 | static void* shim_dlsym_impl(void* handle, const char* symbol) { 131 | return _shim_dlvsym(handle, symbol, NULL); 132 | } 133 | 134 | static void* shim_dlvsym_impl(void* handle, const char* symbol, const char* version) { 135 | return _shim_dlvsym(handle, symbol, version); 136 | } 137 | 138 | SHIM_WRAP(dladdr1); 139 | SHIM_WRAP(dlopen); 140 | SHIM_WRAP(dlmopen); 141 | SHIM_WRAP(dlsym); 142 | SHIM_WRAP(dlvsym); 143 | 144 | #define LINUX_RTLD_DI_ORIGIN 6 145 | 146 | static int shim_dlinfo_impl(void* restrict handle, int request, void* restrict p) { 147 | switch (request) { 148 | case LINUX_RTLD_DI_ORIGIN: return dlinfo(handle, RTLD_DI_ORIGIN, p); 149 | default: 150 | UNIMPLEMENTED_ARGS("%p, %d, %p", handle, request, p); 151 | } 152 | } 153 | 154 | SHIM_WRAP(dlinfo); 155 | -------------------------------------------------------------------------------- /src/libc/errno.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../shim.h" 3 | 4 | static int* shim___errno_location_impl() { 5 | return __error(); 6 | } 7 | 8 | SHIM_WRAP(__errno_location); 9 | -------------------------------------------------------------------------------- /src/libc/fcntl.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "../shim.h" 8 | #include "fcntl.h" 9 | 10 | #ifdef __i386__ 11 | 12 | struct linux_flock { 13 | uint16_t l_type; 14 | uint16_t l_whence; 15 | uint32_t l_start; 16 | uint32_t l_len; 17 | uint32_t l_pid; 18 | }; 19 | 20 | #endif 21 | 22 | #ifdef __x86_64__ 23 | 24 | struct linux_flock { 25 | uint16_t l_type; 26 | uint16_t l_whence; 27 | uint64_t l_start; 28 | uint64_t l_len; 29 | uint32_t l_pid; 30 | }; 31 | 32 | #endif 33 | 34 | #define LINUX_F_RDLCK 0 35 | #define LINUX_F_WRLCK 1 36 | #define LINUX_F_UNLCK 2 37 | 38 | static void copy_linux_flock(struct flock* dst, struct linux_flock* src) { 39 | 40 | switch (src->l_type) { 41 | case LINUX_F_RDLCK: dst->l_type = F_RDLCK; break; 42 | case LINUX_F_WRLCK: dst->l_type = F_WRLCK; break; 43 | case LINUX_F_UNLCK: dst->l_type = F_UNLCK; break; 44 | default: 45 | assert(0); 46 | } 47 | 48 | dst->l_whence = src->l_whence; 49 | dst->l_start = src->l_start; 50 | dst->l_len = src->l_len; 51 | dst->l_pid = src->l_pid; 52 | } 53 | 54 | extern int (*libepoll_epoll_shim_fcntl)(int, int, ...); 55 | 56 | #define LINUX_FD_CLOEXEC 1 57 | 58 | static int shim_fcntl_impl(int fd, int cmd, va_list args) { 59 | 60 | if (cmd == LINUX_F_GETFD) { 61 | LOG("%s: cmd = F_GETFD", __func__); 62 | return libepoll_epoll_shim_fcntl(fd, F_GETFD); 63 | } 64 | 65 | if (cmd == LINUX_F_SETFD) { 66 | int arg = va_arg(args, int); 67 | LOG("%s: cmd = F_SETFD, arg = 0x%x", __func__, arg); 68 | return libepoll_epoll_shim_fcntl(fd, F_SETFD, arg & LINUX_FD_CLOEXEC ? FD_CLOEXEC : 0); 69 | } 70 | 71 | if (cmd == LINUX_F_GETFL) { 72 | LOG("%s: cmd = F_GETFL", __func__); 73 | int flags = libepoll_epoll_shim_fcntl(fd, F_GETFL); 74 | LOG("%s: flags -> %#x", __func__, flags); 75 | 76 | assert((flags & ~(LINUX_O_WRONLY | O_RDWR | O_NONBLOCK)) == 0); 77 | 78 | int linux_flags = 79 | (flags & O_WRONLY ? LINUX_O_WRONLY : 0) | 80 | (flags & O_RDWR ? LINUX_O_RDWR : 0) | 81 | (flags & O_NONBLOCK ? LINUX_O_NONBLOCK : 0); 82 | 83 | return linux_flags; 84 | } 85 | 86 | if (cmd == LINUX_F_SETFL) { 87 | int linux_flags = va_arg(args, int); 88 | LOG("%s: cmd = F_SETFL, arg = 0x%x", __func__, linux_flags); 89 | 90 | assert((linux_flags & ~(LINUX_O_RDWR | LINUX_O_NONBLOCK)) == 0); 91 | 92 | int flags = 93 | (linux_flags & LINUX_O_RDWR ? O_RDWR : 0) | 94 | (linux_flags & LINUX_O_NONBLOCK ? O_NONBLOCK : 0); 95 | 96 | return libepoll_epoll_shim_fcntl(fd, F_SETFL, flags); 97 | } 98 | 99 | if (cmd == LINUX_F_GETLK) { 100 | #ifdef DEBUG 101 | void* lock = va_arg(args, void*); 102 | LOG("%s: cmd = F_GETLK, arg = %p", __func__, lock); 103 | #endif 104 | assert(0); 105 | } 106 | 107 | if (cmd == LINUX_F_SETLK) { 108 | 109 | struct linux_flock* linux_lock = va_arg(args, struct linux_flock*); 110 | LOG("%s: cmd = F_SETLK, arg = %p", __func__, linux_lock); 111 | 112 | struct flock lock; 113 | copy_linux_flock(&lock, linux_lock); 114 | 115 | return libepoll_epoll_shim_fcntl(fd, F_SETLK, &lock); 116 | } 117 | 118 | if (cmd == LINUX_F_SETLKW) { 119 | 120 | struct linux_flock* linux_lock = va_arg(args, struct linux_flock*); 121 | LOG("%s: cmd = F_SETLKW, arg = %p", __func__, linux_lock); 122 | 123 | struct flock lock; 124 | copy_linux_flock(&lock, linux_lock); 125 | 126 | return libepoll_epoll_shim_fcntl(fd, F_SETLKW, &lock); 127 | } 128 | 129 | if (cmd == LINUX_F_SETOWN) { 130 | #ifdef DEBUG 131 | int pid = va_arg(args, int); 132 | LOG("%s: cmd = F_SETOWN, arg = 0x%x", __func__, pid); 133 | #endif 134 | assert(0); 135 | } 136 | 137 | if (cmd == LINUX_F_GETOWN) { 138 | LOG("%s: cmd = F_GETOWN", __func__); 139 | assert(0); 140 | } 141 | 142 | if (cmd == LINUX_F_ADD_SEALS) { 143 | int flags = va_arg(args, int); 144 | LOG("%s: cmd = LINUX_F_ADD_SEALS, arg = 0x%x", __func__, flags); 145 | return libepoll_epoll_shim_fcntl(fd, F_ADD_SEALS, flags); 146 | } 147 | 148 | UNIMPLEMENTED_ARGS("%d, %d, ...", fd, cmd); 149 | } 150 | 151 | static int shim_fcntl64_impl(int fd, int cmd, va_list args) { 152 | return shim_fcntl_impl(fd, cmd, args); 153 | } 154 | 155 | int shim_open_impl(const char* path, int linux_flags, va_list args) { 156 | 157 | char* p = redirect(path); 158 | if (p == NULL) { 159 | errno = EACCES; 160 | return -1; 161 | } 162 | 163 | assert((linux_flags & KNOWN_LINUX_OPEN_FLAGS) == linux_flags); 164 | 165 | int flags = 0; 166 | 167 | if (linux_flags & LINUX_O_WRONLY) flags |= O_WRONLY; 168 | if (linux_flags & LINUX_O_RDWR) flags |= O_RDWR; 169 | if (linux_flags & LINUX_O_CREAT) flags |= O_CREAT; 170 | if (linux_flags & LINUX_O_EXCL) flags |= O_EXCL; 171 | if (linux_flags & LINUX_O_NOCTTY) flags |= O_NOCTTY; 172 | if (linux_flags & LINUX_O_TRUNC) flags |= O_TRUNC; 173 | if (linux_flags & LINUX_O_APPEND) flags |= O_APPEND; 174 | if (linux_flags & LINUX_O_NONBLOCK) flags |= O_NONBLOCK; 175 | if (linux_flags & LINUX_O_DIRECTORY) flags |= O_DIRECTORY; 176 | if (linux_flags & LINUX_O_CLOEXEC) flags |= O_CLOEXEC; 177 | 178 | if (linux_flags & LINUX_O_TMPFILE) { 179 | //~ fprintf(stderr, "%s: O_TMPFILE\n", __func__); 180 | return -1; // ? 181 | } 182 | 183 | mode_t mode = 0; 184 | 185 | if (flags & O_CREAT) { 186 | mode = va_arg(args, linux_mode_t); 187 | } 188 | 189 | return open(p, flags, mode); 190 | } 191 | 192 | static int shim_open64_impl(const char* path, int linux_flags, va_list args) { 193 | return shim_open_impl(path, linux_flags, args); 194 | } 195 | 196 | static int shim_posix_fallocate64_impl(int fd, linux_off64_t offset, linux_off64_t len) { 197 | return posix_fallocate(fd, offset, len); 198 | } 199 | 200 | SHIM_WRAP(fcntl); 201 | SHIM_WRAP(fcntl64); 202 | SHIM_WRAP(open); 203 | SHIM_WRAP(open64); 204 | SHIM_WRAP(posix_fallocate64); 205 | 206 | static int shim_shm_open_impl(const char* path, int linux_flags, linux_mode_t mode) { 207 | 208 | char buf[PATH_MAX]; 209 | snprintf(buf, sizeof(buf), "/compat/linux/dev/shm%s", path); 210 | 211 | assert((linux_flags & (LINUX_O_RDONLY | LINUX_O_RDWR | LINUX_O_CREAT | LINUX_O_EXCL | LINUX_O_TRUNC)) == linux_flags); 212 | 213 | int flags = 0; 214 | 215 | if (linux_flags & LINUX_O_WRONLY) flags |= O_WRONLY; 216 | if (linux_flags & LINUX_O_RDWR) flags |= O_RDWR; 217 | if (linux_flags & LINUX_O_CREAT) flags |= O_CREAT; 218 | if (linux_flags & LINUX_O_EXCL) flags |= O_EXCL; 219 | if (linux_flags & LINUX_O_TRUNC) flags |= O_TRUNC; 220 | 221 | return open(buf, flags, mode | O_CLOEXEC); 222 | } 223 | 224 | SHIM_WRAP(shm_open); 225 | -------------------------------------------------------------------------------- /src/libc/fcntl.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define LINUX_F_GETFD 1 4 | #define LINUX_F_SETFD 2 5 | #define LINUX_F_GETFL 3 6 | #define LINUX_F_SETFL 4 7 | #define LINUX_F_GETLK 5 8 | #define LINUX_F_SETLK 6 9 | #define LINUX_F_SETLKW 7 10 | #define LINUX_F_SETOWN 8 11 | #define LINUX_F_GETOWN 9 12 | 13 | #define LINUX_F_ADD_SEALS 1033 14 | 15 | #define LINUX_O_RDONLY 0x00000 16 | #define LINUX_O_WRONLY 0x00001 17 | #define LINUX_O_RDWR 0x00002 18 | #define LINUX_O_CREAT 0x00040 19 | #define LINUX_O_EXCL 0x00080 20 | #define LINUX_O_NOCTTY 0x00100 21 | #define LINUX_O_TRUNC 0x00200 22 | #define LINUX_O_APPEND 0x00400 23 | #define LINUX_O_NONBLOCK 0x00800 24 | #define LINUX_O_DIRECTORY 0x10000 25 | #define LINUX_O_CLOEXEC 0x80000 26 | #define LINUX_O_TMPFILE (0x400000 | LINUX_O_DIRECTORY) 27 | 28 | #define KNOWN_LINUX_OPEN_FLAGS ( \ 29 | LINUX_O_RDONLY | \ 30 | LINUX_O_WRONLY | \ 31 | LINUX_O_RDWR | \ 32 | LINUX_O_CREAT | \ 33 | LINUX_O_EXCL | \ 34 | LINUX_O_NOCTTY | \ 35 | LINUX_O_TRUNC | \ 36 | LINUX_O_APPEND | \ 37 | LINUX_O_NONBLOCK | \ 38 | LINUX_O_DIRECTORY | \ 39 | LINUX_O_CLOEXEC | \ 40 | LINUX_O_TMPFILE \ 41 | ) 42 | -------------------------------------------------------------------------------- /src/libc/ftw.c: -------------------------------------------------------------------------------- 1 | #include "../shim.h" 2 | #include "sys/stat.h" 3 | 4 | typedef struct FTW linux_FTW; 5 | 6 | static int shim_ftw_impl(const char* path, int (*fn)(const char*, const struct linux_stat*, int), int maxfds) { 7 | return -1; 8 | } 9 | 10 | static int shim_ftw64_impl(const char* path, int (*fn)(const char*, const linux_stat64*, int), int maxfds) { 11 | return -1; 12 | } 13 | 14 | static int shim_nftw_impl(const char* path, int (*fn)(const char*, const struct linux_stat*, int, linux_FTW*), int maxfds, int flags) { 15 | return -1; 16 | } 17 | 18 | static int shim_nftw64_impl(const char* path, int (*fn)(const char*, const linux_stat64*, int, linux_FTW*), int maxfds, int flags) { 19 | return -1; 20 | } 21 | 22 | SHIM_WRAP(ftw); 23 | SHIM_WRAP(ftw64); 24 | SHIM_WRAP(nftw); 25 | SHIM_WRAP(nftw64); 26 | -------------------------------------------------------------------------------- /src/libc/glob.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../shim.h" 3 | #include "glob.h" 4 | 5 | static int linux_to_native_glob_flags(int linux_flags) { 6 | 7 | assert((linux_flags & ~KNOWN_LINUX_GLOB_FLAGS) == 0); 8 | 9 | int flags = 0; 10 | 11 | if (linux_flags & LINUX_GLOB_ERR) flags |= GLOB_ERR; 12 | if (linux_flags & LINUX_GLOB_MARK) flags |= GLOB_MARK; 13 | if (linux_flags & LINUX_GLOB_NOSORT) flags |= GLOB_NOSORT; 14 | if (linux_flags & LINUX_GLOB_DOOFFS) flags |= GLOB_DOOFFS; 15 | if (linux_flags & LINUX_GLOB_NOCHECK) flags |= GLOB_NOCHECK; 16 | if (linux_flags & LINUX_GLOB_APPEND) flags |= GLOB_APPEND; 17 | if (linux_flags & LINUX_GLOB_NOESCAPE) flags |= GLOB_NOESCAPE; 18 | // LINUX_GLOB_PERIOD 19 | if (linux_flags & LINUX_GLOB_MAGCHAR) flags |= GLOB_MAGCHAR; 20 | if (linux_flags & LINUX_GLOB_ALTDIRFUNC) flags |= GLOB_ALTDIRFUNC; 21 | if (linux_flags & LINUX_GLOB_BRACE) flags |= GLOB_BRACE; 22 | if (linux_flags & LINUX_GLOB_NOMAGIC) flags |= GLOB_NOMAGIC; 23 | if (linux_flags & LINUX_GLOB_TILDE) flags |= GLOB_TILDE; 24 | // LINUX_GLOB_ONLYDIR 25 | // LINUX_GLOB_TILDE_CHECK 26 | 27 | return flags; 28 | } 29 | 30 | static int shim_glob_impl(const char* restrict pattern, int linux_flags, int (*errfunc)(const char*, int), linux_glob_t* restrict pglob) { 31 | 32 | assert((linux_flags & LINUX_GLOB_ALTDIRFUNC) == 0); // not implemented 33 | assert(errfunc == NULL); // ditto 34 | 35 | glob_t out; 36 | out.gl_offs = pglob->gl_offs; 37 | 38 | int err = glob(pattern, linux_to_native_glob_flags(linux_flags), NULL, &out); 39 | 40 | pglob->gl_pathc = out.gl_pathc; 41 | pglob->gl_pathv = out.gl_pathv; 42 | pglob->gl_offs = out.gl_offs; 43 | if (out.gl_flags & GLOB_MAGCHAR) { 44 | pglob->gl_flags = linux_flags | LINUX_GLOB_MAGCHAR; 45 | } else { 46 | pglob->gl_flags = linux_flags & ~LINUX_GLOB_MAGCHAR; 47 | } 48 | 49 | switch (err) { 50 | case 0: return 0; 51 | case GLOB_NOSPACE: return LINUX_GLOB_NOSPACE; 52 | case GLOB_ABORTED: return LINUX_GLOB_ABORTED; 53 | case GLOB_NOMATCH: return LINUX_GLOB_NOMATCH; 54 | default: 55 | PANIC("Unknown glob err value: %d", err); 56 | } 57 | } 58 | 59 | static void shim_globfree_impl(linux_glob_t* pglob) { 60 | glob_t g; 61 | g.gl_pathc = pglob->gl_pathc; 62 | g.gl_pathv = pglob->gl_pathv; 63 | g.gl_matchc = 0; 64 | g.gl_offs = pglob->gl_offs; 65 | g.gl_flags = linux_to_native_glob_flags(pglob->gl_flags); // ? 66 | globfree(&g); 67 | } 68 | 69 | static int shim_glob64_impl(const char* restrict pattern, int linux_flags, int (*errfunc)(const char*, int), linux_glob64_t* restrict pglob) { 70 | return shim_glob_impl(pattern, linux_flags, errfunc, pglob); 71 | } 72 | 73 | static void shim_globfree64_impl(linux_glob64_t* pglob) { 74 | shim_globfree_impl(pglob); 75 | } 76 | 77 | SHIM_WRAP(glob); 78 | SHIM_WRAP(glob64); 79 | SHIM_WRAP(globfree); 80 | SHIM_WRAP(globfree64); 81 | -------------------------------------------------------------------------------- /src/libc/glob.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define LINUX_GLOB_ERR 0x0001 4 | #define LINUX_GLOB_MARK 0x0002 5 | #define LINUX_GLOB_NOSORT 0x0004 6 | #define LINUX_GLOB_DOOFFS 0x0008 7 | #define LINUX_GLOB_NOCHECK 0x0010 8 | #define LINUX_GLOB_APPEND 0x0020 9 | #define LINUX_GLOB_NOESCAPE 0x0040 10 | #define LINUX_GLOB_PERIOD 0x0080 11 | #define LINUX_GLOB_MAGCHAR 0x0100 12 | #define LINUX_GLOB_ALTDIRFUNC 0x0200 13 | #define LINUX_GLOB_BRACE 0x0400 14 | #define LINUX_GLOB_NOMAGIC 0x0800 15 | #define LINUX_GLOB_TILDE 0x1000 16 | #define LINUX_GLOB_ONLYDIR 0x2000 17 | #define LINUX_GLOB_TILDE_CHECK 0x4000 18 | 19 | #define KNOWN_LINUX_GLOB_FLAGS ( \ 20 | LINUX_GLOB_ERR | \ 21 | LINUX_GLOB_MARK | \ 22 | LINUX_GLOB_NOSORT | \ 23 | LINUX_GLOB_DOOFFS | \ 24 | LINUX_GLOB_NOCHECK | \ 25 | LINUX_GLOB_APPEND | \ 26 | LINUX_GLOB_NOESCAPE | \ 27 | /*LINUX_GLOB_PERIOD*/ 0 | \ 28 | LINUX_GLOB_MAGCHAR | \ 29 | LINUX_GLOB_ALTDIRFUNC | \ 30 | LINUX_GLOB_BRACE | \ 31 | LINUX_GLOB_NOMAGIC | \ 32 | LINUX_GLOB_TILDE | \ 33 | /*LINUX_GLOB_ONLYDIR*/ 0 | \ 34 | /*LINUX_GLOB_TILDE_CHECK*/ 0 \ 35 | ) 36 | 37 | #define LINUX_GLOB_NOSPACE 1 38 | #define LINUX_GLOB_ABORTED 2 39 | #define LINUX_GLOB_NOMATCH 3 40 | 41 | struct shim_glob { 42 | size_t gl_pathc; 43 | char** gl_pathv; 44 | size_t gl_offs; 45 | int gl_flags; 46 | }; 47 | 48 | typedef struct shim_glob linux_glob_t; 49 | typedef struct shim_glob linux_glob64_t; 50 | -------------------------------------------------------------------------------- /src/libc/iconv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "../shim.h" 5 | 6 | static iconv_t (*libiconv_iconv_open) (const char*, const char*); 7 | static int (*libiconv_iconv_close)(iconv_t); 8 | static size_t (*libiconv_iconv) (iconv_t, char** restrict, size_t* restrict, char** restrict, size_t* restrict); 9 | 10 | __attribute__((constructor)) 11 | static void init() { 12 | void* libiconv = dlopen("libiconv.so.2", RTLD_LAZY); 13 | if (libiconv != NULL) { 14 | libiconv_iconv_open = dlsym(libiconv, "libiconv_open"); assert(libiconv_iconv_open != NULL); 15 | libiconv_iconv_close = dlsym(libiconv, "libiconv_close"); assert(libiconv_iconv_close != NULL); 16 | libiconv_iconv = dlsym(libiconv, "libiconv"); assert(libiconv_iconv != NULL); 17 | } else { 18 | Link_map* link_map = NULL; 19 | 20 | int err = dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &link_map); 21 | assert(err == 0); 22 | 23 | fprintf(stderr, "%s: unable to load libiconv.so.2 (%s)\n", link_map->l_name, dlerror()); 24 | 25 | libiconv_iconv_open = iconv_open; 26 | libiconv_iconv_close = iconv_close; 27 | libiconv_iconv = iconv; 28 | } 29 | } 30 | 31 | static iconv_t shim_iconv_open_impl(const char* dstname, const char* srcname) { 32 | return libiconv_iconv_open(dstname, srcname); 33 | } 34 | 35 | SHIM_WRAP(iconv_open); 36 | 37 | static int shim_iconv_close_impl(iconv_t cd) { 38 | return libiconv_iconv_close(cd); 39 | } 40 | 41 | SHIM_WRAP(iconv_close); 42 | 43 | static size_t shim_iconv_impl(iconv_t cd, char** restrict src, size_t* restrict srcleft, char** restrict dst, size_t* restrict dstleft) { 44 | return libiconv_iconv(cd, src, srcleft, dst, dstleft); 45 | } 46 | 47 | SHIM_WRAP(iconv); 48 | -------------------------------------------------------------------------------- /src/libc/ifaddrs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "sys/socket.h" 8 | #include "../shim.h" 9 | 10 | typedef struct linux_ifaddrs linux_ifaddrs; 11 | 12 | struct linux_ifaddrs { 13 | linux_ifaddrs* ifa_next; 14 | char* ifa_name; 15 | unsigned int ifa_flags; 16 | linux_sockaddr* ifa_addr; 17 | linux_sockaddr* ifa_netmask; 18 | linux_sockaddr* ifa_dstaddr; 19 | void* ifa_data; 20 | }; 21 | 22 | struct linux_sockaddr_ll { 23 | unsigned short sll_family; 24 | unsigned short sll_protocol; 25 | int sll_ifindex; 26 | unsigned short sll_hatype; 27 | unsigned char sll_pkttype; 28 | unsigned char sll_halen; 29 | unsigned char sll_addr[8]; 30 | }; 31 | 32 | typedef struct linux_sockaddr_ll linux_sockaddr_ll; 33 | 34 | static void native_to_linux_sockaddr_dl(struct linux_sockaddr_ll* dest, const struct sockaddr_dl* src) { 35 | dest->sll_family = LINUX_AF_PACKET; 36 | dest->sll_protocol = 0; // ? 37 | dest->sll_ifindex = src->sdl_index; 38 | dest->sll_hatype = 0; 39 | dest->sll_pkttype = 0; 40 | dest->sll_halen = 0; 41 | memset(dest->sll_addr, 0, sizeof(dest->sll_addr)); 42 | } 43 | 44 | #define LINUX_IFF_UP 0x0001 45 | #define LINUX_IFF_BROADCAST 0x0002 46 | #define LINUX_IFF_DEBUG 0x0004 47 | #define LINUX_IFF_LOOPBACK 0x0008 48 | #define LINUX_IFF_POINTOPOINT 0x0010 49 | //~ #define LINUX_IFF_NOTRAILERS 0x0020 50 | #define LINUX_IFF_RUNNING 0x0040 51 | #define LINUX_IFF_NOARP 0x0080 52 | #define LINUX_IFF_PROMISC 0x0100 53 | #define LINUX_IFF_ALLMULTI 0x0200 54 | #define LINUX_IFF_MULTICAST 0x1000 55 | 56 | static int native_to_linux_if_flags(int flags) { 57 | 58 | int linux_flags = 0; 59 | 60 | if (flags & IFF_UP) linux_flags |= LINUX_IFF_UP; 61 | if (flags & IFF_BROADCAST) linux_flags |= LINUX_IFF_BROADCAST; 62 | if (flags & IFF_DEBUG) linux_flags |= LINUX_IFF_DEBUG; 63 | if (flags & IFF_LOOPBACK) linux_flags |= LINUX_IFF_LOOPBACK; 64 | if (flags & IFF_POINTOPOINT) linux_flags |= LINUX_IFF_POINTOPOINT; 65 | if (flags & IFF_RUNNING) linux_flags |= LINUX_IFF_RUNNING; 66 | if (flags & IFF_NOARP) linux_flags |= LINUX_IFF_NOARP; 67 | if (flags & IFF_PROMISC) linux_flags |= LINUX_IFF_PROMISC; 68 | if (flags & IFF_ALLMULTI) linux_flags |= LINUX_IFF_ALLMULTI; 69 | if (flags & IFF_MULTICAST) linux_flags |= LINUX_IFF_MULTICAST; 70 | 71 | return linux_flags; 72 | } 73 | 74 | static struct linux_ifaddrs* copy_ifaddrs(struct ifaddrs* ifa) { 75 | 76 | linux_ifaddrs* linux_ifa = malloc(sizeof(linux_ifaddrs)); 77 | 78 | linux_ifa->ifa_name = strdup(ifa->ifa_name); 79 | linux_ifa->ifa_flags = native_to_linux_if_flags(ifa->ifa_flags); 80 | 81 | if (ifa->ifa_addr != NULL) { 82 | switch (ifa->ifa_addr->sa_family) { 83 | case AF_LINK: 84 | linux_ifa->ifa_addr = malloc(sizeof(linux_sockaddr_ll)); 85 | native_to_linux_sockaddr_dl((linux_sockaddr_ll*)linux_ifa->ifa_addr, (struct sockaddr_dl*)ifa->ifa_addr); 86 | break; 87 | case AF_INET: 88 | linux_ifa->ifa_addr = malloc(sizeof(linux_sockaddr_in)); 89 | native_to_linux_sockaddr_in((linux_sockaddr_in*)linux_ifa->ifa_addr, (struct sockaddr_in*)ifa->ifa_addr); 90 | break; 91 | case AF_INET6: 92 | linux_ifa->ifa_addr = malloc(sizeof(linux_sockaddr_in6)); 93 | native_to_linux_sockaddr_in6((linux_sockaddr_in6*)linux_ifa->ifa_addr, (struct sockaddr_in6*)ifa->ifa_addr); 94 | break; 95 | default: 96 | assert(0); 97 | } 98 | } else { 99 | linux_ifa->ifa_addr = NULL; 100 | } 101 | 102 | if (ifa->ifa_netmask != NULL) { 103 | switch (ifa->ifa_netmask->sa_family) { 104 | case AF_INET: 105 | linux_ifa->ifa_netmask = malloc(sizeof(linux_sockaddr_in)); 106 | native_to_linux_sockaddr_in((linux_sockaddr_in*)linux_ifa->ifa_netmask, (struct sockaddr_in*)ifa->ifa_netmask); 107 | break; 108 | case AF_INET6: 109 | linux_ifa->ifa_netmask = malloc(sizeof(linux_sockaddr_in6)); 110 | native_to_linux_sockaddr_in6((linux_sockaddr_in6*)linux_ifa->ifa_netmask, (struct sockaddr_in6*)ifa->ifa_netmask); 111 | break; 112 | default: 113 | assert(0); 114 | } 115 | } else { 116 | linux_ifa->ifa_netmask = NULL; 117 | } 118 | 119 | linux_ifa->ifa_dstaddr = NULL; // ? 120 | linux_ifa->ifa_data = NULL; 121 | 122 | return linux_ifa; 123 | } 124 | 125 | static int shim_getifaddrs_impl(linux_ifaddrs** res) { 126 | 127 | struct ifaddrs* list_head; 128 | int err = getifaddrs(&list_head); 129 | if (err == 0) { 130 | struct ifaddrs* ifa = list_head; 131 | linux_ifaddrs* linux_ifa = copy_ifaddrs(ifa); 132 | *res = linux_ifa; 133 | ifa = ifa->ifa_next; 134 | 135 | while (ifa != NULL) { 136 | linux_ifa->ifa_next = copy_ifaddrs(ifa); 137 | linux_ifa = linux_ifa->ifa_next; 138 | ifa = ifa->ifa_next; 139 | } 140 | 141 | freeifaddrs(list_head); 142 | } 143 | 144 | return err; 145 | } 146 | 147 | static void shim_freeifaddrs_impl(linux_ifaddrs* ifa) { 148 | while (ifa != NULL) { 149 | linux_ifaddrs* next = ifa->ifa_next; 150 | 151 | free(ifa->ifa_name); 152 | 153 | if (ifa->ifa_addr != NULL) free(ifa->ifa_addr); 154 | if (ifa->ifa_netmask != NULL) free(ifa->ifa_netmask); 155 | if (ifa->ifa_dstaddr != NULL) free(ifa->ifa_dstaddr); 156 | 157 | free(ifa); 158 | 159 | ifa = next; 160 | } 161 | } 162 | 163 | SHIM_WRAP(getifaddrs); 164 | SHIM_WRAP(freeifaddrs); 165 | -------------------------------------------------------------------------------- /src/libc/langinfo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../shim.h" 3 | #include "locale.h" 4 | 5 | #define LINUX_CODESET 14 6 | #define LINUX_D_T_FMT 0x20028 7 | #define LINUX_D_FMT 0x20029 8 | #define LINUX_T_FMT 0x2002a 9 | #define LINUX_T_FMT_AMPM 0x2002b 10 | #define LINUX_AM_STR 0x20026 11 | #define LINUX_PM_STR 0x20027 12 | #define LINUX_DAY_1 0x20007 13 | #define LINUX_DAY_2 0x20008 14 | #define LINUX_DAY_3 0x20009 15 | #define LINUX_DAY_4 0x2000a 16 | #define LINUX_DAY_5 0x2000b 17 | #define LINUX_DAY_6 0x2000c 18 | #define LINUX_DAY_7 0x2000d 19 | #define LINUX_ABDAY_1 0x20000 20 | #define LINUX_ABDAY_2 0x20001 21 | #define LINUX_ABDAY_3 0x20002 22 | #define LINUX_ABDAY_4 0x20003 23 | #define LINUX_ABDAY_5 0x20004 24 | #define LINUX_ABDAY_6 0x20005 25 | #define LINUX_ABDAY_7 0x20006 26 | #define LINUX_MON_1 0x2001a 27 | #define LINUX_MON_2 0x2001b 28 | #define LINUX_MON_3 0x2001c 29 | #define LINUX_MON_4 0x2001d 30 | #define LINUX_MON_5 0x2001e 31 | #define LINUX_MON_6 0x2001f 32 | #define LINUX_MON_7 0x20020 33 | #define LINUX_MON_8 0x20021 34 | #define LINUX_MON_9 0x20022 35 | #define LINUX_MON_10 0x20023 36 | #define LINUX_MON_11 0x20024 37 | #define LINUX_MON_12 0x20025 38 | #define LINUX_ABMON_1 0x2000e 39 | #define LINUX_ABMON_2 0x2000f 40 | #define LINUX_ABMON_3 0x20010 41 | #define LINUX_ABMON_4 0x20011 42 | #define LINUX_ABMON_5 0x20012 43 | #define LINUX_ABMON_6 0x20013 44 | #define LINUX_ABMON_7 0x20014 45 | #define LINUX_ABMON_8 0x20015 46 | #define LINUX_ABMON_9 0x20016 47 | #define LINUX_ABMON_10 0x20017 48 | #define LINUX_ABMON_11 0x20018 49 | #define LINUX_ABMON_12 0x20019 50 | #define LINUX_ERA 0x2002c 51 | #define LINUX_ERA_D_FMT 0x2002e 52 | #define LINUX_ERA_D_T_FMT 0x20030 53 | #define LINUX_ERA_T_FMT 0x20031 54 | #define LINUX_ALT_DIGITS 0x2002f 55 | #define LINUX_RADIXCHAR 0x10000 56 | #define LINUX_THOUSEP 0x10001 57 | #define LINUX_YESEXPR 0x50000 58 | #define LINUX_NOEXPR 0x50001 59 | #define LINUX_CRNCYSTR 0x4000f 60 | 61 | static nl_item linux_to_native_nl_item(nl_item linux_item) { 62 | switch (linux_item) { 63 | case LINUX_CODESET: return CODESET; 64 | case LINUX_D_T_FMT: return D_T_FMT; 65 | case LINUX_D_FMT: return D_FMT; 66 | case LINUX_T_FMT: return T_FMT; 67 | case LINUX_T_FMT_AMPM: return T_FMT_AMPM; 68 | case LINUX_AM_STR: return AM_STR; 69 | case LINUX_PM_STR: return PM_STR; 70 | case LINUX_DAY_1: return DAY_1; 71 | case LINUX_DAY_2: return DAY_2; 72 | case LINUX_DAY_3: return DAY_3; 73 | case LINUX_DAY_4: return DAY_4; 74 | case LINUX_DAY_5: return DAY_5; 75 | case LINUX_DAY_6: return DAY_6; 76 | case LINUX_DAY_7: return DAY_7; 77 | case LINUX_ABDAY_1: return ABDAY_1; 78 | case LINUX_ABDAY_2: return ABDAY_2; 79 | case LINUX_ABDAY_3: return ABDAY_3; 80 | case LINUX_ABDAY_4: return ABDAY_4; 81 | case LINUX_ABDAY_5: return ABDAY_5; 82 | case LINUX_ABDAY_6: return ABDAY_6; 83 | case LINUX_ABDAY_7: return ABDAY_7; 84 | case LINUX_MON_1: return MON_1; 85 | case LINUX_MON_2: return MON_2; 86 | case LINUX_MON_3: return MON_3; 87 | case LINUX_MON_4: return MON_4; 88 | case LINUX_MON_5: return MON_5; 89 | case LINUX_MON_6: return MON_6; 90 | case LINUX_MON_7: return MON_7; 91 | case LINUX_MON_8: return MON_8; 92 | case LINUX_MON_9: return MON_9; 93 | case LINUX_MON_10: return MON_10; 94 | case LINUX_MON_11: return MON_11; 95 | case LINUX_MON_12: return MON_12; 96 | case LINUX_ABMON_1: return ABMON_1; 97 | case LINUX_ABMON_2: return ABMON_2; 98 | case LINUX_ABMON_3: return ABMON_3; 99 | case LINUX_ABMON_4: return ABMON_4; 100 | case LINUX_ABMON_5: return ABMON_5; 101 | case LINUX_ABMON_6: return ABMON_6; 102 | case LINUX_ABMON_7: return ABMON_7; 103 | case LINUX_ABMON_8: return ABMON_8; 104 | case LINUX_ABMON_9: return ABMON_9; 105 | case LINUX_ABMON_10: return ABMON_10; 106 | case LINUX_ABMON_11: return ABMON_11; 107 | case LINUX_ABMON_12: return ABMON_12; 108 | case LINUX_ERA: return ERA; 109 | case LINUX_ERA_D_FMT: return ERA_D_FMT; 110 | case LINUX_ERA_D_T_FMT: return ERA_D_T_FMT; 111 | case LINUX_ERA_T_FMT: return ERA_T_FMT; 112 | case LINUX_ALT_DIGITS: return ALT_DIGITS; 113 | case LINUX_RADIXCHAR: return RADIXCHAR; 114 | case LINUX_THOUSEP: return THOUSEP; 115 | case LINUX_YESEXPR: return YESEXPR; 116 | case LINUX_NOEXPR: return NOEXPR; 117 | case LINUX_CRNCYSTR: return CRNCYSTR; 118 | default: 119 | PANIC("Unknown linux nl_item: %d", linux_item); 120 | } 121 | } 122 | 123 | static char* shim_nl_langinfo_impl(nl_item linux_item) { 124 | return nl_langinfo(linux_to_native_nl_item(linux_item)); 125 | } 126 | 127 | SHIM_WRAP(nl_langinfo); 128 | 129 | static char* shim_nl_langinfo_l_impl(nl_item item, linux_locale_t loc) { 130 | UNIMPLEMENTED(); 131 | } 132 | 133 | SHIM_WRAP(nl_langinfo_l); 134 | -------------------------------------------------------------------------------- /src/libc/libgen.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../shim.h" 3 | 4 | static char* shim___xpg_basename_impl(const char* path) { 5 | return basename(path); 6 | } 7 | 8 | SHIM_WRAP(__xpg_basename); 9 | -------------------------------------------------------------------------------- /src/libc/libintl.c: -------------------------------------------------------------------------------- 1 | #include "../shim.h" 2 | 3 | static char* shim_gettext_impl(const char* msgid) { 4 | return msgid; 5 | } 6 | 7 | SHIM_WRAP(gettext); 8 | -------------------------------------------------------------------------------- /src/libc/locale.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "../shim.h" 5 | #include "locale.h" 6 | 7 | extern const unsigned short** shim___ctype_b_loc(); 8 | extern int32_t** shim___ctype_tolower_loc(); 9 | extern int32_t** shim___ctype_toupper_loc(); 10 | 11 | static linux_locale_t shim___newlocale_impl(int category_mask, const char* locale, linux_locale_t base) { 12 | 13 | assert(category_mask == 64 || category_mask == 8127); // LC_ALL_MASK 14 | assert(strcmp(locale, "C") == 0); 15 | 16 | linux_locale_t linux_locale = malloc(sizeof(struct linux_locale)); 17 | 18 | linux_locale->__ctype_b = *shim___ctype_b_loc(); 19 | linux_locale->__ctype_tolower = *shim___ctype_tolower_loc(); 20 | linux_locale->__ctype_toupper = *shim___ctype_toupper_loc(); 21 | 22 | for (int i = 0; i < 13; i++) { 23 | linux_locale->__locales[i] = (void*)(uintptr_t)(0xdead0000 + i); 24 | linux_locale->__names[i] = ""; 25 | } 26 | 27 | linux_locale->native_locale = newlocale(LC_ALL_MASK, locale, base != NULL ? base->native_locale : NULL); 28 | 29 | return linux_locale; 30 | } 31 | 32 | static linux_locale_t shim___duplocale_impl(linux_locale_t locale) { 33 | linux_locale_t duplicate = malloc(sizeof(struct linux_locale)); 34 | memcpy(duplicate, locale, sizeof(struct linux_locale)); 35 | duplicate->native_locale = duplocale(locale->native_locale); 36 | return duplicate; 37 | } 38 | 39 | __thread linux_locale_t thread_locale = LINUX_LC_GLOBAL_LOCALE; 40 | 41 | static linux_locale_t shim___uselocale_impl(linux_locale_t locale) { 42 | 43 | linux_locale_t prev = thread_locale; 44 | 45 | if (locale != NULL) { 46 | 47 | thread_locale = locale; 48 | 49 | if (locale == LINUX_LC_GLOBAL_LOCALE) { 50 | uselocale(LC_GLOBAL_LOCALE); 51 | } else { 52 | uselocale(locale->native_locale); 53 | } 54 | } 55 | 56 | return prev; 57 | } 58 | 59 | static void shim___freelocale_impl(linux_locale_t locale) { 60 | freelocale(locale->native_locale); 61 | free(locale); 62 | } 63 | 64 | SHIM_WRAP(__newlocale); 65 | SHIM_WRAP(__duplocale); 66 | SHIM_WRAP(__uselocale); 67 | SHIM_WRAP(__freelocale); 68 | 69 | static linux_locale_t shim_newlocale_impl(int mask, const char* locale, linux_locale_t base) { 70 | return shim___newlocale_impl(mask, locale, base); 71 | } 72 | 73 | static linux_locale_t shim_duplocale_impl(linux_locale_t locale) { 74 | return shim___duplocale_impl(locale); 75 | } 76 | 77 | static linux_locale_t shim_uselocale_impl(linux_locale_t locale) { 78 | return shim___uselocale_impl(locale); 79 | } 80 | 81 | static void shim_freelocale_impl(linux_locale_t locale) { 82 | shim___freelocale_impl(locale); 83 | } 84 | 85 | SHIM_WRAP(newlocale); 86 | SHIM_WRAP(duplocale); 87 | SHIM_WRAP(uselocale); 88 | SHIM_WRAP(freelocale); 89 | 90 | struct shim_lconv { 91 | char *decimal_point; 92 | char *thousands_sep; 93 | char *grouping; 94 | char *int_curr_symbol; 95 | char *currency_symbol; 96 | char *mon_decimal_point; 97 | char *mon_thousands_sep; 98 | char *mon_grouping; 99 | char *positive_sign; 100 | char *negative_sign; 101 | char int_frac_digits; 102 | char frac_digits; 103 | char p_cs_precedes; 104 | char p_sep_by_space; 105 | char n_cs_precedes; 106 | char n_sep_by_space; 107 | char p_sign_posn; 108 | char n_sign_posn; 109 | char int_p_cs_precedes; 110 | char int_p_sep_by_space; 111 | char int_n_cs_precedes; 112 | char int_n_sep_by_space; 113 | char int_p_sign_posn; 114 | char int_n_sign_posn; 115 | }; 116 | 117 | typedef struct shim_lconv linux_lconv; 118 | 119 | static linux_lconv process_lconv; 120 | 121 | static void set_process_lconv() { 122 | struct lconv* native_lconv = localeconv(); 123 | assert(native_lconv != NULL); 124 | process_lconv.decimal_point = native_lconv->decimal_point; 125 | process_lconv.thousands_sep = native_lconv->thousands_sep; 126 | process_lconv.grouping = native_lconv->grouping; 127 | process_lconv.int_curr_symbol = native_lconv->int_curr_symbol; 128 | process_lconv.currency_symbol = native_lconv->currency_symbol; 129 | process_lconv.mon_decimal_point = native_lconv->mon_decimal_point; 130 | process_lconv.mon_thousands_sep = native_lconv->mon_thousands_sep; 131 | process_lconv.mon_grouping = native_lconv->mon_grouping; 132 | process_lconv.positive_sign = native_lconv->positive_sign; 133 | process_lconv.negative_sign = native_lconv->negative_sign; 134 | process_lconv.int_frac_digits = native_lconv->int_frac_digits; 135 | process_lconv.frac_digits = native_lconv->frac_digits; 136 | process_lconv.p_cs_precedes = native_lconv->p_cs_precedes; 137 | process_lconv.p_sep_by_space = native_lconv->p_sep_by_space; 138 | process_lconv.n_cs_precedes = native_lconv->n_cs_precedes; 139 | process_lconv.n_sep_by_space = native_lconv->n_sep_by_space; 140 | process_lconv.p_sign_posn = native_lconv->p_sign_posn; 141 | process_lconv.n_sign_posn = native_lconv->n_sign_posn; 142 | process_lconv.int_p_cs_precedes = native_lconv->int_p_cs_precedes; 143 | process_lconv.int_p_sep_by_space = native_lconv->int_p_sep_by_space; 144 | process_lconv.int_n_cs_precedes = native_lconv->int_n_cs_precedes; 145 | process_lconv.int_n_sep_by_space = native_lconv->int_n_sep_by_space; 146 | process_lconv.int_p_sign_posn = native_lconv->int_p_sign_posn; 147 | process_lconv.int_n_sign_posn = native_lconv->int_n_sign_posn; 148 | } 149 | 150 | __attribute__((constructor)) 151 | static void init() { 152 | set_process_lconv(); 153 | } 154 | 155 | static linux_lconv* shim_localeconv_impl() { 156 | return &process_lconv; 157 | } 158 | 159 | #define LINUX_LC_CTYPE 0 160 | #define LINUX_LC_NUMERIC 1 161 | #define LINUX_LC_TIME 2 162 | #define LINUX_LC_COLLATE 3 163 | #define LINUX_LC_MONETARY 4 164 | #define LINUX_LC_MESSAGES 5 165 | #define LINUX_LC_ALL 6 166 | 167 | static int linux_to_native_category(int linux_category) { 168 | switch (linux_category) { 169 | case LINUX_LC_CTYPE: return LC_CTYPE; 170 | case LINUX_LC_NUMERIC : return LC_NUMERIC; 171 | case LINUX_LC_TIME: return LC_TIME; 172 | case LINUX_LC_COLLATE: return LC_COLLATE; 173 | case LINUX_LC_MONETARY: return LC_MONETARY; 174 | case LINUX_LC_MESSAGES: return LC_MESSAGES; 175 | case LINUX_LC_ALL: return LC_ALL; 176 | default: 177 | assert(0); 178 | } 179 | } 180 | 181 | static char* shim_setlocale_impl(int linux_category, const char* locale) { 182 | char* ret = setlocale(linux_to_native_category(linux_category), locale); 183 | if (ret != NULL) { 184 | set_process_lconv(); 185 | } 186 | return ret; 187 | } 188 | 189 | SHIM_WRAP(localeconv); 190 | SHIM_WRAP(setlocale); 191 | -------------------------------------------------------------------------------- /src/libc/locale.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct linux_locale { 4 | void* __locales[13]; 5 | const unsigned short* __ctype_b; 6 | const int* __ctype_tolower; 7 | const int* __ctype_toupper; 8 | const char* __names[13]; 9 | locale_t native_locale; 10 | }; 11 | 12 | typedef struct linux_locale* linux_locale_t; 13 | 14 | #define LINUX_LC_GLOBAL_LOCALE ((linux_locale_t)-1) 15 | -------------------------------------------------------------------------------- /src/libc/malloc.c: -------------------------------------------------------------------------------- 1 | #include "../shim.h" 2 | 3 | //~ void* shim_mallinfo() { 4 | //~ UNIMPLEMENTED(); 5 | //~ } 6 | -------------------------------------------------------------------------------- /src/libc/netdb.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../shim.h" 4 | #include "sys/socket.h" 5 | #include "netdb.h" 6 | 7 | static int* shim___h_errno_location_impl() { 8 | return &h_errno; 9 | } 10 | 11 | SHIM_WRAP(__h_errno_location); 12 | 13 | typedef struct linux_addrinfo linux_addrinfo; 14 | 15 | struct linux_addrinfo { 16 | int ai_flags; 17 | int ai_family; 18 | int ai_socktype; 19 | int ai_protocol; 20 | socklen_t ai_addrlen; 21 | linux_sockaddr* ai_addr; 22 | char* ai_canonname; 23 | linux_addrinfo* ai_next; 24 | }; 25 | 26 | #define LINUX_AI_PASSIVE 0x01 27 | #define LINUX_AI_CANONNAME 0x02 28 | #define LINUX_AI_NUMERICHOST 0x04 29 | #define LINUX_AI_V4MAPPED 0x08 30 | #define LINUX_AI_ALL 0x10 31 | #define LINUX_AI_ADDRCONFIG 0x20 32 | 33 | #define KNOWN_LINUX_AI_FLAGS ( \ 34 | LINUX_AI_PASSIVE | \ 35 | LINUX_AI_CANONNAME | \ 36 | LINUX_AI_NUMERICHOST | \ 37 | LINUX_AI_V4MAPPED | \ 38 | LINUX_AI_ALL | \ 39 | LINUX_AI_ADDRCONFIG \ 40 | ) 41 | 42 | static int linux_to_native_ai_flags(int linux_flags) { 43 | 44 | assert((linux_flags & ~KNOWN_LINUX_AI_FLAGS) == 0); 45 | 46 | int flags = 0; 47 | 48 | if (linux_flags & LINUX_AI_PASSIVE) flags |= AI_PASSIVE; 49 | if (linux_flags & LINUX_AI_CANONNAME) flags |= AI_CANONNAME; 50 | if (linux_flags & LINUX_AI_NUMERICHOST) flags |= AI_NUMERICHOST; 51 | if (linux_flags & LINUX_AI_V4MAPPED) flags |= AI_V4MAPPED; 52 | if (linux_flags & LINUX_AI_ALL) flags |= AI_ALL; 53 | if (linux_flags & LINUX_AI_ADDRCONFIG) flags |= AI_ADDRCONFIG; 54 | 55 | return flags; 56 | } 57 | 58 | static linux_addrinfo* copy_addrinfo(struct addrinfo* info) { 59 | 60 | linux_addrinfo* linux_info = malloc(sizeof(linux_addrinfo)); 61 | 62 | linux_info->ai_flags = 0; 63 | linux_info->ai_socktype = native_to_linux_sock_type(info->ai_socktype); 64 | linux_info->ai_protocol = info->ai_protocol; 65 | linux_info->ai_canonname = info->ai_canonname != NULL ? strdup(info->ai_canonname) : NULL; 66 | 67 | switch (info->ai_family) { 68 | case PF_INET: 69 | linux_info->ai_family = LINUX_PF_INET; 70 | linux_info->ai_addrlen = sizeof(linux_sockaddr_in); 71 | linux_info->ai_addr = malloc(sizeof(linux_sockaddr_in)); 72 | native_to_linux_sockaddr_in((linux_sockaddr_in*)linux_info->ai_addr, (struct sockaddr_in*)info->ai_addr); 73 | break; 74 | case PF_INET6: 75 | linux_info->ai_family = LINUX_PF_INET6; 76 | linux_info->ai_addrlen = sizeof(linux_sockaddr_in6); 77 | linux_info->ai_addr = malloc(sizeof(linux_sockaddr_in6)); 78 | native_to_linux_sockaddr_in6((linux_sockaddr_in6*)linux_info->ai_addr, (struct sockaddr_in6*)info->ai_addr); 79 | break; 80 | default: 81 | assert(0); 82 | } 83 | 84 | return linux_info; 85 | } 86 | 87 | static int shim_getaddrinfo_impl(const char* hostname, const char* servname, const linux_addrinfo* linux_hints, linux_addrinfo** res) { 88 | 89 | struct addrinfo hints; 90 | if (linux_hints != NULL) { 91 | switch (linux_hints->ai_family) { 92 | case LINUX_AF_UNSPEC: hints.ai_family = AF_UNSPEC; break; 93 | case LINUX_AF_INET: hints.ai_family = AF_INET; break; 94 | case LINUX_AF_INET6: hints.ai_family = AF_INET6; break; 95 | default: 96 | assert(0); 97 | } 98 | hints.ai_socktype = linux_to_native_sock_type(linux_hints->ai_socktype); 99 | hints.ai_protocol = linux_hints->ai_protocol; 100 | hints.ai_flags = linux_to_native_ai_flags(linux_hints->ai_flags); 101 | } else { 102 | hints.ai_family = AF_UNSPEC; 103 | hints.ai_socktype = 0; 104 | hints.ai_protocol = 0; 105 | hints.ai_flags = 0; 106 | } 107 | hints.ai_addrlen = 0; 108 | hints.ai_addr = NULL; 109 | hints.ai_canonname = NULL; 110 | hints.ai_next = NULL; 111 | 112 | struct addrinfo* list_head; 113 | int err = getaddrinfo(hostname, servname, &hints, &list_head); 114 | if (err == 0) { 115 | linux_addrinfo* linux_info = (*res = copy_addrinfo(list_head)); 116 | for (struct addrinfo* info = list_head->ai_next; info != NULL; info = info->ai_next) { 117 | linux_info->ai_next = copy_addrinfo(info); 118 | linux_info = linux_info->ai_next; 119 | } 120 | linux_info->ai_next = NULL; 121 | freeaddrinfo(list_head); 122 | } 123 | 124 | return err; 125 | } 126 | 127 | static void shim_freeaddrinfo_impl(linux_addrinfo* ai) { 128 | while (ai != NULL) { 129 | linux_addrinfo* next = ai->ai_next; 130 | if (ai->ai_canonname != NULL) { 131 | free(ai->ai_canonname); 132 | } 133 | free(ai->ai_addr); 134 | free(ai); 135 | ai = next; 136 | } 137 | } 138 | 139 | SHIM_WRAP(getaddrinfo); 140 | SHIM_WRAP(freeaddrinfo); 141 | 142 | #define LINUX_NI_NUMERICHOST 1 143 | #define LINUX_NI_NUMERICSERV 2 144 | #define LINUX_NI_NOFQDN 4 145 | #define LINUX_NI_NAMEREQD 8 146 | #define LINUX_NI_DGRAM 16 147 | 148 | #define KNOWN_LINUX_NI_FLAGS ( \ 149 | LINUX_NI_NUMERICHOST | \ 150 | LINUX_NI_NUMERICSERV | \ 151 | LINUX_NI_NOFQDN | \ 152 | LINUX_NI_NAMEREQD | \ 153 | LINUX_NI_DGRAM \ 154 | ) 155 | 156 | static int linux_to_native_ni_flags(int linux_flags) { 157 | 158 | assert((linux_flags & ~KNOWN_LINUX_NI_FLAGS) == 0); 159 | 160 | int flags = 0; 161 | 162 | if (linux_flags & LINUX_NI_NUMERICHOST) flags |= NI_NUMERICHOST; 163 | if (linux_flags & LINUX_NI_NUMERICSERV) flags |= NI_NUMERICSERV; 164 | if (linux_flags & LINUX_NI_NOFQDN) flags |= NI_NOFQDN; 165 | if (linux_flags & LINUX_NI_NAMEREQD) flags |= NI_NAMEREQD; 166 | if (linux_flags & LINUX_NI_DGRAM) flags |= NI_DGRAM; 167 | 168 | return flags; 169 | } 170 | 171 | static int shim_getnameinfo_impl(const linux_sockaddr* linux_addr, socklen_t linux_addrlen, char* host, size_t hostlen, char* serv, size_t servlen, int linux_flags) { 172 | 173 | switch (linux_addr->sa_family) { 174 | case LINUX_AF_UNIX: 175 | { 176 | struct sockaddr_un addr; 177 | assert(linux_addrlen <= sizeof(struct linux_sockaddr_un)); 178 | linux_to_native_sockaddr_un(&addr, (linux_sockaddr_un*)linux_addr); 179 | return getnameinfo((struct sockaddr*)&addr, sizeof(addr), host, hostlen, serv, servlen, linux_to_native_ni_flags(linux_flags)); 180 | } 181 | break; 182 | case LINUX_AF_INET: 183 | { 184 | struct sockaddr_in addr; 185 | assert(linux_addrlen == sizeof(struct linux_sockaddr_in)); 186 | linux_to_native_sockaddr_in(&addr, (linux_sockaddr_in*)linux_addr); 187 | return getnameinfo((struct sockaddr*)&addr, sizeof(addr), host, hostlen, serv, servlen, linux_to_native_ni_flags(linux_flags)); 188 | } 189 | break; 190 | case LINUX_AF_INET6: 191 | { 192 | struct sockaddr_in6 addr; 193 | assert(linux_addrlen == sizeof(struct linux_sockaddr_in6)); 194 | linux_to_native_sockaddr_in6(&addr, (linux_sockaddr_in6*)linux_addr); 195 | return getnameinfo((struct sockaddr*)&addr, sizeof(addr), host, hostlen, serv, servlen, linux_to_native_ni_flags(linux_flags)); 196 | } 197 | break; 198 | default: 199 | assert(0); 200 | } 201 | } 202 | 203 | SHIM_WRAP(getnameinfo); 204 | -------------------------------------------------------------------------------- /src/libc/netdb.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | typedef struct hostent linux_hostent; 4 | typedef struct protoent linux_protoent; 5 | -------------------------------------------------------------------------------- /src/libc/poll.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../shim.h" 3 | #include "signal.h" 4 | #include "time.h" 5 | 6 | extern int (*libepoll_epoll_shim_poll) (struct pollfd[], nfds_t, int); 7 | extern int (*libepoll_epoll_shim_ppoll)(struct pollfd[], nfds_t, const struct timespec* restrict, const sigset_t* restrict); 8 | 9 | static int shim_poll_impl(struct pollfd fds[], nfds_t nfds, int timeout) { 10 | return libepoll_epoll_shim_poll(fds, nfds, timeout); 11 | } 12 | 13 | static int shim_ppoll_impl(struct pollfd fds[], nfds_t nfds, const linux_timespec* restrict timeout, const linux_sigset_t* restrict newsigmask) { 14 | return libepoll_epoll_shim_ppoll(fds, nfds, timeout, (sigset_t*)newsigmask); 15 | } 16 | 17 | SHIM_WRAP(poll); 18 | SHIM_WRAP(ppoll); 19 | -------------------------------------------------------------------------------- /src/libc/pwd.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "../shim.h" 5 | 6 | struct linux_passwd { 7 | char* pw_name; 8 | char* pw_passwd; 9 | uid_t pw_uid; 10 | gid_t pw_gid; 11 | char* pw_gecos; 12 | char* pw_dir; 13 | char* pw_shell; 14 | }; 15 | 16 | typedef struct linux_passwd linux_passwd; 17 | 18 | static linux_passwd lp; 19 | 20 | static linux_passwd* shim_getpwuid_impl(uid_t uid) { 21 | 22 | struct passwd* p = getpwuid(uid); 23 | if (p == NULL) { 24 | return NULL; 25 | } 26 | 27 | lp.pw_name = p->pw_name; 28 | lp.pw_passwd = p->pw_passwd; 29 | lp.pw_uid = p->pw_uid; 30 | lp.pw_gid = p->pw_gid; 31 | lp.pw_gecos = p->pw_gecos; 32 | lp.pw_dir = p->pw_dir; 33 | lp.pw_shell = p->pw_shell; 34 | 35 | return &lp; 36 | } 37 | 38 | SHIM_WRAP(getpwuid); 39 | -------------------------------------------------------------------------------- /src/libc/sched.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../shim.h" 3 | #include "sched.h" 4 | 5 | typedef void linux_cpu_set_t; 6 | 7 | static int shim_sched_getaffinity_impl(pid_t pid, size_t cpusetsize, linux_cpu_set_t* mask) { 8 | return -1; 9 | } 10 | 11 | static int shim_sched_setaffinity_impl(pid_t pid, size_t cpusetsize, linux_cpu_set_t* mask) { 12 | return 0; 13 | } 14 | 15 | SHIM_WRAP(sched_getaffinity); 16 | SHIM_WRAP(sched_setaffinity); 17 | 18 | int linux_to_native_sched_policy(int linux_policy) { 19 | switch (linux_policy) { 20 | case LINUX_SCHED_NORMAL: return SCHED_OTHER; 21 | case LINUX_SCHED_FIFO: return SCHED_FIFO; 22 | case LINUX_SCHED_RR: return SCHED_RR; 23 | default: 24 | assert(0); 25 | } 26 | } 27 | 28 | int native_to_linux_sched_policy(int linux_policy) { 29 | switch (linux_policy) { 30 | case SCHED_OTHER: return LINUX_SCHED_NORMAL; 31 | case SCHED_FIFO: return LINUX_SCHED_FIFO; 32 | case SCHED_RR: return LINUX_SCHED_RR; 33 | default: 34 | assert(0); 35 | } 36 | } 37 | 38 | static int shim_sched_get_priority_max_impl(int linux_policy) { 39 | return sched_get_priority_max(linux_to_native_sched_policy(linux_policy)); 40 | } 41 | 42 | static int shim_sched_get_priority_min_impl(int linux_policy) { 43 | return sched_get_priority_min(linux_to_native_sched_policy(linux_policy)); 44 | } 45 | 46 | SHIM_WRAP(sched_get_priority_max); 47 | SHIM_WRAP(sched_get_priority_min); 48 | 49 | static int shim_sched_getscheduler_impl(pid_t pid) { 50 | return native_to_linux_sched_policy(sched_getscheduler(pid)); 51 | } 52 | 53 | static int shim_sched_setscheduler_impl(pid_t pid, int policy, const linux_sched_param* param) { 54 | return sched_setscheduler(pid, linux_to_native_sched_policy(policy), param); 55 | } 56 | 57 | SHIM_WRAP(sched_getscheduler); 58 | SHIM_WRAP(sched_setscheduler); 59 | 60 | static int shim_posix_spawnattr_getschedpolicy_impl(const posix_spawnattr_t* restrict attr, int* restrict linux_policy) { 61 | int policy; 62 | int err = posix_spawnattr_getschedpolicy(attr, &policy); 63 | if (err == 0) { 64 | *linux_policy = native_to_linux_sched_policy(policy); 65 | } 66 | return err; 67 | } 68 | 69 | static int shim_posix_spawnattr_setschedpolicy_impl(posix_spawnattr_t* attr, int linux_policy) { 70 | return posix_spawnattr_setschedpolicy(attr, linux_to_native_sched_policy(linux_policy)); 71 | } 72 | 73 | SHIM_WRAP(posix_spawnattr_getschedpolicy); 74 | SHIM_WRAP(posix_spawnattr_setschedpolicy); 75 | -------------------------------------------------------------------------------- /src/libc/sched.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | typedef struct sched_param linux_sched_param; 5 | 6 | enum { 7 | LINUX_SCHED_NORMAL = 0, 8 | LINUX_SCHED_FIFO = 1, 9 | LINUX_SCHED_RR = 2, 10 | LINUX_SCHED_BATCH = 3, 11 | LINUX_SCHED_IDLE = 5 12 | }; 13 | 14 | int linux_to_native_sched_policy(int linux_policy); 15 | int native_to_linux_sched_policy(int linux_policy); 16 | -------------------------------------------------------------------------------- /src/libc/semaphore.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../shim.h" 4 | #include "time.h" 5 | 6 | static int shim_sem_trywait_impl(sem_t* sem) { 7 | int err = sem_trywait(sem); 8 | if (err == -1) { 9 | errno = native_to_linux_errno(errno); 10 | } 11 | return err; 12 | } 13 | 14 | static int shim_sem_timedwait_impl(sem_t* sem, const linux_timespec* abs_timeout) { 15 | int err = sem_timedwait(sem, abs_timeout); 16 | if (err == -1) { 17 | errno = native_to_linux_errno(errno); 18 | } 19 | return err; 20 | } 21 | 22 | SHIM_WRAP(sem_trywait); 23 | SHIM_WRAP(sem_timedwait); 24 | 25 | static int shim_sem_getvalue_impl(sem_t* restrict sem, int* restrict sval) { 26 | return sem_getvalue(sem, sval); 27 | } 28 | 29 | SHIM_WRAP(sem_getvalue); 30 | -------------------------------------------------------------------------------- /src/libc/setjmp.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../shim.h" 3 | 4 | #ifdef __i386__ 5 | _Static_assert(sizeof(jmp_buf) <= 156, ""); 6 | _Static_assert(sizeof(sigjmp_buf) <= 156, ""); 7 | #endif 8 | 9 | #ifdef __x86_64__ 10 | _Static_assert(sizeof(jmp_buf) <= 200, ""); 11 | _Static_assert(sizeof(sigjmp_buf) <= 200, ""); 12 | #endif 13 | 14 | int shim_setjmp(jmp_buf env) { 15 | UNIMPLEMENTED(); 16 | } 17 | 18 | __attribute__((naked)) 19 | int shim__setjmp(jmp_buf env) { 20 | __asm__("jmp _setjmp"); 21 | } 22 | 23 | __attribute__((naked)) 24 | int shim___sigsetjmp(jmp_buf env, int savemask) { 25 | __asm__("jmp sigsetjmp"); 26 | } 27 | 28 | SHIM_EXPORT(setjmp); 29 | SHIM_EXPORT(_setjmp); 30 | SHIM_EXPORT(__sigsetjmp); 31 | 32 | static void shim_longjmp_impl(jmp_buf env, int val) { 33 | //~ fprintf(stderr, "[[%s]]\n", __func__); 34 | _longjmp(env, val); 35 | } 36 | 37 | static void shim__longjmp_impl(jmp_buf env, int val) { 38 | //~ fprintf(stderr, "[[%s]]\n", __func__); 39 | _longjmp(env, val); 40 | } 41 | 42 | static void shim___longjmp_chk_impl(jmp_buf env, int val) { 43 | _longjmp(env, val); 44 | } 45 | 46 | static void shim_siglongjmp_impl(sigjmp_buf env, int val) { 47 | //~ fprintf(stderr, "[[%s]]\n", __func__); 48 | siglongjmp(env, val); 49 | } 50 | 51 | SHIM_WRAP(longjmp); 52 | SHIM_WRAP(_longjmp); 53 | SHIM_WRAP(__longjmp_chk); 54 | SHIM_WRAP(siglongjmp); 55 | -------------------------------------------------------------------------------- /src/libc/signal.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "../shim.h" 7 | #include "signal.h" 8 | #include "time.h" 9 | 10 | static int shim___libc_current_sigrtmin_impl() { 11 | return SIGRTMIN; 12 | } 13 | 14 | static int shim___libc_current_sigrtmax_impl() { 15 | return SIGRTMAX; 16 | } 17 | 18 | SHIM_WRAP(__libc_current_sigrtmin); 19 | SHIM_WRAP(__libc_current_sigrtmax); 20 | 21 | int linux_to_freebsd_signo(int linux_signal) { 22 | 23 | if ( (linux_signal >= 0 && linux_signal < 7) 24 | || (linux_signal > 7 && linux_signal < 10) 25 | || linux_signal == 11 26 | || (linux_signal > 12 && linux_signal < 17) 27 | || (linux_signal > 20 && linux_signal < 23) 28 | || (linux_signal > 23 && linux_signal < 29) 29 | || (linux_signal >= SIGRTMIN && linux_signal <= SIGRTMAX)) 30 | { 31 | return linux_signal; 32 | } 33 | 34 | switch (linux_signal) { 35 | //~ case LINUX_SIGBUS: return SIGBUS; 36 | //~ case LINUX_SIGUSR1: return SIGUSR1; 37 | //~ case LINUX_SIGUSR2: return SIGUSR2; 38 | //~ case LINUX_SIGCHLD: return SIGCHLD; 39 | //~ case LINUX_SIGCONT: return SIGCONT; 40 | //~ case LINUX_SIGSTOP: return SIGSTOP; 41 | //~ case LINUX_SIGTSTP: return SIGTSTP; 42 | //~ case LINUX_SIGURG: return SIGURG; 43 | //~ case LINUX_SIGIO: return SIGIO; 44 | //~ case LINUX_SIGSYS: return SIGSYS; 45 | case LINUX_SIGPWR: return SIGUSR1; // same number 46 | default: 47 | return -1; 48 | } 49 | } 50 | 51 | static int shim_kill_impl(pid_t pid, int linux_sig) { 52 | int sig = linux_to_freebsd_signo(linux_sig); 53 | assert(sig != -1); 54 | return kill(pid, sig); 55 | } 56 | 57 | static int shim_killpg_impl(pid_t pgrp, int sig) { 58 | UNIMPLEMENTED(); 59 | } 60 | 61 | static void shim_psignal_impl(int sig, const char* s) { 62 | UNIMPLEMENTED(); 63 | } 64 | 65 | static int shim_raise_impl(int linux_sig) { 66 | int sig = linux_to_freebsd_signo(linux_sig); 67 | assert(sig != -1); 68 | return raise(sig); 69 | } 70 | 71 | static sig_t shim_signal_impl(int linux_sig, sig_t func) { 72 | int sig = linux_to_freebsd_signo(linux_sig); 73 | assert(sig != -1); 74 | return signal(sig, func); 75 | } 76 | 77 | static char* shim_strsignal_impl(int sig) { 78 | UNIMPLEMENTED() 79 | } 80 | 81 | SHIM_WRAP(kill); 82 | SHIM_WRAP(killpg); 83 | SHIM_WRAP(psignal); 84 | SHIM_WRAP(raise); 85 | SHIM_WRAP(signal); 86 | SHIM_WRAP(strsignal); 87 | 88 | static int linux_to_freebsd_sigaction_flags(int linux_flags) { 89 | 90 | assert((linux_flags & ~KNOWN_LINUX_SIGACTION_FLAGS) == 0); 91 | 92 | int flags = 0; 93 | 94 | if (linux_flags & LINUX_SA_NOCLDSTOP) flags |= SA_NOCLDSTOP; 95 | if (linux_flags & LINUX_SA_NOCLDWAIT) flags |= SA_NOCLDWAIT; 96 | if (linux_flags & LINUX_SA_SIGINFO) flags |= SA_SIGINFO; 97 | if (linux_flags & LINUX_SA_ONSTACK) flags |= SA_ONSTACK; 98 | if (linux_flags & LINUX_SA_RESTART) flags |= SA_RESTART; 99 | if (linux_flags & LINUX_SA_NODEFER) flags |= SA_NODEFER; 100 | if (linux_flags & LINUX_SA_RESETHAND) flags |= SA_RESETHAND; 101 | 102 | return flags; 103 | } 104 | 105 | static int freebsd_to_linux_sigaction_flags(int flags) { 106 | 107 | assert((flags & ~(SA_NOCLDSTOP | SA_NOCLDWAIT | SA_SIGINFO | SA_ONSTACK | SA_RESTART | SA_NODEFER | SA_RESETHAND)) == 0); 108 | 109 | int linux_flags = 0; 110 | 111 | if (flags & SA_NOCLDSTOP) linux_flags |= LINUX_SA_NOCLDSTOP; 112 | if (flags & SA_NOCLDWAIT) linux_flags |= LINUX_SA_NOCLDWAIT; 113 | if (flags & SA_SIGINFO) linux_flags |= LINUX_SA_SIGINFO; 114 | if (flags & SA_ONSTACK) linux_flags |= LINUX_SA_ONSTACK; 115 | if (flags & SA_RESTART) linux_flags |= LINUX_SA_RESTART; 116 | if (flags & SA_NODEFER) linux_flags |= LINUX_SA_NODEFER; 117 | if (flags & SA_RESETHAND) linux_flags |= LINUX_SA_RESETHAND; 118 | 119 | return linux_flags; 120 | } 121 | 122 | // note that LINUX_SIG_DFL == SIG_DFL and LINUX_SIG_IGN == SIG_IGN 123 | static void linux_to_native_sigaction(struct sigaction* dst, const linux_sigaction* src) { 124 | dst->sa_handler = src->linux_sa_handler; 125 | memcpy(&dst->sa_mask, &src->sa_mask, sizeof(sigset_t)); 126 | dst->sa_flags = linux_to_freebsd_sigaction_flags(src->sa_flags); 127 | } 128 | 129 | static void native_to_linux_sigaction(linux_sigaction* dst, const struct sigaction* src) { 130 | dst->linux_sa_handler = src->sa_handler; 131 | memcpy(&dst->sa_mask, &src->sa_mask, sizeof(sigset_t)); 132 | dst->sa_flags = freebsd_to_linux_sigaction_flags(src->sa_flags); 133 | } 134 | 135 | static int shim_sigaction_impl(int linux_sig, const linux_sigaction* linux_act, linux_sigaction* linux_oact) { 136 | 137 | // we are not interested in letting things like Unity to register its own segfault handlers 138 | if (linux_sig == LINUX_SIGABRT || linux_sig == LINUX_SIGSEGV || linux_sig == LINUX_SIGBUS || linux_sig == LINUX_SIGSYS) { 139 | if (linux_oact != NULL) { 140 | linux_oact->linux_sa_handler = LINUX_SIG_DFL; 141 | sigemptyset((sigset_t*)&linux_oact->sa_mask); 142 | linux_oact->sa_flags = 0; 143 | } 144 | return 0; 145 | } 146 | 147 | int sig = linux_to_freebsd_signo(linux_sig); 148 | if (sig == -1) { 149 | return -1; 150 | } 151 | 152 | if (linux_act != NULL) { 153 | struct sigaction act; 154 | linux_to_native_sigaction(&act, linux_act); 155 | 156 | if (linux_oact != NULL) { 157 | struct sigaction oact; 158 | int err = sigaction(sig, &act, &oact); 159 | if (err != -1) { 160 | native_to_linux_sigaction(linux_oact, &oact); 161 | } 162 | return err; 163 | } else { 164 | return sigaction(sig, &act, NULL); 165 | } 166 | } else { 167 | 168 | if (linux_oact != NULL) { 169 | struct sigaction oact; 170 | int err = sigaction(sig, NULL, &oact); 171 | if (err != -1) { 172 | native_to_linux_sigaction(linux_oact, &oact); 173 | } 174 | return err; 175 | } else { 176 | return -1; 177 | } 178 | } 179 | } 180 | 181 | static int shim_sigemptyset_impl(linux_sigset_t* set) { 182 | return sigemptyset((sigset_t*)set); 183 | } 184 | 185 | static int shim_sigfillset_impl(linux_sigset_t* set) { 186 | return sigfillset((sigset_t*)set); 187 | } 188 | 189 | static int shim_sigpending_impl(linux_sigset_t* set) { 190 | return sigpending((sigset_t*)set); 191 | } 192 | 193 | SHIM_WRAP(sigemptyset); 194 | SHIM_WRAP(sigfillset); 195 | SHIM_WRAP(sigpending); 196 | 197 | static int shim_sigaddset_impl(linux_sigset_t* set, int linux_signo) { 198 | return sigaddset((sigset_t*)set, linux_to_freebsd_signo(linux_signo)); 199 | } 200 | 201 | static int shim_sigdelset_impl(linux_sigset_t* set, int linux_signo) { 202 | return sigdelset((sigset_t*)set, linux_to_freebsd_signo(linux_signo)); 203 | } 204 | 205 | static int shim_siginterrupt_impl(int sig, int flag) { 206 | UNIMPLEMENTED(); 207 | } 208 | 209 | static int shim_sigprocmask_impl(int linux_how, const linux_sigset_t* restrict set, linux_sigset_t* restrict oset) { 210 | switch (linux_how) { 211 | case LINUX_SIG_BLOCK: return sigprocmask(SIG_BLOCK, (sigset_t*)set, (sigset_t*)oset); 212 | case LINUX_SIG_UNBLOCK: return sigprocmask(SIG_UNBLOCK, (sigset_t*)set, (sigset_t*)oset); 213 | case LINUX_SIG_SETMASK: return sigprocmask(SIG_SETMASK, (sigset_t*)set, (sigset_t*)oset); 214 | default: 215 | UNIMPLEMENTED_ARGS("%d", linux_how); 216 | } 217 | } 218 | 219 | static int shim_sigismember_impl(const linux_sigset_t* set, int linux_signo) { 220 | return sigismember((sigset_t*)set, linux_to_freebsd_signo(linux_signo)); 221 | } 222 | 223 | static int shim_sigqueue_impl(pid_t pid, int signo, const union sigval value) { 224 | UNIMPLEMENTED(); 225 | } 226 | 227 | static int shim_sigsuspend_impl(const linux_sigset_t* sigmask) { 228 | return sigsuspend((sigset_t*)sigmask); 229 | } 230 | 231 | //TODO: linux_siginfo_t? 232 | static int shim_sigtimedwait_impl(const linux_sigset_t* restrict set, siginfo_t* restrict info, const linux_timespec* restrict timeout) { 233 | UNIMPLEMENTED(); 234 | } 235 | 236 | static int shim_sigwait_impl(const linux_sigset_t* restrict set, int* restrict linux_sig) { 237 | UNIMPLEMENTED(); 238 | } 239 | 240 | //TODO: linux_siginfo_t? 241 | static int shim_sigwaitinfo_impl(const linux_sigset_t* restrict set, siginfo_t* restrict info) { 242 | UNIMPLEMENTED(); 243 | } 244 | 245 | SHIM_WRAP(sigaction); 246 | SHIM_WRAP(sigaddset); 247 | SHIM_WRAP(sigdelset); 248 | SHIM_WRAP(siginterrupt); 249 | SHIM_WRAP(sigismember); 250 | SHIM_WRAP(sigprocmask); 251 | SHIM_WRAP(sigqueue); 252 | SHIM_WRAP(sigsuspend); 253 | SHIM_WRAP(sigtimedwait); 254 | SHIM_WRAP(sigwait); 255 | SHIM_WRAP(sigwaitinfo); 256 | 257 | static int linux_to_freebsd_sigstack_flags(int linux_flags) { 258 | 259 | assert((linux_flags & ~KNOWN_LINUX_SIGSTACK_FLAGS) == 0); 260 | 261 | int flags = 0; 262 | 263 | if (linux_flags & LINUX_SS_ONSTACK) flags |= SS_ONSTACK; 264 | if (linux_flags & LINUX_SS_DISABLE) flags |= SS_DISABLE; 265 | 266 | return flags; 267 | } 268 | 269 | static int shim_sigaltstack_impl(const linux_stack_t* restrict linux_ss, linux_stack_t* restrict linux_oss) { 270 | 271 | assert(linux_ss != NULL); 272 | assert(linux_oss == NULL); 273 | 274 | LOG("%s: ss_sp = %p, ss_flags = %#x, ss_size = %#zx", __func__, linux_ss->ss_sp, linux_ss->ss_flags, linux_ss->ss_size); 275 | 276 | stack_t ss = { 277 | .ss_sp = linux_ss->ss_sp, 278 | .ss_flags = linux_to_freebsd_sigstack_flags(linux_ss->ss_flags), 279 | .ss_size = linux_ss->ss_size 280 | }; 281 | 282 | return sigaltstack(&ss, NULL); 283 | } 284 | 285 | SHIM_WRAP(sigaltstack); 286 | -------------------------------------------------------------------------------- /src/libc/signal.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define LINUX_SIGABRT 6 4 | #define LINUX_SIGBUS 7 5 | #define LINUX_SIGUSR1 10 6 | #define LINUX_SIGSEGV 11 7 | #define LINUX_SIGUSR2 12 8 | #define LINUX_SIGCHLD 17 9 | #define LINUX_SIGCONT 18 10 | #define LINUX_SIGSTOP 19 11 | #define LINUX_SIGTSTP 20 12 | #define LINUX_SIGURG 23 13 | #define LINUX_SIGXCPU 24 14 | #define LINUX_SIGIO 29 15 | #define LINUX_SIGPWR 30 16 | #define LINUX_SIGSYS 31 17 | 18 | #define LINUX_SIG_DFL SIG_DFL 19 | #define LINUX_SIG_IGN SIG_IGN 20 | 21 | typedef struct { uint64_t whatever[16]; } linux_sigset_t; 22 | _Static_assert(sizeof(sigset_t) <= sizeof(linux_sigset_t), ""); 23 | 24 | struct linux_sigaction { 25 | void* linux_sa_handler; 26 | linux_sigset_t sa_mask; 27 | int sa_flags; 28 | }; 29 | 30 | typedef struct linux_sigaction linux_sigaction; 31 | 32 | #define LINUX_SA_NOCLDSTOP 0x00000001 33 | #define LINUX_SA_NOCLDWAIT 0x00000002 34 | #define LINUX_SA_SIGINFO 0x00000004 35 | #define LINUX_SA_ONSTACK 0x08000000 36 | #define LINUX_SA_RESTART 0x10000000 37 | #define LINUX_SA_NODEFER 0x40000000 38 | #define LINUX_SA_RESETHAND 0x80000000 39 | 40 | #define KNOWN_LINUX_SIGACTION_FLAGS ( \ 41 | LINUX_SA_NOCLDSTOP | \ 42 | LINUX_SA_NOCLDWAIT | \ 43 | LINUX_SA_SIGINFO | \ 44 | LINUX_SA_ONSTACK | \ 45 | LINUX_SA_RESTART | \ 46 | LINUX_SA_NODEFER | \ 47 | LINUX_SA_RESETHAND \ 48 | ) 49 | 50 | int linux_to_freebsd_signo(int linux_signal); 51 | 52 | #define LINUX_SIG_BLOCK 0 53 | #define LINUX_SIG_UNBLOCK 1 54 | #define LINUX_SIG_SETMASK 2 55 | 56 | #define LINUX_SS_ONSTACK 1 57 | #define LINUX_SS_DISABLE 2 58 | 59 | #define KNOWN_LINUX_SIGSTACK_FLAGS (LINUX_SS_ONSTACK | LINUX_SS_DISABLE) 60 | 61 | struct linux_stack { 62 | void* ss_sp; 63 | int ss_flags; 64 | size_t ss_size; 65 | }; 66 | 67 | typedef struct linux_stack linux_stack_t; 68 | -------------------------------------------------------------------------------- /src/libc/spawn.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../shim.h" 3 | #include "signal.h" 4 | 5 | static int shim_posix_spawnattr_getsigdefault_impl(const posix_spawnattr_t* restrict attr, linux_sigset_t* restrict sigdefault) { 6 | return posix_spawnattr_getsigdefault(attr, (sigset_t*)sigdefault); 7 | } 8 | 9 | static int shim_posix_spawnattr_getsigmask_impl(const posix_spawnattr_t* restrict attr, linux_sigset_t* restrict sigmask) { 10 | return posix_spawnattr_getsigmask(attr, (sigset_t*)sigmask); 11 | } 12 | 13 | static int shim_posix_spawnattr_setsigdefault_impl(posix_spawnattr_t* attr, const linux_sigset_t* restrict sigdefault) { 14 | return posix_spawnattr_setsigdefault(attr, (sigset_t*)sigdefault); 15 | } 16 | 17 | static int shim_posix_spawnattr_setsigmask_impl(posix_spawnattr_t* attr, const linux_sigset_t* restrict sigmask) { 18 | return posix_spawnattr_setsigmask(attr, (sigset_t*)sigmask); 19 | } 20 | 21 | SHIM_WRAP(posix_spawnattr_getsigdefault); 22 | SHIM_WRAP(posix_spawnattr_getsigmask); 23 | SHIM_WRAP(posix_spawnattr_setsigdefault); 24 | SHIM_WRAP(posix_spawnattr_setsigmask); 25 | -------------------------------------------------------------------------------- /src/libc/stdio.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include "../shim.h" 11 | 12 | static int shim___isoc99_fscanf_impl(FILE* restrict stream, const char* restrict format, va_list args) { 13 | return vfscanf(stream, format, args); 14 | } 15 | 16 | static FILE* shim_fopen_impl(const char* path, const char* mode) { 17 | 18 | if (strcmp(path, "/proc/driver/nvidia/params") == 0) { 19 | 20 | assert(strcmp(mode, "r") == 0); 21 | 22 | char str[] = "ModifyDeviceFiles: 0\n"; 23 | 24 | FILE* mem = fmemopen(0, sizeof(str), "r+"); 25 | fwrite(str, sizeof(char), sizeof(str), mem); 26 | rewind(mem); 27 | 28 | return mem; 29 | } 30 | 31 | // CUDA 32 | if (strncmp(path, "/proc/self/task/", sizeof("/proc/self/task/") - 1) == 0) { 33 | char* tail = strchr(path + sizeof("/proc/self/task/"), '/'); 34 | if (tail != NULL && strcmp(tail, "/comm") == 0) { 35 | assert(strcmp(mode, "wb") == 0); 36 | return fopen("/dev/null", mode); 37 | } 38 | } 39 | 40 | char* p = redirect(path); 41 | if (p == NULL) { 42 | errno = EACCES; 43 | return NULL; 44 | } 45 | 46 | return fopen(p, mode); 47 | } 48 | 49 | static FILE* shim_fopen64_impl(const char* path, const char* mode) { 50 | return shim_fopen_impl(path, mode); 51 | } 52 | 53 | static int shim_remove_impl(const char* path) { 54 | assert(str_starts_with(path, "/dev/char/195:") || !str_starts_with(path, "/dev/")); 55 | return remove(path); 56 | } 57 | 58 | SHIM_WRAP(__isoc99_fscanf); 59 | SHIM_WRAP(fopen); 60 | SHIM_WRAP(fopen64); 61 | SHIM_WRAP(remove); 62 | 63 | static int shim___printf_chk_impl(int flag, const char* format, va_list args) { 64 | return vprintf(format, args); 65 | } 66 | 67 | static int shim___snprintf_chk_impl(char* str, size_t maxlen, int flag, size_t strlen, const char* format, va_list args) { 68 | assert(flag == 1 && strlen >= maxlen); 69 | return vsnprintf(str, maxlen, format, args); 70 | } 71 | 72 | static int shim___vsnprintf_chk_impl(char* str, size_t maxlen, int flag, size_t strlen, const char* format, va_list args) { 73 | assert(flag == 1 && strlen >= maxlen); 74 | return vsnprintf(str, maxlen, format, args); 75 | } 76 | 77 | static int shim___fprintf_chk_impl(FILE* stream, int flag, const char* format, va_list args) { 78 | return vfprintf(stream, format, args); 79 | } 80 | 81 | static int shim___sprintf_chk_impl(char* str, int flag, size_t strlen, const char* format, va_list args) { 82 | return vsprintf(str, format, args); 83 | } 84 | 85 | static int shim___vasprintf_chk_impl(char** ret, int flags, const char* format, va_list args) { 86 | return vasprintf(ret, format, args); 87 | } 88 | 89 | static int shim___vfprintf_chk_impl(FILE* stream, int flag, const char* format, va_list args) { 90 | return vfprintf(stream, format, args); 91 | } 92 | 93 | SHIM_WRAP(__printf_chk); 94 | SHIM_WRAP(__snprintf_chk); 95 | SHIM_WRAP(__vsnprintf_chk); 96 | SHIM_WRAP(__fprintf_chk); 97 | SHIM_WRAP(__sprintf_chk); 98 | SHIM_WRAP(__vasprintf_chk); 99 | SHIM_WRAP(__vfprintf_chk); 100 | 101 | static int shim_fgetpos64_impl(FILE* stream, linux_fpos64_t* pos) { 102 | return fgetpos(stream, pos); 103 | } 104 | 105 | SHIM_WRAP(fgetpos64); 106 | 107 | static int shim_fseeko64_impl(FILE* stream, linux_off64_t offset, int whence) { 108 | return fseeko(stream, offset, whence); 109 | } 110 | 111 | SHIM_WRAP(fseeko64); 112 | 113 | static linux_off64_t shim_ftello64_impl(FILE* stream) { 114 | return ftello(stream); 115 | } 116 | 117 | SHIM_WRAP(ftello64); 118 | -------------------------------------------------------------------------------- /src/libc/stdlib.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "../shim.h" 10 | 11 | #define STRTONUM_INTERNAL_I(ret_type, name) \ 12 | static ret_type shim_ ## __ ## name ## _internal_impl(char* nptr, char** endptr, int base, int group) {\ 13 | return name(nptr, endptr, base);\ 14 | } 15 | 16 | #define STRTONUM_INTERNAL_F(ret_type, name) \ 17 | static ret_type shim_ ## __ ## name ## _internal_impl(char* nptr, char** endptr, int group) {\ 18 | return name(nptr, endptr);\ 19 | } 20 | 21 | STRTONUM_INTERNAL_I(long, strtol); 22 | STRTONUM_INTERNAL_I(long long, strtoll); 23 | STRTONUM_INTERNAL_I(unsigned long, strtoul); 24 | STRTONUM_INTERNAL_I(unsigned long long, strtoull); 25 | STRTONUM_INTERNAL_F(float, strtof); 26 | STRTONUM_INTERNAL_F(double, strtod); 27 | STRTONUM_INTERNAL_F(long double, strtold); 28 | 29 | SHIM_WRAP(__strtol_internal); 30 | SHIM_WRAP(__strtoll_internal); 31 | SHIM_WRAP(__strtoul_internal); 32 | SHIM_WRAP(__strtoull_internal); 33 | SHIM_WRAP(__strtof_internal); 34 | SHIM_WRAP(__strtod_internal); 35 | SHIM_WRAP(__strtold_internal); 36 | 37 | static void* shim_memalign_impl(size_t alignment, size_t size) { 38 | void* p = NULL; 39 | posix_memalign(&p, alignment, size); 40 | return p; 41 | } 42 | 43 | SHIM_WRAP(memalign); 44 | 45 | static char* shim___realpath_chk_impl(const char* path, char* resolved_path, size_t resolved_len) { 46 | assert(resolved_len >= PATH_MAX); 47 | return realpath(path, resolved_path); 48 | } 49 | 50 | SHIM_WRAP(__realpath_chk); 51 | 52 | static char* shim_secure_getenv_impl(const char* name) { 53 | return issetugid() == 0 ? getenv(name) : NULL; 54 | } 55 | 56 | SHIM_WRAP(secure_getenv); 57 | 58 | static char* shim_realpath_impl(const char* restrict path, char* restrict resolved_path) { 59 | 60 | if (str_starts_with(path, "/proc/")) { 61 | 62 | char* p = strdup(&path[sizeof("/proc/") - 1]); 63 | assert(p != NULL); 64 | 65 | char* s = p; 66 | char* node = strsep(&s, "/"); 67 | char* entry = strsep(&s, "/"); 68 | 69 | if (strcmp(entry, "exe") == 0) { 70 | 71 | int pid; 72 | if (strcmp(node, "self") == 0) { 73 | pid = -1; 74 | } else { 75 | pid = strtoul(node, NULL, 10); 76 | assert(pid > 0); 77 | } 78 | 79 | free(p); 80 | 81 | char* out = resolved_path != NULL ? resolved_path : malloc(PATH_MAX); 82 | 83 | if ((pid == -1 || pid == getpid()) && proc_self_exe_override != NULL) { 84 | size_t nchars = strlcpy(out, proc_self_exe_override, PATH_MAX); 85 | assert(nchars < PATH_MAX); 86 | } else { 87 | int name[] = { 88 | CTL_KERN, 89 | KERN_PROC, 90 | KERN_PROC_PATHNAME, 91 | pid 92 | }; 93 | 94 | size_t len = PATH_MAX; 95 | int err = sysctl(name, nitems(name), out, &len, NULL, 0); 96 | if (err == -1) { 97 | errno = native_to_linux_errno(errno); 98 | return NULL; 99 | } 100 | } 101 | 102 | return out; 103 | 104 | } else { 105 | 106 | free(p); 107 | 108 | errno = native_to_linux_errno(EACCES); 109 | return NULL; 110 | } 111 | } 112 | 113 | if (str_starts_with(path, "/sys/")) { 114 | errno = native_to_linux_errno(EACCES); 115 | return NULL; 116 | } 117 | 118 | return realpath(path, resolved_path); 119 | } 120 | 121 | SHIM_WRAP(realpath); 122 | -------------------------------------------------------------------------------- /src/libc/string.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "../shim.h" 6 | #include "locale.h" 7 | 8 | static void* shim___rawmemchr_impl(const void* s, int c) { 9 | return memchr(s, c, INT_MAX); 10 | } 11 | 12 | static void shim_perror_impl(const char* string) { 13 | errno = linux_to_native_errno(errno); 14 | perror(string); 15 | } 16 | 17 | static char* shim_strerror_impl(int errnum) { 18 | return strerror(linux_to_native_errno(errnum)); 19 | } 20 | 21 | static char* shim_strerror_r_impl(int errnum, char* strerrbuf, size_t buflen) { 22 | strerror_r(linux_to_native_errno(errnum), strerrbuf, buflen); 23 | return strerrbuf; 24 | } 25 | 26 | SHIM_WRAP(__rawmemchr); 27 | SHIM_WRAP(perror); 28 | SHIM_WRAP(strerror); 29 | SHIM_WRAP(strerror_r); 30 | 31 | static void* shim___memset_chk_impl(void* dest, int c, size_t len, size_t destlen) { 32 | assert(len <= destlen); 33 | return memset(dest, c, len); 34 | } 35 | 36 | SHIM_WRAP(__memset_chk); 37 | 38 | static char* shim___strcat_chk_impl(char* dest, const char* src, size_t destlen) { 39 | assert(strlen(src) + strlen(dest) < destlen); 40 | return strcat(dest, src); 41 | } 42 | 43 | static char* shim___strncat_chk_impl(char* dest, const char* src, size_t n, size_t destlen) { 44 | assert(strlen(src) + strlen(dest) < destlen); 45 | return strncat(dest, src, n); 46 | } 47 | 48 | SHIM_WRAP(__strcat_chk); 49 | SHIM_WRAP(__strncat_chk); 50 | 51 | static void* shim___memcpy_chk_impl(void* dst, const void* src, size_t len, size_t destlen) { 52 | assert(len <= destlen); 53 | return memcpy(dst, src, len); 54 | } 55 | 56 | static char* shim___strcpy_chk_impl(char* dest, const char* src, size_t destlen) { 57 | assert(strlen(src) < destlen); 58 | return strcpy(dest, src); 59 | } 60 | 61 | static char* shim___stpcpy_chk_impl(char* dest, const char* src, size_t destlen) { 62 | assert(strlen(src) < destlen); 63 | return stpcpy(dest, src); 64 | } 65 | 66 | static char* shim___strncpy_chk_impl(char* s1, const char* s2, size_t n, size_t s1len) { 67 | assert(n <= s1len); 68 | return strncpy(s1, s2, n); 69 | } 70 | 71 | SHIM_WRAP(__memcpy_chk); 72 | SHIM_WRAP(__strcpy_chk); 73 | SHIM_WRAP(__stpcpy_chk); 74 | SHIM_WRAP(__strncpy_chk); 75 | 76 | static int shim_strcasecmp_l_impl(const char* s1, const char* s2, linux_locale_t loc) { 77 | return strcasecmp_l(s1, s2, loc->native_locale); 78 | } 79 | 80 | static int shim_strcoll_l_impl(const char* s1, const char* s2, linux_locale_t loc) { 81 | return strcoll_l(s1, s2, loc->native_locale); 82 | } 83 | 84 | static int shim_strncasecmp_l_impl(const char* s1, const char* s2, size_t len, linux_locale_t loc) { 85 | return strncasecmp_l(s1, s2, len, loc->native_locale); 86 | } 87 | 88 | static size_t shim___strxfrm_l_impl(char* restrict dst, const char* restrict src, size_t n, linux_locale_t loc) { 89 | return strxfrm_l(dst, src, n, loc->native_locale); 90 | } 91 | 92 | static size_t shim_strxfrm_l_impl(char* restrict dst, const char* restrict src, size_t n, linux_locale_t loc) { 93 | return strxfrm_l(dst, src, n, loc->native_locale); 94 | } 95 | 96 | SHIM_WRAP(strcasecmp_l); 97 | SHIM_WRAP(strcoll_l); 98 | SHIM_WRAP(strncasecmp_l); 99 | SHIM_WRAP(__strxfrm_l); 100 | SHIM_WRAP(strxfrm_l); 101 | 102 | static int shim___xpg_strerror_r_impl(int errnum, char* buf, size_t buflen) { 103 | return strerror_r(linux_to_native_errno(errnum), buf, buflen); 104 | } 105 | 106 | SHIM_WRAP(__xpg_strerror_r); 107 | 108 | static void* shim___memmove_chk_impl(void* dest, const void* src, size_t len, size_t destlen) { 109 | assert(len <= destlen); 110 | return memmove(dest, src, len); 111 | } 112 | 113 | SHIM_WRAP(__memmove_chk); 114 | -------------------------------------------------------------------------------- /src/libc/sys/epoll.c: -------------------------------------------------------------------------------- 1 | #define EPOLL_SHIM_DISABLE_WRAPPER_MACROS 2 | 3 | #include 4 | #include 5 | #include "../../shim.h" 6 | #include "../signal.h" 7 | 8 | #define LINUX_EPOLL_CLOEXEC 0x80000 9 | 10 | typedef struct epoll_event linux_epoll_event; 11 | 12 | extern int (*libepoll_epoll_create) (int); 13 | extern int (*libepoll_epoll_create1)(int); 14 | extern int (*libepoll_epoll_ctl) (int, int, int, struct epoll_event*); 15 | extern int (*libepoll_epoll_wait) (int, struct epoll_event*, int, int); 16 | extern int (*libepoll_epoll_pwait) (int, struct epoll_event*, int, int, const sigset_t*); 17 | 18 | static int shim_epoll_create_impl(int size) { 19 | return libepoll_epoll_create(size); 20 | } 21 | 22 | static int shim_epoll_create1_impl(int linux_flags) { 23 | 24 | assert((linux_flags & ~LINUX_EPOLL_CLOEXEC) == 0); 25 | 26 | int flags = 0; 27 | 28 | if (linux_flags & LINUX_EPOLL_CLOEXEC) { 29 | flags |= EPOLL_CLOEXEC; 30 | } 31 | 32 | return libepoll_epoll_create1(flags); 33 | } 34 | 35 | static int shim_epoll_ctl_impl(int epfd, int linux_op, int fd, linux_epoll_event* linux_event) { 36 | return libepoll_epoll_ctl(epfd, linux_op /* same encoding */, fd, linux_event /* same encoding */); 37 | } 38 | 39 | static int shim_epoll_wait_impl(int epfd, linux_epoll_event* events, int maxevents, int timeout) { 40 | return libepoll_epoll_wait(epfd, events /* same encoding */, maxevents, timeout); 41 | } 42 | 43 | static int shim_epoll_pwait_impl(int epfd, struct epoll_event* events, int maxevents, int timeout, const linux_sigset_t* sigmask) { 44 | return libepoll_epoll_pwait(epfd, events /* same encoding */, maxevents, timeout, (sigset_t*)sigmask); 45 | } 46 | 47 | SHIM_WRAP(epoll_create); 48 | SHIM_WRAP(epoll_create1); 49 | SHIM_WRAP(epoll_ctl); 50 | SHIM_WRAP(epoll_wait); 51 | SHIM_WRAP(epoll_pwait); 52 | -------------------------------------------------------------------------------- /src/libc/sys/eventfd.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../../shim.h" 4 | #include "fcntl.h" 5 | 6 | #define LINUX_EFD_SEMAPHORE 1 7 | #define LINUX_EFD_NONBLOCK 0x00800 8 | #define LINUX_EFD_CLOEXEC 0x80000 9 | 10 | static int shim_eventfd_impl(unsigned int initval, int linux_flags) { 11 | 12 | assert((linux_flags & ~(LINUX_EFD_CLOEXEC | LINUX_EFD_NONBLOCK | LINUX_EFD_SEMAPHORE)) == 0); 13 | 14 | int flags = 0; 15 | if (linux_flags & LINUX_EFD_SEMAPHORE) flags |= EFD_SEMAPHORE; 16 | if (linux_flags & LINUX_EFD_NONBLOCK) flags |= EFD_NONBLOCK; 17 | if (linux_flags & LINUX_EFD_CLOEXEC) flags |= EFD_CLOEXEC; 18 | 19 | return eventfd(initval, flags); 20 | } 21 | 22 | SHIM_WRAP(eventfd); 23 | -------------------------------------------------------------------------------- /src/libc/sys/inotify.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "../../shim.h" 5 | 6 | #define LINUX_ENFILE 23 7 | 8 | static int dummy() { 9 | errno = LINUX_ENFILE; 10 | return -1; 11 | } 12 | 13 | static int (*libinotify_inotify_init) (void); 14 | static int (*libinotify_inotify_init1) (int); 15 | static int (*libinotify_inotify_add_watch)(int, const char*, uint32_t); 16 | static int (*libinotify_inotify_rm_watch) (int, int); 17 | 18 | __attribute__((constructor)) 19 | static void init() { 20 | void* libinotify = dlopen("libinotify.so.0", RTLD_LAZY); 21 | if (libinotify != NULL) { 22 | libinotify_inotify_init = dlsym(libinotify, "inotify_init"); assert(libinotify_inotify_init != NULL); 23 | libinotify_inotify_init1 = dlsym(libinotify, "inotify_init1"); assert(libinotify_inotify_init1 != NULL); 24 | libinotify_inotify_add_watch = dlsym(libinotify, "inotify_add_watch"); assert(libinotify_inotify_add_watch != NULL); 25 | libinotify_inotify_rm_watch = dlsym(libinotify, "inotify_rm_watch"); assert(libinotify_inotify_rm_watch != NULL); 26 | } else { 27 | Link_map* link_map = NULL; 28 | 29 | int err = dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &link_map); 30 | assert(err == 0); 31 | 32 | fprintf(stderr, "%s: unable to load libinotify.so.0 (%s)\n", link_map->l_name, dlerror()); 33 | 34 | libinotify_inotify_init = dummy; 35 | libinotify_inotify_init1 = dummy; 36 | libinotify_inotify_add_watch = dummy; 37 | libinotify_inotify_rm_watch = dummy; 38 | } 39 | } 40 | 41 | static int shim_inotify_init_impl() { 42 | return libinotify_inotify_init(); 43 | } 44 | 45 | SHIM_WRAP(inotify_init); 46 | 47 | static int shim_inotify_init1_impl(int flags) { 48 | return libinotify_inotify_init1(flags); 49 | } 50 | 51 | SHIM_WRAP(inotify_init1); 52 | 53 | static int shim_inotify_add_watch_impl(int fd, const char* path, uint32_t mask) { 54 | return libinotify_inotify_add_watch(fd, path, mask); 55 | } 56 | 57 | SHIM_WRAP(inotify_add_watch); 58 | 59 | static int shim_inotify_rm_watch_impl(int fd, int wd) { 60 | return libinotify_inotify_rm_watch(fd, wd); 61 | } 62 | 63 | SHIM_WRAP(inotify_rm_watch); 64 | -------------------------------------------------------------------------------- /src/libc/sys/ioctl.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include "../../shim.h" 8 | 9 | #define NV_UVM_INITIALIZE 0x30000001 10 | #define NV_UVM_DEINITIALIZE 0x30000002 11 | 12 | #define NV_ERR_NOT_SUPPORTED 0x56 13 | 14 | struct NvUvmInitParams 15 | { 16 | uint64_t flags __attribute__((aligned(8))); 17 | uint32_t status; 18 | }; 19 | 20 | #define LINUX_TIOCGWINSZ 0x5413 21 | #define LINUX_FIONREAD 0x541b 22 | #define LINUX_FIONBIO 0x5421 23 | #define LINUX_SNDCTL_SYSINFO 0x84f85801 24 | 25 | static int shim_ioctl_impl(int fd, unsigned long request, va_list args) { 26 | 27 | int m = request & 0xffff; 28 | if ((m >= 0x4600 && m <= 0x46ff) /* nvidia */ || m == 0x6d00 /* nvidia-modeset */) { 29 | return ioctl(fd, request, va_arg(args, void*)); 30 | } 31 | 32 | if (m >= 0x4d00 && m <= 0x510E /* SOUND_MIXER_WRITE_VOLUME to SNDCTL_SYNTH_MEMAVL */) { 33 | 34 | // Linuxulator has slightly more elaborate OSS handling, so this is somewhat off 35 | 36 | if ((request & 0xff000000) == 0x40000000) { 37 | return ioctl(fd, (0x80 << 24) + (request & 0xffffff), va_arg(args, void*)); 38 | } 39 | 40 | if ((request & 0xff000000) == 0x80000000) { 41 | return ioctl(fd, (0x40 << 24) + (request & 0xffffff), va_arg(args, void*)); 42 | } 43 | 44 | return ioctl(fd, request, va_arg(args, void*)); 45 | } 46 | 47 | if (request == LINUX_TIOCGWINSZ) { 48 | return ioctl(fd, TIOCGWINSZ, va_arg(args, void*)); 49 | } 50 | 51 | if (request == LINUX_FIONREAD) { 52 | return ioctl(fd, FIONREAD, va_arg(args, int*)); 53 | } 54 | 55 | if (request == LINUX_FIONBIO) { 56 | return ioctl(fd, FIONBIO, va_arg(args, int*)); 57 | } 58 | 59 | if (request == LINUX_SNDCTL_SYSINFO) { 60 | errno = EINVAL; 61 | return -1; 62 | } 63 | 64 | if (request == NV_UVM_INITIALIZE) { 65 | struct NvUvmInitParams* params = (struct NvUvmInitParams*)va_arg(args, void*); 66 | params->status = NV_ERR_NOT_SUPPORTED; 67 | return 0; 68 | } 69 | 70 | if (request == NV_UVM_DEINITIALIZE) { 71 | return 0; 72 | } 73 | 74 | UNIMPLEMENTED_ARGS("%d, 0x%lx, _", fd, request); 75 | } 76 | 77 | SHIM_WRAP(ioctl); 78 | -------------------------------------------------------------------------------- /src/libc/sys/mman.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "../../shim.h" 7 | 8 | #define LINUX_MAP_SHARED 0x0001 9 | #define LINUX_MAP_PRIVATE 0x0002 10 | #define LINUX_MAP_FIXED 0x0010 11 | #define LINUX_MAP_ANON 0x0020 12 | #define LINUX_MAP_32BIT 0x0040 13 | #define LINUX_MAP_EXECUTABLE 0x1000 14 | #define LINUX_MAP_NORESERVE 0x4000 15 | 16 | #define KNOWN_LINUX_MMAP_FLAGS ( \ 17 | LINUX_MAP_SHARED | \ 18 | LINUX_MAP_PRIVATE | \ 19 | LINUX_MAP_FIXED | \ 20 | LINUX_MAP_ANON | \ 21 | LINUX_MAP_32BIT | \ 22 | LINUX_MAP_EXECUTABLE | \ 23 | LINUX_MAP_NORESERVE \ 24 | ) 25 | 26 | static void* shim_mmap64_impl(void *addr, size_t len, int prot, int linux_flags, int fd, linux_off64_t offset) { 27 | 28 | assert((linux_flags & KNOWN_LINUX_MMAP_FLAGS) == linux_flags); 29 | 30 | int flags = 0; 31 | 32 | if (linux_flags & LINUX_MAP_SHARED) { 33 | flags |= MAP_SHARED; 34 | } 35 | 36 | if (linux_flags & LINUX_MAP_PRIVATE) { 37 | flags |= MAP_PRIVATE; 38 | flags |= fd == -1 ? MAP_ANON : 0; // ? 39 | } 40 | 41 | if (linux_flags & LINUX_MAP_FIXED) { 42 | flags |= MAP_FIXED; 43 | } 44 | 45 | if (linux_flags & LINUX_MAP_ANON) { 46 | flags |= MAP_ANON; 47 | assert(fd == -1 || fd == 0); 48 | fd = -1; 49 | } 50 | 51 | if (linux_flags & LINUX_MAP_32BIT) { 52 | #ifdef __x86_64__ 53 | assert((linux_flags & LINUX_MAP_FIXED) == 0); 54 | flags |= MAP_32BIT; 55 | #else 56 | assert(0); 57 | #endif 58 | } 59 | 60 | void* p = mmap(addr, len, prot, flags, fd, offset); 61 | if (p == MAP_FAILED) { 62 | perror(__func__); 63 | } 64 | 65 | return p; 66 | } 67 | 68 | void* shim_mmap_impl(void *addr, size_t len, int prot, int linux_flags, int fd, linux_off_t offset) { 69 | return shim_mmap64_impl(addr, len, prot, linux_flags, fd, offset); 70 | } 71 | 72 | SHIM_WRAP(mmap); 73 | SHIM_WRAP(mmap64); 74 | 75 | static void* shim_mremap_impl(void* old_address, size_t old_size, size_t new_size, int flags, va_list args) { 76 | return (void*)-1; 77 | } 78 | 79 | SHIM_WRAP(mremap); 80 | -------------------------------------------------------------------------------- /src/libc/sys/mount.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "../../shim.h" 7 | #include "mount.h" 8 | 9 | static void copy_statfs_buf(linux_statfs* dst, struct statfs* src) { 10 | dst->f_type = src->f_type; 11 | dst->f_bsize = src->f_bsize; 12 | dst->f_blocks = src->f_blocks; 13 | dst->f_bfree = src->f_bfree; 14 | dst->f_bavail = src->f_bavail; 15 | dst->f_files = src->f_files; 16 | dst->f_ffree = src->f_ffree; 17 | dst->f_fsid = 0; // buf->f_fsid; 18 | dst->f_namelen = src->f_namemax; 19 | dst->f_frsize = 0; 20 | dst->f_flags = 0; // ? 21 | } 22 | 23 | static void copy_statfs64_buf(linux_statfs64* dst, struct statfs* src) { 24 | dst->f_type = src->f_type; 25 | dst->f_bsize = src->f_bsize; 26 | dst->f_blocks = src->f_blocks; 27 | dst->f_bfree = src->f_bfree; 28 | dst->f_bavail = src->f_bavail; 29 | dst->f_files = src->f_files; 30 | dst->f_ffree = src->f_ffree; 31 | dst->f_fsid = 0; // buf->f_fsid; 32 | dst->f_namelen = src->f_namemax; 33 | dst->f_frsize = 0; 34 | dst->f_flags = 0; // ? 35 | } 36 | 37 | static int shim_fstatfs_impl(int fd, linux_statfs* linux_buf) { 38 | 39 | struct statfs buf; 40 | 41 | int err = fstatfs(fd, &buf); 42 | if (err == 0) { 43 | copy_statfs_buf(linux_buf, &buf); 44 | } 45 | 46 | return err; 47 | } 48 | 49 | static int shim_fstatfs64_impl(int fd, linux_statfs64* linux_buf) { 50 | 51 | struct statfs buf; 52 | 53 | int err = fstatfs(fd, &buf); 54 | if (err == 0) { 55 | copy_statfs64_buf(linux_buf, &buf); 56 | } 57 | 58 | return err; 59 | } 60 | 61 | static int shim_statfs_impl(const char* path, linux_statfs* linux_buf) { 62 | 63 | struct statfs buf; 64 | 65 | int err = statfs(path, &buf); 66 | if (err == 0) { 67 | copy_statfs_buf(linux_buf, &buf); 68 | } 69 | 70 | return err; 71 | } 72 | 73 | static int shim_statfs64_impl(const char* path, linux_statfs64* linux_buf) { 74 | 75 | struct statfs buf; 76 | 77 | int err = statfs(path, &buf); 78 | if (err == 0) { 79 | copy_statfs64_buf(linux_buf, &buf); 80 | } 81 | 82 | return err; 83 | } 84 | 85 | SHIM_WRAP(fstatfs); 86 | SHIM_WRAP(fstatfs64); 87 | SHIM_WRAP(statfs); 88 | SHIM_WRAP(statfs64); 89 | -------------------------------------------------------------------------------- /src/libc/sys/mount.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #ifdef __i386__ 4 | 5 | struct linux_statfs { 6 | uint32_t f_type; 7 | uint32_t f_bsize; 8 | uint32_t f_blocks; 9 | uint32_t f_bfree; 10 | uint32_t f_bavail; 11 | uint32_t f_files; 12 | uint32_t f_ffree; 13 | uint64_t f_fsid; 14 | uint32_t f_namelen; 15 | uint32_t f_frsize; 16 | uint32_t f_flags; 17 | uint32_t f_spare[4]; 18 | }; 19 | 20 | struct linux_statfs64 { 21 | uint32_t f_type; 22 | uint32_t f_bsize; 23 | uint64_t f_blocks; 24 | uint64_t f_bfree; 25 | uint64_t f_bavail; 26 | uint64_t f_files; 27 | uint64_t f_ffree; 28 | uint64_t f_fsid; 29 | uint32_t f_namelen; 30 | uint32_t f_frsize; 31 | uint32_t f_flags; 32 | uint32_t f_spare[4]; 33 | }; 34 | 35 | typedef struct linux_statfs linux_statfs; 36 | typedef struct linux_statfs64 linux_statfs64; 37 | 38 | #endif 39 | 40 | #ifdef __x86_64__ 41 | 42 | struct linux_statfs { 43 | uint64_t f_type; 44 | uint64_t f_bsize; 45 | uint64_t f_blocks; 46 | uint64_t f_bfree; 47 | uint64_t f_bavail; 48 | uint64_t f_files; 49 | uint64_t f_ffree; 50 | uint64_t f_fsid; 51 | uint64_t f_namelen; 52 | uint64_t f_frsize; 53 | uint64_t f_flags; 54 | uint64_t f_spare[4]; 55 | }; 56 | 57 | typedef struct linux_statfs linux_statfs; 58 | typedef struct linux_statfs linux_statfs64; 59 | 60 | #endif 61 | -------------------------------------------------------------------------------- /src/libc/sys/prctl.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../../shim.h" 4 | 5 | static int shim_prctl_impl(int option, unsigned long arg2, unsigned long arg3, unsigned long arg4, unsigned long arg5) { 6 | errno = EACCES; 7 | return -1; 8 | } 9 | 10 | SHIM_WRAP(prctl); 11 | -------------------------------------------------------------------------------- /src/libc/sys/resource.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include "../../shim.h" 6 | 7 | typedef void linux_rlimit; 8 | typedef void linux_rlimit64; 9 | 10 | static int shim_getrlimit_impl(int resource, linux_rlimit* rlp) { 11 | errno = native_to_linux_errno(EPERM); 12 | return -1; 13 | } 14 | 15 | static int shim_getrlimit64_impl(int resource, linux_rlimit64* rlp) { 16 | errno = native_to_linux_errno(EPERM); 17 | return -1; 18 | } 19 | 20 | static int shim_setrlimit_impl(int resource, const linux_rlimit* rlp) { 21 | UNIMPLEMENTED(); 22 | } 23 | 24 | SHIM_WRAP(getrlimit); 25 | SHIM_WRAP(getrlimit64); 26 | SHIM_WRAP(setrlimit); 27 | -------------------------------------------------------------------------------- /src/libc/sys/select.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../../shim.h" 4 | #include "../signal.h" 5 | #include "../time.h" 6 | 7 | static int shim_pselect_impl(int nfds, fd_set* restrict readfds, fd_set* restrict writefds, fd_set* restrict exceptfds, 8 | const linux_timespec* restrict timeout, const linux_sigset_t* restrict newsigmask) 9 | { 10 | return pselect(nfds, readfds, writefds, exceptfds, timeout, (sigset_t*)newsigmask); 11 | } 12 | 13 | SHIM_WRAP(pselect); 14 | -------------------------------------------------------------------------------- /src/libc/sys/sem.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "../../shim.h" 10 | 11 | #define LINUX_IPC_RMID 0 12 | #define LINUX_IPC_SET 1 13 | #define LINUX_IPC_STAT 2 14 | #define LINUX_GETPID 11 15 | #define LINUX_GETVAL 12 16 | #define LINUX_GETALL 13 17 | #define LINUX_GETNCNT 14 18 | #define LINUX_GETZCNT 15 19 | #define LINUX_SETVAL 16 20 | #define LINUX_SETALL 17 21 | 22 | static int linux_to_native_sem_cmd(int cmd) { 23 | switch (cmd) { 24 | case LINUX_IPC_RMID: return IPC_RMID; 25 | //~ case LINUX_IPC_SET: return IPC_SET; 26 | //~ case LINUX_IPC_STAT: return IPC_STAT; 27 | case LINUX_GETPID: return GETPID; 28 | case LINUX_GETVAL: return GETVAL; 29 | //~ case LINUX_GETALL: return GETALL; 30 | case LINUX_GETNCNT: return GETNCNT; 31 | case LINUX_GETZCNT: return GETZCNT; 32 | default: 33 | assert(0); 34 | } 35 | } 36 | 37 | static int shim_semctl_impl(int semid, int semnum, int cmd, va_list args) { 38 | 39 | if (cmd == LINUX_SETVAL) { 40 | return semctl(semid, semnum, SETVAL, va_arg(args, int)); 41 | } 42 | 43 | if (cmd == LINUX_SETALL) { 44 | return semctl(semid, semnum, SETALL, va_arg(args, unsigned short*)); 45 | } 46 | 47 | return semctl(semid, semnum, linux_to_native_sem_cmd(cmd)); 48 | } 49 | 50 | SHIM_WRAP(semctl); 51 | 52 | typedef struct sembuf linux_sembuf; 53 | 54 | // IPC_NOWAIT and SEM_UNDO have same values on Linux and FreeBSD 55 | static int shim_semop_impl(int semid, linux_sembuf* array, size_t nops) { 56 | int err = semop(semid, array, nops); 57 | if (err == -1) { 58 | errno = native_to_linux_errno(errno); 59 | } 60 | return err; 61 | } 62 | 63 | SHIM_WRAP(semop); 64 | -------------------------------------------------------------------------------- /src/libc/sys/socket.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define LINUX_PF_UNSPEC 0 9 | #define LINUX_PF_UNIX 1 10 | #define LINUX_PF_INET 2 11 | #define LINUX_PF_INET6 10 12 | #define LINUX_PF_PACKET 17 13 | 14 | #define LINUX_AF_UNSPEC LINUX_PF_UNSPEC 15 | #define LINUX_AF_UNIX LINUX_PF_UNIX 16 | #define LINUX_AF_INET LINUX_PF_INET 17 | #define LINUX_AF_INET6 LINUX_PF_INET6 18 | #define LINUX_AF_PACKET LINUX_PF_PACKET 19 | 20 | #define LINUX_SOL_IP 0 21 | #define LINUX_SOL_SOCKET 1 22 | #define LINUX_SOL_TCP 6 23 | #define LINUX_SOL_UDP 17 24 | #define LINUX_SOL_IPV6 41 25 | 26 | #define LINUX_SCM_RIGHTS 1 27 | 28 | #define LINUX_SOCK_STREAM 1 29 | #define LINUX_SOCK_DGRAM 2 30 | #define LINUX_SOCK_RAW 3 31 | #define LINUX_SOCK_RDM 4 32 | #define LINUX_SOCK_SEQPACKET 5 33 | #define LINUX_SOCK_NONBLOCK 0x00800 34 | #define LINUX_SOCK_CLOEXEC 0x80000 35 | 36 | #define KNOWN_LINUX_SOCKET_TYPES ( \ 37 | LINUX_SOCK_STREAM | \ 38 | LINUX_SOCK_DGRAM | \ 39 | LINUX_SOCK_RAW | \ 40 | LINUX_SOCK_RDM | \ 41 | LINUX_SOCK_SEQPACKET | \ 42 | LINUX_SOCK_NONBLOCK | \ 43 | LINUX_SOCK_CLOEXEC \ 44 | ) 45 | 46 | #define LINUX_SO_DEBUG 1 47 | #define LINUX_SO_REUSEADDR 2 48 | #define LINUX_SO_TYPE 3 49 | #define LINUX_SO_ERROR 4 50 | #define LINUX_SO_DONTROUTE 5 51 | #define LINUX_SO_BROADCAST 6 52 | #define LINUX_SO_SNDBUF 7 53 | #define LINUX_SO_RCVBUF 8 54 | #define LINUX_SO_KEEPALIVE 9 55 | #define LINUX_SO_OOBINLINE 10 56 | #define LINUX_SO_LINGER 13 57 | #define LINUX_SO_REUSEPORT 15 58 | #define LINUX_SO_PASSCRED 16 59 | #define LINUX_SO_RCVLOWAT 18 60 | #define LINUX_SO_SNDLOWAT 19 61 | #define LINUX_SO_RCVTIMEO 20 62 | #define LINUX_SO_SNDTIMEO 21 63 | #define LINUX_SO_TIMESTAMP 29 64 | #define LINUX_SO_ACCEPTCONN 30 65 | #define LINUX_SO_PROTOCOL 38 66 | 67 | #define LINUX_IP_TOS 1 68 | #define LINUX_IP_MTU_DISCOVER 10 69 | #define LINUX_IP_RECVTOS 13 70 | 71 | #define LINUX_IPV6_V6ONLY 26 72 | 73 | #define LINUX_TCP_NODELAY 1 74 | #define LINUX_TCP_KEEPIDLE 4 75 | #define LINUX_TCP_KEEPINTVL 5 76 | #define LINUX_TCP_USER_TIMEOUT 18 77 | 78 | #define LINUX_MSG_OOB 0x00000001 79 | #define LINUX_MSG_PEEK 0x00000002 80 | #define LINUX_MSG_DONTROUTE 0x00000004 81 | #define LINUX_MSG_CTRUNC 0x00000008 82 | #define LINUX_MSG_TRUNC 0x00000020 83 | #define LINUX_MSG_DONTWAIT 0x00000040 84 | #define LINUX_MSG_EOR 0x00000080 85 | #define LINUX_MSG_WAITALL 0x00000100 86 | #define LINUX_MSG_NOSIGNAL 0x00004000 87 | #define LINUX_MSG_WAITFORONE 0x00010000 88 | #define LINUX_MSG_CMSG_CLOEXEC 0x40000000 89 | 90 | #define KNOWN_LINUX_MSG_FLAGS ( \ 91 | LINUX_MSG_OOB | \ 92 | LINUX_MSG_PEEK | \ 93 | LINUX_MSG_DONTROUTE | \ 94 | LINUX_MSG_CTRUNC | \ 95 | LINUX_MSG_TRUNC | \ 96 | LINUX_MSG_DONTWAIT | \ 97 | LINUX_MSG_EOR | \ 98 | LINUX_MSG_WAITALL | \ 99 | LINUX_MSG_NOSIGNAL | \ 100 | LINUX_MSG_WAITFORONE | \ 101 | LINUX_MSG_CMSG_CLOEXEC \ 102 | ) 103 | 104 | #define KNOWN_NATIVE_MSG_FLAGS ( \ 105 | MSG_OOB | \ 106 | MSG_PEEK | \ 107 | MSG_DONTROUTE | \ 108 | MSG_CTRUNC | \ 109 | MSG_TRUNC | \ 110 | MSG_DONTWAIT | \ 111 | MSG_EOR | \ 112 | MSG_EOF | \ 113 | MSG_WAITALL | \ 114 | MSG_NOSIGNAL | \ 115 | MSG_WAITFORONE | \ 116 | MSG_CMSG_CLOEXEC \ 117 | ) 118 | 119 | typedef struct in_addr linux_in_addr; 120 | typedef struct in6_addr linux_in6_addr; 121 | typedef struct iovec linux_iovec; 122 | 123 | struct linux_sockaddr { 124 | uint16_t sa_family; 125 | char sa_data[14]; 126 | }; 127 | 128 | struct linux_sockaddr_in { 129 | uint16_t sin_family; 130 | uint16_t sin_port; 131 | linux_in_addr sin_addr; 132 | uint8_t sin_zero[8]; 133 | }; 134 | 135 | struct linux_sockaddr_in6 { 136 | uint16_t sin6_family; 137 | uint16_t sin6_port; 138 | uint32_t sin6_flowinfo; 139 | linux_in6_addr sin6_addr; 140 | uint32_t sin6_scope_id; 141 | }; 142 | 143 | struct linux_sockaddr_un { 144 | uint16_t sun_family; 145 | char sun_path[108]; 146 | }; 147 | 148 | struct linux_msghdr { 149 | void* msg_name; 150 | socklen_t msg_namelen; 151 | linux_iovec* msg_iov; 152 | size_t msg_iovlen; 153 | void* msg_control; 154 | size_t msg_controllen; 155 | int msg_flags; 156 | }; 157 | 158 | struct linux_cmsghdr { 159 | size_t cmsg_len; 160 | int cmsg_level; 161 | int cmsg_type; 162 | // unsigned char cmsg_data[]; 163 | }; 164 | 165 | typedef struct linux_cmsghdr linux_cmsghdr; 166 | typedef struct linux_msghdr linux_msghdr; 167 | typedef struct linux_sockaddr linux_sockaddr; 168 | typedef struct linux_sockaddr_in linux_sockaddr_in; 169 | typedef struct linux_sockaddr_in6 linux_sockaddr_in6; 170 | typedef struct linux_sockaddr_un linux_sockaddr_un; 171 | 172 | int linux_to_native_sock_type(int linux_type); 173 | int native_to_linux_sock_type(int linux_type); 174 | 175 | void linux_to_native_sockaddr_in(struct sockaddr_in* dest, const linux_sockaddr_in* src); 176 | void native_to_linux_sockaddr_in(linux_sockaddr_in* dest, const struct sockaddr_in* src); 177 | 178 | void linux_to_native_sockaddr_in6(struct sockaddr_in6* dest, const linux_sockaddr_in6* src); 179 | void native_to_linux_sockaddr_in6(linux_sockaddr_in6* dest, const struct sockaddr_in6* src); 180 | 181 | void linux_to_native_sockaddr_un(struct sockaddr_un* dest, const linux_sockaddr_un* src); 182 | void native_to_linux_sockaddr_un(linux_sockaddr_un* dest, const struct sockaddr_un* src); 183 | -------------------------------------------------------------------------------- /src/libc/sys/stat.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "../../shim.h" 9 | #include "stat.h" 10 | 11 | void copy_stat_buf(linux_stat* dst, struct stat* src) { 12 | 13 | memset(dst, 0, sizeof(linux_stat)); 14 | 15 | dst->st_dev = src->st_dev; 16 | dst->st_ino = src->st_ino; 17 | dst->st_nlink = src->st_nlink; 18 | dst->st_mode = src->st_mode; 19 | dst->st_uid = src->st_uid; 20 | dst->st_gid = src->st_gid; 21 | dst->st_rdev = src->st_rdev; 22 | dst->st_size = src->st_size; 23 | dst->st_blksize = src->st_blksize; 24 | dst->st_blocks = src->st_blocks; 25 | dst->st_atim.tv_sec = src->st_atim.tv_sec; 26 | dst->st_atim.tv_nsec = src->st_atim.tv_nsec; 27 | dst->st_mtim.tv_sec = src->st_mtim.tv_sec; 28 | dst->st_mtim.tv_nsec = src->st_mtim.tv_nsec; 29 | dst->st_ctim.tv_sec = src->st_ctim.tv_sec; 30 | dst->st_ctim.tv_nsec = src->st_ctim.tv_nsec; 31 | } 32 | 33 | void copy_stat_buf64(linux_stat64* dst, struct stat* src) { 34 | 35 | memset(dst, 0, sizeof(linux_stat64)); 36 | 37 | dst->st_dev = src->st_dev; 38 | dst->st_ino = src->st_ino; 39 | dst->st_nlink = src->st_nlink; 40 | dst->st_mode = src->st_mode; 41 | dst->st_uid = src->st_uid; 42 | dst->st_gid = src->st_gid; 43 | dst->st_rdev = src->st_rdev; 44 | dst->st_size = src->st_size; 45 | dst->st_blksize = src->st_blksize; 46 | dst->st_blocks = src->st_blocks; 47 | dst->st_atim.tv_sec = src->st_atim.tv_sec; 48 | dst->st_atim.tv_nsec = src->st_atim.tv_nsec; 49 | dst->st_mtim.tv_sec = src->st_mtim.tv_sec; 50 | dst->st_mtim.tv_nsec = src->st_mtim.tv_nsec; 51 | dst->st_ctim.tv_sec = src->st_ctim.tv_sec; 52 | dst->st_ctim.tv_nsec = src->st_ctim.tv_nsec; 53 | } 54 | 55 | static int shim___fxstat_impl(int ver, int fd, linux_stat* stat_buf) { 56 | 57 | struct stat sb; 58 | 59 | int err = fstat(fd, &sb); 60 | if (err == 0) { 61 | copy_stat_buf(stat_buf, &sb); 62 | } 63 | 64 | return err; 65 | } 66 | 67 | static int shim___fxstat64_impl(int ver, int fd, linux_stat64* stat_buf) { 68 | 69 | struct stat sb; 70 | 71 | int err = fstat(fd, &sb); 72 | if (err == 0) { 73 | copy_stat_buf64(stat_buf, &sb); 74 | } 75 | 76 | return err; 77 | } 78 | 79 | #define LINUX_AT_SYMLINK_NOFOLLOW 0x0100 80 | #define LINUX_AT_EMPTY_PATH 0x1000 81 | 82 | #define KNOWN_LINUX_AT_FLAGS (LINUX_AT_SYMLINK_NOFOLLOW | LINUX_AT_EMPTY_PATH) 83 | 84 | static int linux_to_native_fstatat_flags(int linux_flags) { 85 | 86 | assert((linux_flags & ~KNOWN_LINUX_AT_FLAGS) == 0); 87 | 88 | int flags = 0; 89 | 90 | if (linux_flags & LINUX_AT_SYMLINK_NOFOLLOW) flags |= AT_SYMLINK_NOFOLLOW; 91 | if (linux_flags & LINUX_AT_EMPTY_PATH) flags |= AT_EMPTY_PATH; 92 | 93 | return flags; 94 | } 95 | 96 | static int shim___fxstatat64_impl(int ver, int dirfd, const char* path, linux_stat64* stat_buf, int linux_flags) { 97 | 98 | struct stat sb; 99 | 100 | int err = fstatat(dirfd, path, &sb, linux_to_native_fstatat_flags(linux_flags)); 101 | if (err == 0) { 102 | copy_stat_buf64(stat_buf, &sb); 103 | } 104 | 105 | return err; 106 | } 107 | 108 | static int shim___lxstat_impl(int ver, const char* path, linux_stat* stat_buf) { 109 | 110 | struct stat sb; 111 | 112 | int err = lstat(redirect(path), &sb); 113 | if (err == 0) { 114 | copy_stat_buf(stat_buf, &sb); 115 | } 116 | 117 | return err; 118 | } 119 | 120 | static int shim___lxstat64_impl(int ver, const char* path, linux_stat64* stat_buf) { 121 | 122 | struct stat sb; 123 | 124 | int err = lstat(redirect(path), &sb); 125 | if (err == 0) { 126 | copy_stat_buf64(stat_buf, &sb); 127 | } 128 | 129 | return err; 130 | } 131 | 132 | static int shim___xmknod_impl(int ver, const char* path, linux_mode_t mode, dev_t* dev) { 133 | UNIMPLEMENTED(); 134 | } 135 | 136 | static uint64_t make_dev_id(uint32_t major, uint32_t minor) { 137 | return 138 | (((uint64_t)(major & 0x00000fffu)) << 8) | 139 | (((uint64_t)(major & 0xfffff000u)) << 32) | 140 | (((uint64_t)(minor & 0x000000ffu)) << 0) | 141 | (((uint64_t)(minor & 0xffffff00u)) << 12); 142 | } 143 | 144 | #define FIX_NV_DEV_ID(path, stat_buf) \ 145 | if (str_starts_with(path, "/dev/nvidia")) { \ 146 | switch (path[sizeof("/dev/nvidia") - 1]) { \ 147 | case 'c': stat_buf->st_rdev = make_dev_id(195, 255); break; \ 148 | case '-': stat_buf->st_rdev = make_dev_id(195, 254); break; \ 149 | default: \ 150 | errno = 0; \ 151 | unsigned long i = strtoul(&path[sizeof("/dev/nvidia") - 1], NULL, 10); \ 152 | if (errno != ERANGE && errno != EINVAL) { \ 153 | assert(i < 254); \ 154 | stat_buf->st_rdev = make_dev_id(195, i); \ 155 | } \ 156 | } \ 157 | } 158 | 159 | static int shim___xstat_impl(int ver, const char* path, linux_stat* stat_buf) { 160 | 161 | struct stat sb; 162 | 163 | int err = stat(path, &sb); 164 | if (err == 0) { 165 | copy_stat_buf(stat_buf, &sb); 166 | FIX_NV_DEV_ID(path, stat_buf); 167 | } 168 | 169 | return err; 170 | } 171 | 172 | static int shim___xstat64_impl(int ver, const char* path, linux_stat64* stat_buf) { 173 | 174 | struct stat sb; 175 | 176 | int err = stat(path, &sb); 177 | if (err == 0) { 178 | copy_stat_buf64(stat_buf, &sb); 179 | FIX_NV_DEV_ID(path, stat_buf); 180 | } 181 | 182 | return err; 183 | } 184 | 185 | static int shim_chmod_impl(const char* path, linux_mode_t mode) { 186 | assert(!str_starts_with(path, "/dev/")); 187 | return chmod(path, mode); 188 | } 189 | 190 | SHIM_WRAP(__fxstat); 191 | SHIM_WRAP(__fxstat64); 192 | SHIM_WRAP(__fxstatat64); 193 | SHIM_WRAP(__lxstat); 194 | SHIM_WRAP(__lxstat64); 195 | SHIM_WRAP(__xmknod); 196 | SHIM_WRAP(__xstat); 197 | SHIM_WRAP(__xstat64); 198 | SHIM_WRAP(chmod); 199 | -------------------------------------------------------------------------------- /src/libc/sys/stat.h: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../../shim.h" 3 | #include "../time.h" 4 | 5 | #ifdef __i386__ 6 | 7 | struct linux_stat { 8 | uint64_t st_dev; 9 | uint8_t _pad1[4]; 10 | uint32_t st_ino; 11 | uint32_t st_mode; 12 | uint32_t st_nlink; 13 | uint32_t st_uid; 14 | uint32_t st_gid; 15 | uint64_t st_rdev; 16 | uint8_t _pad2[4]; 17 | uint32_t st_size; 18 | uint32_t st_blksize; 19 | uint32_t st_blocks; 20 | linux_timespec st_atim; 21 | linux_timespec st_mtim; 22 | linux_timespec st_ctim; 23 | uint8_t _pad3[8]; 24 | }; 25 | 26 | struct linux_stat64 { 27 | uint64_t st_dev; 28 | uint8_t _pad1[8]; 29 | uint32_t st_mode; 30 | uint32_t st_nlink; 31 | uint32_t st_uid; 32 | uint32_t st_gid; 33 | uint64_t st_rdev; 34 | uint8_t _pad2[4]; 35 | int64_t st_size; 36 | uint32_t st_blksize; 37 | uint64_t st_blocks; 38 | linux_timespec st_atim; 39 | linux_timespec st_mtim; 40 | linux_timespec st_ctim; 41 | uint64_t st_ino; 42 | }; 43 | 44 | typedef struct linux_stat linux_stat; 45 | typedef struct linux_stat64 linux_stat64; 46 | 47 | #endif 48 | 49 | #ifdef __x86_64__ 50 | 51 | struct linux_stat { 52 | uint64_t st_dev; 53 | uint64_t st_ino; 54 | uint64_t st_nlink; 55 | uint32_t st_mode; 56 | uint32_t st_uid; 57 | uint32_t st_gid; 58 | uint8_t _pad1[4]; 59 | uint64_t st_rdev; 60 | int64_t st_size; 61 | int64_t st_blksize; 62 | int64_t st_blocks; 63 | linux_timespec st_atim; 64 | linux_timespec st_mtim; 65 | linux_timespec st_ctim; 66 | uint8_t _pad2[24]; 67 | }; 68 | 69 | typedef struct linux_stat linux_stat; 70 | typedef struct linux_stat linux_stat64; 71 | 72 | #endif 73 | -------------------------------------------------------------------------------- /src/libc/sys/statvfs.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../../shim.h" 3 | 4 | #ifdef __i386__ 5 | struct linux_statvfs64 { 6 | uint32_t f_bsize; 7 | uint32_t f_frsize; 8 | uint64_t f_blocks; 9 | uint64_t f_bfree; 10 | uint64_t f_bavail; 11 | uint64_t f_files; 12 | uint64_t f_ffree; 13 | uint64_t f_favail; 14 | uint32_t f_fsid; 15 | uint8_t _pad1[4]; 16 | uint32_t f_flag; 17 | uint32_t f_namemax; 18 | uint8_t _pad2[24]; 19 | }; 20 | #endif 21 | 22 | #ifdef __x86_64__ 23 | struct linux_statvfs64 { 24 | uint64_t f_bsize; 25 | uint64_t f_frsize; 26 | uint64_t f_blocks; 27 | uint64_t f_bfree; 28 | uint64_t f_bavail; 29 | uint64_t f_files; 30 | uint64_t f_ffree; 31 | uint64_t f_favail; 32 | uint64_t f_fsid; 33 | uint64_t f_flag; 34 | uint64_t f_namemax; 35 | uint8_t _pad[24]; 36 | }; 37 | #endif 38 | 39 | typedef struct linux_statvfs64 linux_statvfs64; 40 | 41 | #define LINUX_ST_RDONLY 1 42 | #define LINUX_ST_NOSUID 2 43 | 44 | static int shim_statvfs64_impl(const char* restrict path, linux_statvfs64* restrict linux_buf) { 45 | 46 | struct statvfs buf; 47 | int err = statvfs(path, &buf); 48 | if (err == 0) { 49 | linux_buf->f_bsize = buf.f_bsize; 50 | linux_buf->f_frsize = buf.f_frsize; 51 | 52 | linux_buf->f_blocks = buf.f_blocks; 53 | linux_buf->f_bfree = buf.f_bfree; 54 | linux_buf->f_bavail = buf.f_bavail; 55 | 56 | linux_buf->f_files = buf.f_files; 57 | linux_buf->f_ffree = buf.f_ffree; 58 | linux_buf->f_favail = buf.f_favail; 59 | 60 | linux_buf->f_fsid = 0; 61 | 62 | linux_buf->f_flag = 0; 63 | if (buf.f_flag & ST_RDONLY) { 64 | linux_buf->f_flag |= LINUX_ST_RDONLY; 65 | } 66 | if (buf.f_flag & ST_NOSUID) { 67 | linux_buf->f_flag |= LINUX_ST_NOSUID; 68 | } 69 | 70 | linux_buf->f_namemax = buf.f_namemax; 71 | } 72 | 73 | return err; 74 | } 75 | 76 | SHIM_WRAP(statvfs64); 77 | -------------------------------------------------------------------------------- /src/libc/sys/syscall.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "../time.h" 15 | #include "../../shim.h" 16 | 17 | #ifdef __i386__ 18 | #define LINUX_FORK 2 19 | #define LINUX_WRITE 4 20 | #define LINUX_OPEN 5 21 | #define LINUX_GETPID 20 22 | #define LINUX_CAPGET 184 23 | #define LINUX_GETTID 224 24 | #define LINUX_FUTEX 240 25 | #define LINUX_CLOCK_GETTIME 265 26 | #define LINUX_TGKILL 270 27 | #define LINUX_GET_ROBUST_LIST 312 28 | #define LINUX_PIPE2 331 29 | #define LINUX_GETRANDOM 355 30 | #define LINUX_MEMFD_CREATE 356 31 | #endif 32 | 33 | #ifdef __x86_64__ 34 | #define LINUX_WRITE 1 35 | #define LINUX_OPEN 2 36 | #define LINUX_MMAP 9 37 | #define LINUX_GETPID 39 38 | #define LINUX_FORK 57 39 | #define LINUX_CAPGET 125 40 | #define LINUX_GETTID 186 41 | #define LINUX_FUTEX 202 42 | #define LINUX_CLOCK_GETTIME 228 43 | #define LINUX_TGKILL 234 44 | #define LINUX_GET_ROBUST_LIST 274 45 | #define LINUX_PIPE2 293 46 | #define LINUX_GETRANDOM 318 47 | #define LINUX_MEMFD_CREATE 319 48 | #endif 49 | 50 | #define LINUX_MFD_CLOEXEC 0x01 51 | #define LINUX_MFD_ALLOW_SEALING 0x02 52 | #define LINUX_MFD_EXEC 0x10 53 | 54 | void* shim_mmap_impl(void*, size_t, int, int, int, linux_off_t); 55 | int shim_open_impl(const char*, int, va_list); 56 | 57 | static long shim_syscall_impl(long number, va_list args) { 58 | 59 | if (number == LINUX_WRITE) { 60 | 61 | int fd = va_arg(args, int); 62 | void* buf = va_arg(args, void*); 63 | size_t nbytes = va_arg(args, size_t); 64 | 65 | LOG("%s: write(%d, %p, %zu)", __func__, fd, buf, nbytes); 66 | 67 | extern ssize_t (*libepoll_epoll_shim_write)(int, const void*, size_t); 68 | 69 | int n = libepoll_epoll_shim_write(fd, buf, nbytes); 70 | LOG("%s: write -> %d", __func__, n); 71 | 72 | return n; 73 | } 74 | 75 | if (number == LINUX_OPEN) { 76 | 77 | char* path = va_arg(args, void*); 78 | int flags = va_arg(args, int); 79 | 80 | LOG("%s: open(\"%s\", 0x%x, ...)", __func__, path, flags); 81 | 82 | int fd = shim_open_impl(path, flags, args); 83 | LOG("%s: open -> %d", __func__, fd); 84 | 85 | return fd; 86 | } 87 | 88 | #ifdef __x86_64__ 89 | if (number == LINUX_MMAP) { 90 | void* addr = va_arg(args, void*); 91 | size_t len = va_arg(args, size_t); 92 | int prot = va_arg(args, int); 93 | int flags = va_arg(args, int); 94 | int fd = va_arg(args, int); 95 | linux_off_t pgoffset = va_arg(args, linux_off_t); 96 | 97 | LOG("%s: mmap(%p, %zu, %d, %d, %d, %ld)", __func__, addr, len, prot, flags, fd, pgoffset); 98 | 99 | void* p = shim_mmap_impl(addr, len, prot, flags, fd, pgoffset); 100 | LOG("%s: mmap -> %p", __func__, p); 101 | 102 | return (uintptr_t)p; 103 | } 104 | #endif 105 | 106 | if (number == LINUX_GETPID) { 107 | 108 | LOG("%s: getpid()", __func__); 109 | 110 | pid_t pid = getpid(); 111 | LOG("%s: getpid -> %d", __func__, pid); 112 | 113 | return pid; 114 | } 115 | 116 | if (number == LINUX_FORK) { 117 | 118 | LOG("%s: fork()", __func__); 119 | 120 | pid_t pid = fork(); 121 | LOG("%s: fork -> %d", __func__, pid); 122 | 123 | return pid; 124 | } 125 | 126 | if (number == LINUX_GETTID) { 127 | 128 | LOG("%s: gettid()", __func__); 129 | 130 | int tid = pthread_getthreadid_np(); 131 | LOG("%s: gettid -> %d", __func__, tid); 132 | 133 | return tid; 134 | } 135 | 136 | if (number == LINUX_CAPGET) { 137 | LOG("%s: capget(...)", __func__); 138 | errno = native_to_linux_errno(EPERM); 139 | return -1; 140 | } 141 | 142 | if (number == LINUX_FUTEX) { 143 | 144 | #define FUTEX_WAIT_PRIVATE 0x80 145 | #define FUTEX_WAKE_PRIVATE 0x81 146 | 147 | uint32_t* uaddr = va_arg(args, uint32_t*); 148 | int futex_op = va_arg(args, int); 149 | uint32_t val = va_arg(args, uint32_t); 150 | linux_timespec* timeout = va_arg(args, linux_timespec*); 151 | #ifdef DEBUG 152 | uint32_t* uaddr2 = va_arg(args, uint32_t*); 153 | uint32_t val3 = va_arg(args, uint32_t); 154 | #endif 155 | 156 | LOG("%s: futex(%p, op = %#x, val = %d, timeout = %p, uaddr2 = %p, val3 = %d)", __func__, uaddr, futex_op, val, timeout, uaddr2, val3); 157 | 158 | int err; 159 | switch (futex_op) { 160 | case FUTEX_WAIT_PRIVATE: 161 | err = _umtx_op(uaddr, UMTX_OP_WAIT, val, (void*)sizeof(struct timespec), timeout); 162 | break; 163 | case FUTEX_WAKE_PRIVATE: 164 | err = _umtx_op(uaddr, UMTX_OP_WAKE, val, NULL, NULL); 165 | break; 166 | default: 167 | err = -1; 168 | errno = ENOSYS; 169 | } 170 | 171 | if (err == -1) { 172 | errno = native_to_linux_errno(errno); 173 | } 174 | 175 | return err; 176 | } 177 | 178 | if (number == LINUX_CLOCK_GETTIME) { 179 | 180 | linux_clockid_t clock_id = va_arg(args, linux_clockid_t); 181 | linux_timespec* tp = va_arg(args, linux_timespec*); 182 | 183 | LOG("%s: clock_gettime(%d, %p)", __func__, clock_id, tp); 184 | 185 | int err = shim_clock_gettime_impl(clock_id, tp); 186 | LOG("%s: clock_gettime -> %d", __func__, err); 187 | 188 | return err; 189 | } 190 | 191 | if (number == LINUX_TGKILL) { 192 | 193 | pid_t tgid = va_arg(args, pid_t); 194 | pid_t tid = va_arg(args, pid_t); 195 | int sig = va_arg(args, int); 196 | 197 | LOG("%s: tgkill(%d, %d, %d)", __func__, tgid, tid, sig); 198 | 199 | assert(tgid == getpid()); 200 | assert(sig == 0); 201 | 202 | int err = thr_kill(tid, sig); 203 | LOG("%s: tgkill -> %d", __func__, err); 204 | 205 | return err; 206 | } 207 | 208 | if (number == LINUX_GET_ROBUST_LIST) { 209 | 210 | typedef void robust_list_head; 211 | 212 | int get_robust_list(int, robust_list_head**, size_t*); 213 | 214 | int pid = va_arg(args, int); 215 | robust_list_head** list_head = va_arg(args, robust_list_head**); 216 | size_t* struct_len = va_arg(args, size_t*); 217 | 218 | #if DEBUG 219 | LOG("%s: get_robust_list(%d, %p, %p)\n", __func__, pid, list_head, struct_len); 220 | #else 221 | fprintf(stderr, "%s [get_robust_list]: nothing to see here, move along\n", __func__); 222 | #endif 223 | 224 | int err = get_robust_list(pid, list_head, struct_len); 225 | LOG("%s: get_robust_list -> %d", __func__, err); 226 | 227 | return err; 228 | } 229 | 230 | if (number == LINUX_PIPE2) { 231 | 232 | int shim_pipe2_impl(int[2], int); 233 | 234 | int* fds = va_arg(args, int*); 235 | int flags = va_arg(args, int); 236 | 237 | LOG("%s: pipe2(%p, %d)", __func__, fds, flags); 238 | 239 | int err = shim_pipe2_impl(fds, flags); 240 | LOG("%s: pipe2 -> %d ({%d, %d})", __func__, err, fds[0], fds[1]); 241 | 242 | return err; 243 | } 244 | 245 | if (number == LINUX_GETRANDOM) { 246 | 247 | void* buf = va_arg(args, void*); 248 | size_t buflen = va_arg(args, size_t); 249 | int flags = va_arg(args, unsigned int); 250 | 251 | LOG("%s: getrandom(%p, %zd, %#x)", __func__, buf, buflen, flags); 252 | 253 | int err = getrandom(buf, buflen, flags /* same values */); 254 | LOG("%s: getrandom -> %d", __func__, err); 255 | 256 | return err; 257 | } 258 | 259 | if (number == LINUX_MEMFD_CREATE) { 260 | char* name = va_arg(args, char*); 261 | int linux_flags = va_arg(args, int); 262 | 263 | LOG("%s: memfd_create(\"%s\", 0x%x)", __func__, name, linux_flags); 264 | 265 | assert((linux_flags & ~(LINUX_MFD_CLOEXEC | LINUX_MFD_ALLOW_SEALING | LINUX_MFD_EXEC)) == 0); 266 | 267 | int flags = 0; 268 | if (linux_flags & LINUX_MFD_CLOEXEC) flags |= MFD_CLOEXEC; 269 | if (linux_flags & LINUX_MFD_ALLOW_SEALING) flags |= MFD_ALLOW_SEALING; 270 | 271 | int err = memfd_create(name, flags); 272 | 273 | LOG("%s: memfd_create -> %d", __func__, err); 274 | 275 | return err; 276 | } 277 | 278 | UNIMPLEMENTED_ARGS("%ld, ...", number); 279 | } 280 | 281 | SHIM_WRAP(syscall); 282 | -------------------------------------------------------------------------------- /src/libc/sys/sysctl.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "../../shim.h" 7 | 8 | static int shim_sysctl_impl(int* name, int namelen, void* oldp, size_t* oldlenp, void* newp, size_t newlen) { 9 | UNIMPLEMENTED(); 10 | } 11 | 12 | SHIM_WRAP(sysctl); 13 | -------------------------------------------------------------------------------- /src/libc/sys/sysinfo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../../shim.h" 4 | 5 | static int shim_get_nprocs_impl() { 6 | return sysconf(_SC_NPROCESSORS_CONF); 7 | } 8 | 9 | SHIM_WRAP(get_nprocs); 10 | 11 | static int shim_sysinfo_impl(void* info) { 12 | return -1; 13 | } 14 | 15 | SHIM_WRAP(sysinfo); 16 | -------------------------------------------------------------------------------- /src/libc/sys/utsname.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../../shim.h" 4 | #include "utsname.h" 5 | 6 | static int shim_uname_impl(struct linux_utsname* linux_name) { 7 | 8 | struct utsname name; 9 | 10 | int err = uname(&name); 11 | if (err == 0) { 12 | memset(linux_name, 0, sizeof(struct linux_utsname)); 13 | 14 | strlcpy(linux_name->machine, 15 | #ifdef __x86_64__ 16 | "x86_64" 17 | #elif defined(__i386__) 18 | access("/libexec/ld-elf32.so.1", F_OK) == 0 ? "x86_64" : name.machine 19 | #else 20 | name.machine 21 | #endif 22 | , 65); 23 | 24 | strlcpy(linux_name->sysname, name.sysname, 65); 25 | strlcpy(linux_name->nodename, name.nodename, 65); 26 | strlcpy(linux_name->release, name.release, 65); 27 | strlcpy(linux_name->version, name.version, 65); 28 | strlcpy(linux_name->domainname, "", 65); 29 | } 30 | 31 | return err; 32 | } 33 | 34 | SHIM_WRAP(uname); 35 | -------------------------------------------------------------------------------- /src/libc/sys/utsname.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | struct linux_utsname { 4 | char sysname[65]; 5 | char nodename[65]; 6 | char release[65]; 7 | char version[65]; 8 | char machine[65]; 9 | char domainname[65]; 10 | }; 11 | 12 | typedef struct linux_utsname linux_utsname; 13 | -------------------------------------------------------------------------------- /src/libc/termios.c: -------------------------------------------------------------------------------- 1 | #include "../shim.h" 2 | #include "termios.h" 3 | 4 | static int shim_tcgetattr_impl(int fd, linux_termios* t) { 5 | return -1; 6 | } 7 | 8 | SHIM_WRAP(tcgetattr); 9 | -------------------------------------------------------------------------------- /src/libc/termios.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | typedef void linux_termios; 4 | -------------------------------------------------------------------------------- /src/libc/time.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "time.h" 4 | #include "../shim.h" 5 | #include "locale.h" 6 | 7 | long shim_timezone = 0; 8 | SHIM_EXPORT(timezone); 9 | 10 | extern long shim___timezone __attribute__((alias("shim_timezone"))); 11 | SHIM_EXPORT(__timezone); 12 | 13 | int shim_daylight = 0; 14 | SHIM_EXPORT(daylight); 15 | 16 | extern int shim___daylight __attribute__((alias("shim_daylight"))); 17 | SHIM_EXPORT(__daylight); 18 | 19 | static char shim_tzname_0[] = "GMT\0\0"; 20 | static char shim_tzname_1[] = "GMT\0\0"; 21 | 22 | char* shim_tzname[2] = {shim_tzname_0, shim_tzname_1}; 23 | SHIM_EXPORT(tzname); 24 | 25 | extern char** shim___tzname __attribute__((alias("shim_tzname"))); 26 | SHIM_EXPORT(__tzname); 27 | 28 | static bool find_offset(int current_year, int current_month, bool is_dst, long* offset) { 29 | 30 | struct tm date = {0}; 31 | struct tm out; 32 | 33 | for (int year = current_year; year >= 70; year--) { 34 | for (int month = 11; month >= 5; month -= 6) { 35 | 36 | if (year == current_year && month > current_month) { 37 | continue; 38 | } 39 | 40 | date.tm_mday = 21; 41 | date.tm_mon = month; 42 | date.tm_year = year; 43 | 44 | time_t t = timegm(&date); 45 | 46 | if (localtime_r(&t, &out) == NULL) { 47 | PANIC("localtime_r"); 48 | } 49 | 50 | if (out.tm_isdst == is_dst) { 51 | if (offset != NULL) { 52 | *offset = out.tm_gmtoff; 53 | } 54 | return true; 55 | } 56 | } 57 | } 58 | 59 | return false; 60 | } 61 | 62 | static void shim_tzset_impl() { 63 | 64 | tzset(); 65 | 66 | strlcpy(shim_tzname_0, tzname[0], sizeof(shim_tzname_0)); 67 | strlcpy(shim_tzname_1, tzname[1], sizeof(shim_tzname_1)); 68 | 69 | time_t t = time(NULL); 70 | 71 | struct tm lt; 72 | if (localtime_r(&t, <) == NULL) { 73 | PANIC("localtime_r"); 74 | } 75 | 76 | int current_year = lt.tm_year; 77 | int current_month = lt.tm_mon; 78 | 79 | long timezone; 80 | if (find_offset(current_year, current_month, 0, &timezone)) { 81 | timezone = -timezone; 82 | } else { 83 | timezone = 0; 84 | } 85 | 86 | *globals.timezone = timezone; 87 | *globals.__timezone = timezone; 88 | 89 | int daylight; 90 | if (find_offset(current_year, current_month, 1, NULL)) { 91 | daylight = 1; 92 | } else { 93 | daylight = 0; 94 | } 95 | 96 | *globals.daylight = daylight; 97 | *globals.__daylight = daylight; 98 | } 99 | 100 | SHIM_WRAP(tzset); 101 | 102 | #ifndef CLOCK_BOOTTIME 103 | #define CLOCK_BOOTTIME CLOCK_UPTIME 104 | #endif 105 | 106 | static clockid_t linux_to_native_clockid(linux_clockid_t linux_clock_id) { 107 | switch (linux_clock_id) { 108 | case LINUX_CLOCK_REALTIME: return CLOCK_REALTIME; 109 | case LINUX_CLOCK_MONOTONIC: return CLOCK_MONOTONIC; 110 | case LINUX_CLOCK_MONOTONIC_RAW: return CLOCK_MONOTONIC_FAST; 111 | case LINUX_CLOCK_REALTIME_COARSE: return CLOCK_REALTIME_FAST; 112 | case LINUX_CLOCK_MONOTONIC_COARSE: return CLOCK_MONOTONIC_FAST; 113 | case LINUX_CLOCK_BOOTTIME: return CLOCK_BOOTTIME; 114 | default: 115 | UNIMPLEMENTED_ARGS("%d", linux_clock_id); 116 | } 117 | } 118 | 119 | int shim_clock_gettime_impl(linux_clockid_t linux_clock_id, linux_timespec* tp) { 120 | return clock_gettime(linux_to_native_clockid(linux_clock_id), tp); 121 | } 122 | 123 | SHIM_WRAP(clock_gettime); 124 | 125 | static size_t shim___strftime_l_impl(char* restrict buf, size_t maxsize, const char* restrict format, const linux_tm* restrict timeptr, linux_locale_t loc) { 126 | return strftime_l(buf, maxsize, format, timeptr, loc->native_locale); 127 | } 128 | 129 | static size_t shim_strftime_l_impl(char* restrict buf, size_t maxsize, const char* restrict format, const linux_tm* restrict timeptr, linux_locale_t loc) { 130 | return strftime_l(buf, maxsize, format, timeptr, loc->native_locale); 131 | } 132 | 133 | static char* shim_strptime_l_impl(const char* restrict buf, const char* restrict format, linux_tm* restrict timeptr, linux_locale_t loc) { 134 | return strptime_l(buf, format, timeptr, loc->native_locale); 135 | } 136 | 137 | SHIM_WRAP(__strftime_l); 138 | SHIM_WRAP(strftime_l); 139 | SHIM_WRAP(strptime_l); 140 | -------------------------------------------------------------------------------- /src/libc/time.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #define LINUX_CLOCK_REALTIME 0 6 | #define LINUX_CLOCK_MONOTONIC 1 7 | #define LINUX_CLOCK_MONOTONIC_RAW 4 8 | #define LINUX_CLOCK_REALTIME_COARSE 5 9 | #define LINUX_CLOCK_MONOTONIC_COARSE 6 10 | #define LINUX_CLOCK_BOOTTIME 7 11 | 12 | typedef clockid_t linux_clockid_t; 13 | 14 | typedef struct timespec linux_timespec; 15 | typedef struct timeval linux_timeval; 16 | typedef struct timezone linux_timezone; 17 | typedef struct tm linux_tm; 18 | 19 | int shim_clock_gettime_impl(linux_clockid_t clock_id, linux_timespec* tp); 20 | -------------------------------------------------------------------------------- /src/libc/ucontext.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../shim.h" 3 | 4 | // Breakpad 5 | int shim_getcontext_impl(ucontext_t* ucp) { 6 | return -1; 7 | } 8 | 9 | SHIM_WRAP(getcontext); 10 | -------------------------------------------------------------------------------- /src/libc/unistd.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include "../shim.h" 13 | #include "fcntl.h" 14 | 15 | static int shim_chown_impl(const char* path, uid_t owner, gid_t group) { 16 | assert(!str_starts_with(path, "/dev/")); 17 | return chown(path, owner, group); 18 | } 19 | 20 | static ssize_t shim_readlink_impl(const char* path, char* buf, size_t bufsize) { 21 | 22 | if (str_starts_with(path, "/proc/")) { 23 | 24 | char* p = strdup(&path[sizeof("/proc/") - 1]); 25 | assert(p != NULL); 26 | 27 | char* s = p; 28 | char* node = strsep(&s, "/"); 29 | char* entry = strsep(&s, "/"); 30 | 31 | if (strcmp(entry, "exe") == 0) { 32 | 33 | int pid; 34 | if (strcmp(node, "self") == 0) { 35 | pid = -1; 36 | } else { 37 | pid = strtoul(node, NULL, 10); 38 | assert(pid > 0); 39 | } 40 | 41 | free(p); 42 | 43 | if ((pid == -1 || pid == getpid()) && proc_self_exe_override != NULL) { 44 | size_t nchars = strlen(proc_self_exe_override); 45 | strncpy(buf, proc_self_exe_override, nchars < bufsize ? nchars : bufsize); 46 | return nchars < bufsize ? nchars : bufsize; 47 | } else { 48 | int name[] = { 49 | CTL_KERN, 50 | KERN_PROC, 51 | KERN_PROC_PATHNAME, 52 | pid 53 | }; 54 | 55 | int err = sysctl(name, nitems(name), buf, &bufsize, NULL, 0); 56 | if (err == -1) { 57 | // we don't care about emulating silent truncation here 58 | errno = native_to_linux_errno(errno); 59 | return -1; 60 | } 61 | 62 | return bufsize - 1; // length without a nul char 63 | } 64 | 65 | } else { 66 | 67 | free(p); 68 | 69 | errno = native_to_linux_errno(EACCES); 70 | return -1; 71 | } 72 | } 73 | 74 | if (str_starts_with(path, "/sys/")) { 75 | errno = native_to_linux_errno(EACCES); 76 | return -1; 77 | } 78 | 79 | return readlink(path, buf, bufsize); 80 | } 81 | 82 | //~ int shim_execl_impl(const char* path, const char* arg, va_list args) { 83 | //~ UNIMPLEMENTED(); 84 | //~ } 85 | 86 | //~ int shim_execle_impl(const char* path, const char* arg, va_list args) { 87 | //~ UNIMPLEMENTED(); 88 | //~ } 89 | 90 | //~ int shim_execlp_impl(const char* file, const char* arg, va_list args) { 91 | //~ UNIMPLEMENTED(); 92 | //~ } 93 | 94 | #define GLIBC_SC_PAGESIZE 30 95 | #define GLIBC_SC_NPROCESSORS_CONF 83 96 | #define GLIBC_SC_NPROCESSORS_ONLN 84 97 | #define GLIBC_SC_PHYS_PAGES 85 98 | #define GLIBC_SC_MONOTONIC_CLOCK 149 99 | 100 | static long shim_sysconf_impl(int name) { 101 | 102 | if (name == GLIBC_SC_NPROCESSORS_CONF) { 103 | return sysconf(_SC_NPROCESSORS_CONF); 104 | } 105 | 106 | if (name == GLIBC_SC_NPROCESSORS_ONLN) { 107 | return sysconf(_SC_NPROCESSORS_ONLN); 108 | } 109 | 110 | if (name == GLIBC_SC_PAGESIZE) { 111 | return sysconf(_SC_PAGESIZE); 112 | } 113 | 114 | if (name == GLIBC_SC_PHYS_PAGES) { 115 | return sysconf(_SC_PHYS_PAGES); 116 | } 117 | 118 | if (name == GLIBC_SC_MONOTONIC_CLOCK) { 119 | return sysconf(_SC_MONOTONIC_CLOCK); 120 | } 121 | 122 | UNIMPLEMENTED_ARGS("%d", name); 123 | } 124 | 125 | static int shim_ftruncate64_impl(int fd, linux_off64_t length) { 126 | return ftruncate(fd, length); 127 | } 128 | 129 | SHIM_WRAP(chown); 130 | SHIM_WRAP(ftruncate64); 131 | SHIM_WRAP(readlink); 132 | SHIM_WRAP(sysconf); 133 | 134 | int shim_pipe2_impl(int fildes[2], int linux_flags) { 135 | 136 | assert((linux_flags & (LINUX_O_CLOEXEC | LINUX_O_NONBLOCK)) == linux_flags); 137 | 138 | int flags = 0; 139 | 140 | if (linux_flags & LINUX_O_NONBLOCK) flags |= O_NONBLOCK; 141 | if (linux_flags & LINUX_O_CLOEXEC) flags |= O_CLOEXEC; 142 | 143 | return pipe2(fildes, flags); 144 | } 145 | 146 | SHIM_WRAP(pipe2); 147 | 148 | static linux_off64_t shim_lseek64_impl(int fd, linux_off64_t offset, int whence) { 149 | return lseek(fd, offset, whence); 150 | } 151 | 152 | SHIM_WRAP(lseek64); 153 | 154 | static int shim_getopt_impl(int argc, char* const argv[], const char* optstring) { 155 | 156 | optind = *globals.optind; 157 | opterr = *globals.opterr; 158 | 159 | int err = getopt(argc, argv, optstring); 160 | 161 | *globals.optarg = optarg; 162 | *globals.optind = optind; 163 | *globals.optopt = optopt; 164 | 165 | return err; 166 | } 167 | 168 | SHIM_WRAP(getopt); 169 | 170 | static int shim_access_impl(const char* path, int mode) { 171 | 172 | char* p = redirect(path); 173 | if (p == NULL) { 174 | errno = EACCES; 175 | return -1; 176 | } 177 | 178 | return access(p, mode); 179 | } 180 | 181 | SHIM_WRAP(access); 182 | 183 | extern ssize_t (*libepoll_epoll_shim_read) (int, void*, size_t); 184 | extern ssize_t (*libepoll_epoll_shim_write)(int, const void*, size_t); 185 | extern int (*libepoll_epoll_shim_close)(int); 186 | 187 | static ssize_t shim_read_impl(int fd, void *buf, size_t nbytes) { 188 | return libepoll_epoll_shim_read(fd, buf, nbytes); 189 | } 190 | 191 | static ssize_t shim_write_impl(int fd, const void* buf, size_t nbytes) { 192 | return libepoll_epoll_shim_write(fd, buf, nbytes); 193 | } 194 | 195 | static int shim_close_impl(int fd) { 196 | return libepoll_epoll_shim_close(fd); 197 | } 198 | 199 | SHIM_WRAP(read); 200 | SHIM_WRAP(write); 201 | SHIM_WRAP(close); 202 | -------------------------------------------------------------------------------- /src/libc/wctype.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../shim.h" 3 | #include "locale.h" 4 | 5 | static wctype_t shim___wctype_l_impl(const char* property, linux_locale_t locale) { 6 | return wctype_l(property, locale->native_locale); 7 | } 8 | 9 | SHIM_WRAP(__wctype_l); 10 | 11 | static int shim_iswalnum_l_impl(wint_t wc, linux_locale_t loc) { 12 | return iswalnum_l(wc, loc->native_locale); 13 | } 14 | 15 | static int shim_iswalpha_l_impl(wint_t wc, linux_locale_t loc) { 16 | return iswalpha_l(wc, loc->native_locale); 17 | } 18 | 19 | static int shim_iswblank_l_impl(wint_t wc, linux_locale_t loc) { 20 | return iswblank_l(wc, loc->native_locale); 21 | } 22 | 23 | static int shim_iswcntrl_l_impl(wint_t wc, linux_locale_t loc) { 24 | return iswcntrl_l(wc, loc->native_locale); 25 | } 26 | 27 | static int shim_iswdigit_l_impl(wint_t wc, linux_locale_t loc) { 28 | return iswdigit_l(wc, loc->native_locale); 29 | } 30 | 31 | static int shim_iswgraph_l_impl(wint_t wc, linux_locale_t loc) { 32 | return iswgraph_l(wc, loc->native_locale); 33 | } 34 | 35 | static int shim_iswlower_l_impl(wint_t wc, linux_locale_t loc) { 36 | return iswlower_l(wc, loc->native_locale); 37 | } 38 | 39 | static int shim_iswprint_l_impl(wint_t wc, linux_locale_t loc) { 40 | return iswprint_l(wc, loc->native_locale); 41 | } 42 | 43 | static int shim_iswpunct_l_impl(wint_t wc, linux_locale_t loc) { 44 | return iswpunct_l(wc, loc->native_locale); 45 | } 46 | 47 | static int shim_iswspace_l_impl(wint_t wc, linux_locale_t loc) { 48 | return iswspace_l(wc, loc->native_locale); 49 | } 50 | 51 | static int shim_iswupper_l_impl(wint_t wc, linux_locale_t loc) { 52 | return iswupper_l(wc, loc->native_locale); 53 | } 54 | 55 | static int shim_iswxdigit_l_impl(wint_t wc, linux_locale_t loc) { 56 | return iswxdigit_l(wc, loc->native_locale); 57 | } 58 | 59 | SHIM_WRAP(iswalnum_l); 60 | SHIM_WRAP(iswalpha_l); 61 | SHIM_WRAP(iswblank_l); 62 | SHIM_WRAP(iswcntrl_l); 63 | SHIM_WRAP(iswdigit_l); 64 | SHIM_WRAP(iswgraph_l); 65 | SHIM_WRAP(iswlower_l); 66 | SHIM_WRAP(iswprint_l); 67 | SHIM_WRAP(iswpunct_l); 68 | SHIM_WRAP(iswspace_l); 69 | SHIM_WRAP(iswupper_l); 70 | SHIM_WRAP(iswxdigit_l); 71 | 72 | static wint_t shim_towctrans_l_impl(wint_t wc, wctrans_t _arg_2, linux_locale_t loc) { 73 | return towctrans_l(wc, _arg_2, loc->native_locale); 74 | } 75 | 76 | static wint_t shim_towlower_l_impl(wint_t wc, linux_locale_t loc) { 77 | return towlower_l(wc, loc->native_locale); 78 | } 79 | 80 | static wint_t shim_towupper_l_impl(wint_t wc, linux_locale_t loc) { 81 | return towupper_l(wc, loc->native_locale); 82 | } 83 | 84 | static wctrans_t shim_wctrans_l_impl(const char* _arg_1, linux_locale_t loc) { 85 | return wctrans_l(_arg_1, loc->native_locale); 86 | } 87 | 88 | SHIM_WRAP(towctrans_l); 89 | SHIM_WRAP(towlower_l); 90 | SHIM_WRAP(towupper_l); 91 | SHIM_WRAP(wctrans_l); 92 | -------------------------------------------------------------------------------- /src/libexecinfo/execinfo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "../shim.h" 5 | 6 | //~ size_t shim_backtrace_impl(void** addrlist, size_t len) { 7 | //~ UNIMPLEMENTED(); 8 | //~ } 9 | -------------------------------------------------------------------------------- /src/libm/fenv.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "../shim.h" 3 | 4 | #define LINUX_FE_DFL_ENV ((const fenv_t*)-1) 5 | 6 | static int shim_fesetenv_impl(const fenv_t* envp) { 7 | if (envp == LINUX_FE_DFL_ENV) { 8 | return fesetenv(FE_DFL_ENV); 9 | } else { 10 | return fesetenv(envp); 11 | } 12 | } 13 | 14 | SHIM_WRAP(fesetenv); 15 | -------------------------------------------------------------------------------- /src/libm/math.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "../shim.h" 4 | 5 | static int shim___isinf_impl(double arg) { 6 | return isinf(arg); 7 | } 8 | 9 | static int shim___isinff_impl(float arg) { 10 | return isinf(arg); 11 | } 12 | 13 | static int shim___isnan_impl(double arg) { 14 | return isnan(arg); 15 | } 16 | 17 | static int shim___isnanf_impl(float arg) { 18 | return isnanf(arg); 19 | } 20 | 21 | static int shim___finitef_impl(float x) { 22 | return isfinite(x); 23 | } 24 | 25 | static int shim_finite_impl(double x) { 26 | return isfinite(x); 27 | } 28 | 29 | static int shim___signbitf_impl(float x) { 30 | return signbit(x); 31 | } 32 | 33 | static int shim___signbit_impl(double x) { 34 | return signbit(x); 35 | } 36 | 37 | #ifdef __i386__ 38 | 39 | static int64_t shim___divdi3_impl(int64_t a, int64_t b) { 40 | return a / b; 41 | } 42 | 43 | static uint64_t shim___udivdi3_impl(uint64_t a, uint64_t b) { 44 | return a / b; 45 | } 46 | 47 | static int64_t shim___moddi3_impl(int64_t a, int64_t b) { 48 | return a % b; 49 | } 50 | 51 | static uint64_t shim___umoddi3_impl(uint64_t a, uint64_t b) { 52 | return a % b; 53 | } 54 | 55 | SHIM_WRAP(__divdi3); 56 | SHIM_WRAP(__udivdi3); 57 | SHIM_WRAP(__moddi3); 58 | SHIM_WRAP(__umoddi3); 59 | 60 | #endif // __i386__ 61 | 62 | SHIM_WRAP(__isinf); 63 | SHIM_WRAP(__isinff); 64 | 65 | #ifdef SHIM_SCAN 66 | #undef __isnan 67 | #undef __isnanf 68 | SHIM_WRAP(__isnan); 69 | SHIM_WRAP(__isnanf); 70 | #else 71 | SHIM_WRAPPER___isnan 72 | SHIM_WRAPPER___isnanf 73 | #endif 74 | 75 | SHIM_WRAP(__finitef); 76 | SHIM_WRAP(finite); 77 | SHIM_WRAP(__signbitf); 78 | SHIM_WRAP(__signbit); 79 | -------------------------------------------------------------------------------- /src/libthr/pthread.h: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #define LINUX_PTHREAD_CANCELED ((void*)-1) 4 | 5 | struct shim_pthread_mutex { 6 | pthread_mutex_t _wrapped_mutex; 7 | uint32_t _pad[2]; 8 | uint32_t linux_kind; 9 | }; 10 | 11 | typedef struct shim_pthread_mutex linux_pthread_mutex_t; 12 | 13 | #ifdef __i386__ 14 | _Static_assert(sizeof(struct shim_pthread_mutex) <= 24 /* sizeof(pthread_mutex_t) on glibc/Linux */, ""); 15 | #endif 16 | 17 | #ifdef __x86_64__ 18 | _Static_assert(sizeof(struct shim_pthread_mutex) <= 40 /* sizeof(pthread_mutex_t) on glibc/Linux */, ""); 19 | #endif 20 | 21 | typedef uint32_t linux_pthread_barrierattr_t; 22 | typedef uint32_t linux_pthread_condattr_t; 23 | typedef uint32_t linux_pthread_mutexattr_t; 24 | typedef uint32_t linux_pthread_once_t; 25 | 26 | _Static_assert(sizeof(pthread_rwlockattr_t) <= 8 /* sizeof(pthread_rwlockattr_t) on glibc/Linux */, ""); 27 | 28 | typedef pthread_rwlockattr_t linux_pthread_rwlockattr_t; 29 | 30 | enum linux_pthread_mutextype { 31 | LINUX_PTHREAD_MUTEX_NORMAL = 0, 32 | LINUX_PTHREAD_MUTEX_RECURSIVE = 1, 33 | LINUX_PTHREAD_MUTEX_ERRORCHECK = 2, 34 | LINUX_PTHREAD_MUTEX_ADAPTIVE_NP = 3 35 | }; 36 | 37 | enum linux_pthread_inheritsched { 38 | LINUX_PTHREAD_INHERIT_SCHED = 0, 39 | LINUX_PTHREAD_EXPLICIT_SCHED = 1 40 | }; 41 | 42 | enum linux_pthread_contentionscope { 43 | LINUX_PTHREAD_SCOPE_SYSTEM = 0, 44 | LINUX_PTHREAD_SCOPE_PROCESS = 1 45 | }; 46 | -------------------------------------------------------------------------------- /src/main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "shim.h" 16 | 17 | // necessary for the rtld's direct execution mode 18 | char** environ = NULL; 19 | char* __progname = ""; 20 | 21 | struct globals globals; 22 | 23 | static char** shim_env = NULL; 24 | static int shim_argc = 0; 25 | static char** shim_argv = NULL; 26 | 27 | // we don't route fread/fwrite through libepoll-shim, should we? 28 | int (*libepoll_epoll_create) (int); 29 | int (*libepoll_epoll_create1) (int); 30 | int (*libepoll_epoll_ctl) (int, int, int, struct epoll_event*); 31 | int (*libepoll_epoll_wait) (int, struct epoll_event*, int, int); 32 | int (*libepoll_epoll_pwait) (int, struct epoll_event*, int, int, const sigset_t*); 33 | ssize_t (*libepoll_epoll_shim_read) (int, void*, size_t); 34 | ssize_t (*libepoll_epoll_shim_write)(int, const void*, size_t); 35 | int (*libepoll_epoll_shim_close)(int); 36 | int (*libepoll_epoll_shim_poll) (struct pollfd[], nfds_t, int); 37 | int (*libepoll_epoll_shim_ppoll)(struct pollfd[], nfds_t, const struct timespec* restrict, const sigset_t* restrict); 38 | int (*libepoll_epoll_shim_fcntl)(int, int, ...); 39 | 40 | static int dummy() { 41 | return -1; 42 | } 43 | 44 | __attribute__((constructor(101))) 45 | static void shim_init(int argc, char** argv, char** env) { 46 | 47 | Link_map* link_map = NULL; 48 | 49 | int err = dlinfo(RTLD_SELF, RTLD_DI_LINKMAP, &link_map); 50 | assert(err == 0); 51 | 52 | fprintf(stderr, "%s: shim init\n", link_map->l_name); 53 | 54 | char* short_program_name = basename(argv[0]); 55 | 56 | #define G(var, version, value)\ 57 | globals.var = dlvsym(RTLD_DEFAULT, #var, version); assert(globals.var != NULL); \ 58 | *globals.var = value; 59 | 60 | #ifdef __amd64__ 61 | G(_IO_2_1_stderr_, "GLIBC_2.2.5", stderr); 62 | G(_IO_2_1_stdin_, "GLIBC_2.2.5", stdin); 63 | G(_IO_2_1_stdout_, "GLIBC_2.2.5", stdout); 64 | G(__daylight, "GLIBC_2.2.5", 0); 65 | G(daylight, "GLIBC_2.2.5", 0); 66 | G(__environ, "GLIBC_2.2.5", env); 67 | G(_environ, "GLIBC_2.2.5", env); 68 | G(environ, "GLIBC_2.2.5", env); 69 | G(stderr, "GLIBC_2.2.5", stderr); 70 | G(stdin, "GLIBC_2.2.5", stdin); 71 | G(stdout, "GLIBC_2.2.5", stdout); 72 | G(optarg, "GLIBC_2.2.5", NULL); 73 | G(opterr, "GLIBC_2.2.5", 1); 74 | G(optind, "GLIBC_2.2.5", 1); 75 | G(optopt, "GLIBC_2.2.5", 0); 76 | G(__progname, "GLIBC_2.2.5", short_program_name); 77 | G(__progname_full, "GLIBC_2.2.5", argv[0]); 78 | G(program_invocation_name, "GLIBC_2.2.5", argv[0]); 79 | G(program_invocation_short_name, "GLIBC_2.2.5", short_program_name); 80 | G(__timezone, "GLIBC_2.2.5", 0); 81 | G(timezone, "GLIBC_2.2.5", 0); 82 | #endif 83 | 84 | #ifdef __i386__ 85 | G(_IO_stderr_, "GLIBC_2.0", stderr); 86 | G(_IO_stdin_, "GLIBC_2.0", stdin); 87 | G(_IO_stdout_, "GLIBC_2.0", stdout); 88 | G(_IO_2_1_stderr_, "GLIBC_2.1", stderr); 89 | G(_IO_2_1_stdin_, "GLIBC_2.1", stdin); 90 | G(_IO_2_1_stdout_, "GLIBC_2.1", stdout); 91 | G(__daylight, "GLIBC_2.0", 0); 92 | G(daylight, "GLIBC_2.0", 0); 93 | G(__environ, "GLIBC_2.0", env); 94 | G(_environ, "GLIBC_2.0", env); 95 | G(environ, "GLIBC_2.0", env); 96 | G(stderr, "GLIBC_2.0", stderr); 97 | G(stdin, "GLIBC_2.0", stdin); 98 | G(stdout, "GLIBC_2.0", stdout); 99 | G(optarg, "GLIBC_2.0", NULL); 100 | G(opterr, "GLIBC_2.0", 1); 101 | G(optind, "GLIBC_2.0", 1); 102 | G(optopt, "GLIBC_2.0", 0); 103 | G(__progname, "GLIBC_2.0", short_program_name); 104 | G(__progname_full, "GLIBC_2.0", argv[0]); 105 | G(program_invocation_name, "GLIBC_2.0", argv[0]); 106 | G(program_invocation_short_name, "GLIBC_2.0", short_program_name); 107 | G(__timezone, "GLIBC_2.0", 0); 108 | G(timezone, "GLIBC_2.0", 0); 109 | #endif 110 | 111 | #undef G 112 | 113 | shim_env = env; 114 | shim_argc = argc; 115 | shim_argv = argv; 116 | 117 | void* libepoll = dlopen("libepoll-shim.so.0", RTLD_LAZY); 118 | if (libepoll != NULL) { 119 | #define E(sym) libepoll_##sym = dlsym(libepoll, #sym); assert(libepoll_##sym != NULL); 120 | E(epoll_create); 121 | E(epoll_create1); 122 | E(epoll_ctl); 123 | E(epoll_wait); 124 | E(epoll_pwait); 125 | E(epoll_shim_read); 126 | E(epoll_shim_write); 127 | E(epoll_shim_close); 128 | E(epoll_shim_poll); 129 | E(epoll_shim_ppoll); 130 | E(epoll_shim_fcntl); 131 | #undef E 132 | } else { 133 | fprintf(stderr, "%s: unable to load libepoll-shim.so.0 (%s)\n", link_map->l_name, dlerror()); 134 | libepoll_epoll_create = dummy; 135 | libepoll_epoll_create1 = dummy; 136 | libepoll_epoll_ctl = dummy; 137 | libepoll_epoll_wait = dummy; 138 | libepoll_epoll_pwait = dummy; 139 | libepoll_epoll_shim_read = read; 140 | libepoll_epoll_shim_write = write; 141 | libepoll_epoll_shim_close = close; 142 | libepoll_epoll_shim_poll = poll; 143 | libepoll_epoll_shim_ppoll = ppoll; 144 | libepoll_epoll_shim_fcntl = fcntl; 145 | } 146 | } 147 | 148 | extern int __cxa_atexit(void (*)(void*), void*, void*); 149 | 150 | #ifdef __i386__ 151 | struct wrapper_args { 152 | void (*cb)(void*); 153 | void* arg; 154 | }; 155 | 156 | // helps with stack alignment crashes in steamclient.so 157 | static void __cxa_atexit_cb_wrapper(void* arg) { 158 | LOG_ENTRY("%p", arg); 159 | struct wrapper_args* wargs = (struct wrapper_args*)arg; 160 | LOG("cb = %p, arg = %p", wargs->cb, wargs->arg); 161 | wargs->cb(wargs->arg); 162 | free(wargs); 163 | LOG_EXIT(); 164 | } 165 | 166 | static int shim___cxa_atexit_impl(void (*cb)(void*), void* arg, void* dso) { 167 | struct wrapper_args* wargs = malloc(sizeof(struct wrapper_args)); 168 | wargs->cb = cb; 169 | wargs->arg = arg; 170 | return __cxa_atexit(__cxa_atexit_cb_wrapper, wargs, dso); 171 | } 172 | #else 173 | static int shim___cxa_atexit_impl(void (*cb)(void*), void* arg, void* dso) { 174 | return __cxa_atexit(cb, arg, dso); 175 | } 176 | #endif 177 | 178 | extern void __cxa_finalize(void*); 179 | 180 | static void shim___cxa_finalize_impl(void* dso) { 181 | __cxa_finalize(dso); 182 | } 183 | 184 | extern void __libc_start1(int, char*[], char*[], void (*)(void), int (*)(int, char*[], char*[])); 185 | 186 | static void dummy_cleanup() { 187 | // do nothing 188 | } 189 | 190 | void shim___libc_start_main( 191 | int (*main)(int, char**, char**), 192 | int argc, 193 | char** ubp_av, 194 | void (*init)(int, char**, char**), 195 | void (*fini)(void), 196 | void (*rtld_fini)(void), 197 | void* stack_end 198 | ) { 199 | LOG_ENTRY("main: %p, argc: %#x, upb_av: %p, init: %p, fini: %p, rtld_fini: %p, stack_end: %p", main, argc, ubp_av, init, fini, rtld_fini, stack_end); 200 | 201 | assert(init != NULL); 202 | assert(fini != NULL); 203 | 204 | init(shim_argc, shim_argv, shim_env); 205 | atexit(fini); 206 | 207 | __libc_start1(shim_argc, shim_argv, shim_env, dummy_cleanup, main); 208 | } 209 | 210 | static void shim___stack_chk_fail_impl() { 211 | assert(0); 212 | } 213 | 214 | static int shim___register_atfork_impl(void (*prepare)(void), void (*parent)(void), void (*child)(void), void* dso_handle) { 215 | return pthread_atfork(prepare, parent, child); 216 | } 217 | 218 | static char* shim_gnu_get_libc_version_impl() { 219 | return "2.17"; 220 | } 221 | 222 | SHIM_WRAP(__cxa_atexit); 223 | SHIM_WRAP(__cxa_finalize); 224 | SHIM_EXPORT(__libc_start_main); 225 | SHIM_WRAP(__stack_chk_fail); 226 | SHIM_WRAP(__register_atfork); 227 | SHIM_WRAP(gnu_get_libc_version); 228 | 229 | extern void* __tls_get_addr(void*); 230 | 231 | __attribute__((__regparm__(1))) 232 | void* shim___tls_get_addr(void* ti) { 233 | return __tls_get_addr(ti); 234 | } 235 | 236 | extern __typeof(shim___tls_get_addr) shim____tls_get_addr __attribute__((alias("shim___tls_get_addr"))); 237 | 238 | __asm__(".symver shim___tls_get_addr,__tls_get_addr@GLIBC_2.3"); 239 | __asm__(".symver shim____tls_get_addr,___tls_get_addr@GLIBC_2.3"); 240 | 241 | #define LINUX_AT_SYSINFO_EHDR 33 242 | 243 | static unsigned long shim_getauxval_impl(unsigned long type) { 244 | assert(type == LINUX_AT_SYSINFO_EHDR); 245 | return 0; 246 | } 247 | 248 | SHIM_WRAP(getauxval); 249 | -------------------------------------------------------------------------------- /src/shim.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #define __HEAD(head, ...) head 12 | #define __TAIL(head, ...) __VA_ARGS__ 13 | 14 | #define __OPT_TAIL(head, ...) __VA_OPT__(,) __VA_ARGS__ 15 | 16 | #ifdef DEBUG 17 | 18 | #include 19 | #include 20 | 21 | extern __thread int what_was_that_error; 22 | 23 | #define LOG(...) (\ 24 | what_was_that_error = errno,\ 25 | fprintf(stderr, "[%d:%d] " __HEAD(__VA_ARGS__) "\n", getpid(), pthread_getthreadid_np(), __TAIL(__VA_ARGS__)),\ 26 | errno = what_was_that_error\ 27 | ) 28 | 29 | #define LOG_ENTRY(fmt, ...) __builtin_choose_expr(__builtin_strcmp("" fmt, "") == 0, LOG("%s()", __func__), LOG("%s(" fmt ")", __func__, ## __VA_ARGS__)) 30 | #define LOG_EXIT( fmt, ...) __builtin_choose_expr(__builtin_strcmp("" fmt, "") == 0, LOG("%s -> void", __func__), LOG("%s -> " fmt, __func__, ## __VA_ARGS__)) 31 | 32 | #else 33 | 34 | #define LOG(...) 35 | #define LOG_ENTRY(fmt, ...) 36 | #define LOG_EXIT( fmt, ...) 37 | 38 | #endif 39 | 40 | #define UNIMPLEMENTED() {\ 41 | fprintf(stderr, "%s is not implemented\n", __func__);\ 42 | void* buffer[100];\ 43 | int nframes = backtrace(buffer, 100);\ 44 | backtrace_symbols_fd(buffer, nframes, STDERR_FILENO);\ 45 | abort();\ 46 | } 47 | 48 | #define UNIMPLEMENTED_ARGS(...) {\ 49 | fprintf(stderr, "%s(" __HEAD(__VA_ARGS__) ") is not implemented\n", __func__, __TAIL(__VA_ARGS__));\ 50 | void* buffer[100];\ 51 | int nframes = backtrace(buffer, 100);\ 52 | backtrace_symbols_fd(buffer, nframes, STDERR_FILENO);\ 53 | abort();\ 54 | } 55 | 56 | #define PANIC(...) {\ 57 | fprintf(stderr, "%s: " __HEAD(__VA_ARGS__) "\n", __func__ __OPT_TAIL(__VA_ARGS__));\ 58 | void* buffer[100];\ 59 | int nframes = backtrace(buffer, 100);\ 60 | backtrace_symbols_fd(buffer, nframes, STDERR_FILENO);\ 61 | abort();\ 62 | } 63 | 64 | #ifndef SHIM_EXPORT 65 | #define SHIM_EXPORT(sym) SHIM_EXPORT_ ##sym 66 | #endif 67 | 68 | #ifndef SHIM_WRAP 69 | #define SHIM_WRAP(fun, ...) SHIM_WRAPPER_ ##fun 70 | #endif 71 | 72 | bool str_starts_with(const char* str, const char* substr); 73 | 74 | int native_to_linux_errno(int error); 75 | int linux_to_native_errno(int error); 76 | 77 | const char* redirect(const char* path); 78 | 79 | extern char* proc_self_exe_override; 80 | 81 | struct globals { 82 | #ifdef __i386__ 83 | FILE** _IO_stderr_; 84 | FILE** _IO_stdin_; 85 | FILE** _IO_stdout_; 86 | #endif 87 | FILE** _IO_2_1_stderr_; 88 | FILE** _IO_2_1_stdin_; 89 | FILE** _IO_2_1_stdout_; 90 | int* __daylight; 91 | int* daylight; 92 | char*** __environ; 93 | char*** _environ; 94 | char*** environ; 95 | FILE** stdin; 96 | FILE** stderr; 97 | FILE** stdout; 98 | char** optarg; 99 | int* opterr; 100 | int* optind; 101 | int* optopt; 102 | char** __progname; 103 | char** __progname_full; 104 | char** program_invocation_name; 105 | char** program_invocation_short_name; 106 | long* __timezone; 107 | long* timezone; 108 | }; 109 | 110 | extern struct globals globals; 111 | 112 | typedef int32_t linux_mode_t; 113 | 114 | typedef int64_t linux_off64_t; 115 | 116 | #ifdef __i386__ 117 | typedef int32_t linux_off_t; 118 | #endif 119 | 120 | #ifdef __x86_64__ 121 | typedef int64_t linux_off_t; 122 | #endif 123 | 124 | #include 125 | 126 | typedef struct option linux_option; 127 | 128 | #include 129 | #include 130 | #include 131 | 132 | typedef struct rusage linux_rusage; 133 | 134 | #include 135 | 136 | typedef struct pollfd linux_pollfd; 137 | 138 | struct linux_sysinfo; 139 | 140 | typedef struct linux_sysinfo linux_sysinfo; 141 | 142 | #include 143 | 144 | typedef struct dl_phdr_info linux_dl_phdr_info; 145 | 146 | _Static_assert(sizeof(fpos_t) <= 12 /* sizeof(fpos_t) on glibc/Linux with i386 */, ""); 147 | 148 | typedef fpos_t linux_fpos_t; 149 | typedef fpos_t linux_fpos64_t; 150 | 151 | #include 152 | 153 | typedef struct utimbuf linux_utimbuf; 154 | -------------------------------------------------------------------------------- /src/shim.map: -------------------------------------------------------------------------------- 1 | SHIM { global: shim_*; __progname; environ; local: *; }; 2 | 3 | GLIBC_2.0 {} SHIM; 4 | GLIBC_2.1 {} SHIM; 5 | GLIBC_2.1.1 {} SHIM; 6 | GLIBC_2.1.2 {} SHIM; 7 | GLIBC_2.1.3 {} SHIM; 8 | GLIBC_2.2 {} SHIM; 9 | GLIBC_2.2.1 {} SHIM; 10 | GLIBC_2.2.2 {} SHIM; 11 | GLIBC_2.2.3 {} SHIM; 12 | GLIBC_2.2.4 {} SHIM; 13 | GLIBC_2.2.5 {} SHIM; 14 | GLIBC_2.2.6 {} SHIM; 15 | GLIBC_2.3 {} SHIM; 16 | GLIBC_2.3.2 {} SHIM; 17 | GLIBC_2.3.3 {} SHIM; 18 | GLIBC_2.3.4 {} SHIM; 19 | GLIBC_2.4 {} SHIM; 20 | GLIBC_2.5 {} SHIM; 21 | GLIBC_2.6 {} SHIM; 22 | GLIBC_2.7 {} SHIM; 23 | GLIBC_2.8 {} SHIM; 24 | GLIBC_2.9 {} SHIM; 25 | GLIBC_2.10 {} SHIM; 26 | GLIBC_2.11 {} SHIM; 27 | GLIBC_2.12 {} SHIM; 28 | GLIBC_2.13 {} SHIM; 29 | GLIBC_2.14 {} SHIM; 30 | GLIBC_2.15 {} SHIM; 31 | GLIBC_2.16 {} SHIM; 32 | GLIBC_2.17 {} SHIM; 33 | GLIBC_2.18 {} SHIM; 34 | GLIBC_2.22 {} SHIM; 35 | GLIBC_2.23 {} SHIM; 36 | GLIBC_2.24 {} SHIM; 37 | GLIBC_2.25 {} SHIM; 38 | GLIBC_2.26 {} SHIM; 39 | GLIBC_2.27 {} SHIM; 40 | GLIBC_2.28 {} SHIM; 41 | GLIBC_2.29 {} SHIM; 42 | GLIBC_2.30 {} SHIM; 43 | GLIBC_2.31 {} SHIM; 44 | GLIBC_2.32 {} SHIM; 45 | GLIBC_2.33 {} SHIM; 46 | GLIBC_2.34 {} SHIM; 47 | GLIBC_2.35 {} SHIM; 48 | 49 | # libexecinfo.so.1 brings _Unwind_Find_FDE@@GCC_3.0 (through libgcc_s.so.1) 50 | # as required by 32-bit libnvidia-{glvkspirv.so,gpucomp.so} and lsteamclient.dll.so 51 | # we still need this line, though 52 | 53 | GCC_3.0 {}; 54 | 55 | # we don't export any FBSD symbols, but due to a librt.so.1 name collision 56 | # we still must pass a dynamic linker's sanity check 57 | 58 | FBSD_1.0 {}; 59 | -------------------------------------------------------------------------------- /src/util.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include "shim.h" 10 | 11 | #ifdef DEBUG 12 | __thread int what_was_that_error; 13 | #endif 14 | 15 | bool str_starts_with(const char* str, const char* substr) { 16 | return strncmp(str, substr, strlen(substr)) == 0; 17 | } 18 | 19 | #define LINUX_EAGAIN 11 20 | #define LINUX_ENOSYS 38 21 | #define LINUX_ETIMEDOUT 110 22 | 23 | int native_to_linux_errno(int error) { 24 | switch (error) { 25 | case EAGAIN: return LINUX_EAGAIN; 26 | case ENOSYS: return LINUX_ENOSYS; 27 | case ETIMEDOUT: return LINUX_ETIMEDOUT; 28 | //TODO: anything else? 29 | default: 30 | return error; 31 | } 32 | } 33 | 34 | int linux_to_native_errno(int error) { 35 | switch (error) { 36 | case LINUX_EAGAIN: return EAGAIN; 37 | case LINUX_ENOSYS: return ENOSYS; 38 | case LINUX_ETIMEDOUT: return ETIMEDOUT; 39 | default: 40 | return error; 41 | } 42 | } 43 | 44 | static char** procfs_redirects = NULL; 45 | 46 | __attribute__((constructor)) 47 | static void init_redirects() { 48 | 49 | int capacity = 5; 50 | procfs_redirects = malloc(sizeof(char*) * capacity); 51 | 52 | char linux_emul_path[MAXPATHLEN]; 53 | size_t linux_emul_path_size = MAXPATHLEN; 54 | 55 | int err = sysctlbyname("compat.linux.emul_path", linux_emul_path, &linux_emul_path_size, NULL, 0); 56 | assert(err == 0); 57 | 58 | int i = 0; 59 | 60 | // CUDA init 61 | procfs_redirects[i++] = "/proc/self/maps"; 62 | procfs_redirects[i++] = "/dev/null"; 63 | 64 | // Steam 65 | //~ asprintf(&procfs_redirects[i++], "/proc/%d/status", getpid()); 66 | //~ asprintf(&procfs_redirects[i++], "%s/proc/%d/status", linux_emul_path, getpid()); 67 | 68 | procfs_redirects[i++] = "/proc/cpuinfo"; 69 | asprintf(&procfs_redirects[i++], "%s/%s", linux_emul_path, "/proc/cpuinfo"); 70 | 71 | //~ procfs_redirects[i++] = "/proc/net/route"; 72 | //~ asprintf(&procfs_redirects[i++], "%s/%s", linux_emul_path, "/proc/net/route"); 73 | 74 | //~ procfs_redirects[i++] = "/proc/version"; 75 | //~ asprintf(&procfs_redirects[i++], "%s/%s", linux_emul_path, "/proc/version"); 76 | 77 | procfs_redirects[i++] = NULL; 78 | assert(i <= capacity); 79 | } 80 | 81 | const char* redirect(const char* path) { 82 | 83 | if (strcmp("/dev/nvidia-uvm", path) == 0) { 84 | return "/dev/null"; 85 | } 86 | 87 | if (str_starts_with(path, "/proc/")) { 88 | 89 | for (int i = 0; procfs_redirects[i] != NULL; i += 2) { 90 | if (strcmp(path, procfs_redirects[i]) == 0) { 91 | return procfs_redirects[i + 1]; 92 | } 93 | } 94 | 95 | return NULL; 96 | } 97 | 98 | if (str_starts_with(path, "/sys/")) { 99 | return NULL; 100 | } 101 | 102 | // Steam 103 | if (strcmp(path, "/etc/ssl/certs/ca-certificates.crt") == 0) { 104 | return "/etc/ssl/cert.pem"; 105 | } 106 | 107 | return path; 108 | } 109 | 110 | char* proc_self_exe_override = NULL; 111 | 112 | __attribute__((constructor)) 113 | static void init_proc_self_exe_override() { 114 | proc_self_exe_override = getenv("SHIM_PROC_SELF_EXE"); 115 | } 116 | -------------------------------------------------------------------------------- /utils/find_glibc_symbols.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: utf-8 3 | 4 | symbols = {} 5 | 6 | libs = [] 7 | for lib in ['libc.so.6', 'libm.so.6', 'libdl.so.2', 'libresolv.so.2', 'librt.so.1', 'libpthread.so.0'] 8 | libs << (ARGV.include?('-32') ? "/compat/linux/lib/#{lib}" : "/compat/linux/lib64/#{lib}") 9 | end 10 | 11 | for lib in libs 12 | for line in `readelf -s #{lib}`.lines 13 | if !(line =~ /(UND|LOCAL)/) && line =~ /\s(\w+)@@?(GLIBC_[0-9\.]+)/i 14 | 15 | name = $1 16 | version = $2 17 | type = 18 | case line.split(/\s+/)[4] 19 | when 'FUNC' then :fun 20 | when 'IFUNC' then :fun 21 | when 'OS+0' then :fun 22 | when 'OBJECT' then :obj 23 | else 24 | raise 25 | end 26 | 27 | if not symbols[name] 28 | symbols[name] = {versions: [], type: type} 29 | end 30 | 31 | if not symbols[name][:versions].include?(version) 32 | symbols[name][:versions] << version 33 | end 34 | end 35 | end 36 | end 37 | 38 | for sym in symbols.keys.sort 39 | print symbols[sym][:type], ' ', sym, ': ', symbols[sym][:versions].sort.join(', '), "\n" 40 | end 41 | -------------------------------------------------------------------------------- /utils/prototype-check.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: UTF-8 3 | 4 | LINUX = true 5 | 6 | require(__dir__ + '/../src/prototypes.rb') 7 | 8 | puts < 1 && function[:args].last[:name] == '...' 84 | end 85 | 86 | FUNCTION_POINTER_TYPE = /^(.+)?\(([\*\^])\)\s*(\([^\)]+\))$/ 87 | 88 | def to_shim_type(type) 89 | case type 90 | when 'cpu_set_t*' 91 | 'linux_cpu_set_t*' 92 | when /glob(64|)_t\*(\srestrict|)/ 93 | "linux_glob#{$1}_t*#{$2}" 94 | when 'mode_t' 95 | 'linux_mode_t' 96 | when 'off_t' 97 | 'linux_off_t' 98 | when 'off64_t' 99 | 'linux_off64_t' 100 | when 'fpos_t*' 101 | 'linux_fpos_t*' 102 | when 'fpos64_t*' 103 | 'linux_fpos64_t*' 104 | when 'DIR*' 105 | 'linux_DIR*' 106 | when 'locale_t' 107 | 'linux_locale_t' 108 | when 'pthread_once_t*' 109 | 'linux_pthread_once_t*' 110 | when 'pthread_mutex_t*' 111 | 'linux_pthread_mutex_t*' 112 | when /^(const |)pthread_(barrier|cond|mutex|rwlock)attr_t\*/ 113 | $1 + 'linux_pthread_' + $2 + 'attr_t*' 114 | when /(^|\s)(stack_t|sigset_t)($|[^\w_])/ 115 | type.gsub(/(^|\s)(stack_t|sigset_t)($|[^\w_])/) { "#{$1}linux_#{$2}#{$3}" } 116 | else 117 | type.gsub(/struct\s+/, 'linux_') 118 | end 119 | end 120 | 121 | def generate_wrapper(out, function, shim_fun_impl) 122 | 123 | args = function[:args] 124 | args = [] if args.size == 1 && args.first[:type] == 'void' 125 | 126 | def to_decl(arg) 127 | case arg[:type] 128 | when /^(.+?)\s?(\[(\d*|restrict)\])$/ 129 | "#{$1} #{arg[:name]}#{$2}" 130 | when FUNCTION_POINTER_TYPE 131 | "#{to_shim_type($1)}(#{$2}#{arg[:name]})#{to_shim_type($3)}" 132 | else 133 | "#{arg[:type] ? to_shim_type(arg[:type]) : ''} #{arg[:name]}" 134 | end 135 | end 136 | 137 | out.puts to_shim_type(function[:type]) + ' shim_' + function[:name] + '(' + function[:args].map(&method(:to_decl)).join(', ') + ') {' 138 | 139 | out.puts ' ' + log_args(args) 140 | 141 | if is_variadic(function) 142 | out.puts " va_list _args_;" 143 | out.puts " va_start(_args_, #{args[-2][:name]});" 144 | end 145 | 146 | if function[:type] != 'void' 147 | out.puts " #{to_shim_type(function[:type])} _ret_ = " 148 | end 149 | 150 | if shim_fun_impl 151 | out.print " #{shim_fun_impl}" 152 | else 153 | out.print ' ' 154 | if is_variadic(function) 155 | out.print 'v' 156 | end 157 | out.print function[:name] 158 | end 159 | out.print '(' 160 | out.print (args.map do |arg| 161 | if arg[:name] == '...' 162 | '_args_' 163 | else 164 | arg[:name] 165 | end 166 | end).join(', ') 167 | out.puts ');' 168 | 169 | if is_variadic(function) 170 | out.puts ' va_end(_args_);' 171 | end 172 | 173 | out.puts ' ' + log_result(function) 174 | 175 | if function[:type] != 'void' 176 | out.puts ' return _ret_;' 177 | end 178 | 179 | out.puts '}' 180 | end 181 | -------------------------------------------------------------------------------- /utils/wrappers_c.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: UTF-8 3 | 4 | SUBSTITUTIONS = { 5 | __getdelim: 'getdelim', 6 | __isoc99_sscanf: 'sscanf', 7 | __libc_free: 'free', 8 | __libc_malloc: 'malloc', 9 | __strdup: 'strdup', 10 | __strndup: 'strndup', 11 | _exit: '_Exit', 12 | _IO_getc: 'getc', 13 | _IO_putc: 'putc', 14 | creat64: 'creat', 15 | mkstemp64: 'mkstemp' 16 | } 17 | 18 | STRUCT_COMPATIBILITY = { 19 | FTW: true, 20 | addrinfo: false, 21 | cmsghdr: false, # compatible on i386 22 | dirent: false, 23 | dl_phdr_info: true, 24 | in_addr: true, 25 | iovec: true, 26 | hostent: true, 27 | msghdr: false, # compatible on i386 28 | option: true, 29 | passwd: false, 30 | pollfd: true, 31 | protoent: true, 32 | rlimit: false, # compatible on x86_64 33 | rusage: true, 34 | sembuf: true, 35 | sched_param: true, 36 | shmid_ds: false, 37 | sigaction: false, 38 | sockaddr: false, 39 | stat: false, 40 | statfs: false, 41 | termios: false, 42 | timespec: true, 43 | timeval: true, 44 | timezone: true, 45 | tm: true, 46 | utsname: false, 47 | stat64: false, 48 | statfs64: false, 49 | utimbuf: true 50 | } 51 | 52 | symbols = {} 53 | 54 | for line in IO.read(ARGV[0]).lines 55 | line.strip =~ /(fun|obj) (\w+): (.+)/ 56 | symbols[$2] = {type: $1, versions: $3.split(', ')} 57 | end 58 | 59 | puts < 61 | #include 62 | 63 | #include "../src/shim.h" 64 | #include "../src/libc/dirent.h" 65 | #include "../src/libc/glob.h" 66 | #include "../src/libc/locale.h" 67 | #include "../src/libc/netdb.h" 68 | #include "../src/libc/signal.h" 69 | #include "../src/libc/sched.h" 70 | #include "../src/libc/time.h" 71 | #include "../src/libc/sys/mount.h" 72 | #include "../src/libc/sys/socket.h" 73 | #include "../src/libc/sys/stat.h" 74 | #include "../src/libc/sys/utsname.h" 75 | #include "../src/libthr/pthread.h" 76 | E 77 | 78 | LINUX = false 79 | 80 | require(__dir__ + '/../src/prototypes.rb') 81 | require(__dir__ + '/wrappers.rb') 82 | 83 | def check_compat(function) 84 | 85 | return false if function[:name] =~ /^sig|signal/ && function[:name] != 'pthread_cond_signal' 86 | 87 | args = function[:args] 88 | args = [] if args.size == 1 && args.first[:type] == 'void' 89 | 90 | for type in args.map{|arg| arg[:type]} + [function[:type]] 91 | case type 92 | when /^(const |)(pthread_(barrier|cond|mutex)attr_t|pthread_mutex_t)\*/ 93 | return false 94 | when /ucontext_t/ 95 | return false 96 | when /^(const |)struct (\w+)/ 97 | 98 | struct = $2.to_sym 99 | 100 | if not STRUCT_COMPATIBILITY.keys.include?(struct) 101 | STDERR.puts "\e[31m#{$PROGRAM_NAME}: unknown struct #{struct}, skipping function #{function[:name]}\e[0m" 102 | return false 103 | end 104 | 105 | compatible = STRUCT_COMPATIBILITY[struct] 106 | if !compatible 107 | #~ STDERR.puts "\e[31m#{$PROGRAM_NAME}: found binary incompatible struct #{struct}, explicit shim impl required for function #{function[:name]}\e[0m" 108 | return false 109 | end 110 | end 111 | end 112 | 113 | true 114 | end 115 | 116 | def generate_stub(name) 117 | puts 'void shim_' + name + '() {' 118 | puts ' UNIMPLEMENTED();' 119 | puts '}' 120 | end 121 | 122 | for sym in symbols.keys 123 | 124 | puts "// #{sym}" 125 | 126 | if symbols[sym][:type] == 'fun' && !(SUBSTITUTIONS[sym.to_sym] || sym.to_sym =~ /^__libc_start_main$|setjmp/) 127 | 128 | puts "#ifndef SHIM_WRAPPER_#{sym}" 129 | puts 130 | 131 | function = $functions[sym] 132 | if function 133 | puts '// ' + function[:prototype] 134 | if !function[:lsb] && check_compat(function) 135 | for include in function[:includes] 136 | puts include 137 | end 138 | generate_wrapper(STDOUT, function, nil) 139 | else 140 | generate_stub(function[:name]) 141 | end 142 | else 143 | generate_stub(sym) 144 | end 145 | puts 146 | 147 | puts "SHIM_EXPORT(#{sym});" 148 | puts 149 | 150 | puts "#endif // SHIM_WRAPPER_#{sym}" 151 | end 152 | 153 | puts 154 | end 155 | 156 | puts 157 | 158 | for sym, subst in SUBSTITUTIONS 159 | puts "extern __typeof(shim_#{subst}) shim_#{sym} __attribute__((alias(\"shim_#{subst}\")));" 160 | puts "SHIM_EXPORT(#{sym});" 161 | end 162 | 163 | puts 164 | -------------------------------------------------------------------------------- /utils/wrappers_h.rb: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | # encoding: UTF-8 3 | 4 | require 'stringio' 5 | 6 | LINUX = false 7 | 8 | require(__dir__ + '/../src/prototypes.rb') 9 | require(__dir__ + '/wrappers.rb') 10 | 11 | CC = ENV['cc'] || 'cc' 12 | 13 | START_TAG = "@@#{rand(1_000_000_000)}{{" 14 | END_TAG = "}}@@" 15 | 16 | options, files = ARGV.partition{|arg| arg.start_with?('-')} 17 | 18 | input = `#{CC} #{options.join(' ')} -E -DSHIM_SCAN -D"SHIM_WRAP(fun, ...)=#{START_TAG} fun @opts __VA_ARGS__ #{END_TAG}" #{files.join(' ')}` 19 | 20 | input.scan(/#{START_TAG}\s([^\s]+)\s@opts(.*?)\s#{END_TAG}/m) do |function_name, options| 21 | 22 | raise "Unknown function #{function_name}" if not $functions[function_name] 23 | 24 | io = StringIO.new 25 | generate_wrapper(io, $functions[function_name], "shim_#{function_name}_impl") 26 | lines = io.string.lines 27 | 28 | puts "#define SHIM_WRAPPER_#{function_name} \\" 29 | puts lines.map{|line| line.gsub("\n", "\\\n")} 30 | puts "SHIM_EXPORT(#{function_name});" 31 | puts 32 | end 33 | --------------------------------------------------------------------------------