├── GNUmakefile ├── README.md ├── andre-apk.sh ├── android └── libwrap.c ├── default.nix └── src ├── jvm ├── jni.h ├── jvm.c └── jvm.h ├── libEGL.c ├── libOpenSLES.c ├── libandroid.c ├── libc-antiantidebug.c ├── libc-bsd.c ├── libc-ctype.h ├── libc-sha1.c ├── libc-stdio.c ├── libc-sysconf.h ├── libc-verbose.h ├── libc.c ├── libjvm-android.c ├── libjvm-java.c ├── libjvm-misc.c ├── libjvm-unity.c ├── liblog.c ├── libpthread.c ├── linker ├── NOTICE ├── README.TXT ├── bionic_tls.h ├── dlfcn.c ├── dlfcn.h ├── linker.c ├── linker.h ├── linker_debug.h ├── linker_environ.c ├── linker_environ.h ├── linker_format.h ├── rt.c ├── strlcpy.c └── strlcpy.h ├── loader.c └── wrapper ├── verbose.h ├── wrapper.c └── wrapper.h /GNUmakefile: -------------------------------------------------------------------------------- 1 | PREFIX ?= /usr/local 2 | BINDIR ?= /bin 3 | LIBDIR ?= /lib 4 | RUNTIMEDIR ?= /andre 5 | 6 | MAKEFLAGS += --no-builtin-rules 7 | 8 | WARNINGS = -Wall -Wextra -Wpedantic -Wformat=2 -Wstrict-aliasing=3 -Wstrict-overflow=3 -Wstack-usage=4096000 \ 9 | -Wfloat-equal -Wcast-align -Wpointer-arith -Wchar-subscripts -Warray-bounds=2 -Wno-unused-parameter 10 | 11 | override CFLAGS ?= -g -O2 $(WARNINGS) 12 | override CFLAGS += -std=c11 13 | override CPPFLAGS ?= -D_FORTIFY_SOURCE=2 14 | override CPPFLAGS += -Isrc -DANDROID_X86_LINKER # -DVERBOSE_FUNCTIONS 15 | 16 | bins = andre 17 | libs = runtime/libphtread.so runtime/libdl.so runtime/libc.so runtime/libandroid.so \ 18 | runtime/liblog.so runtime/libEGL.so runtime/libOpenSLES.so runtime/libjvm.so \ 19 | runtime/libjvm-java.so runtime/libjvm-android.so runtime/libjvm-unity.so \ 20 | runtime/libjvm-misc.so 21 | all: $(bins) 22 | 23 | # https://developer.android.com/ndk/guides/abis 24 | # https://android.googlesource.com/platform/ndk/+/ics-mr0/docs/STANDALONE-TOOLCHAIN.html 25 | # https://android.googlesource.com/platform/ndk/+/ics-mr0/docs/CPU-ARCH-ABIS.html 26 | # you can also try compiling with your custom ABI with the all target, 27 | # but compatibility with android binaries is not guaranteed 28 | 29 | x86: override CFLAGS += -march=i686 -mtune=intel -mssse3 -mstackrealign -mfpmath=sse -m32 30 | x86: override LDFLAGS += -march=i686 -m32 31 | x86: all 32 | 33 | x86_64: override CFLAGS += -march=x86-64 -msse4.2 -mpopcnt -m64 -mtune=intel -fPIC 34 | x86_64: override LDFLAGS += -march=x86-64 -m64 35 | x86_64: all 36 | 37 | armeabi: override CFLAGS += -march=armv5te -mthumb 38 | armeabi: override LDFLAGS += -march=armv5te 39 | armeabi: all 40 | 41 | armeabi-v7a: override CFLAGS += -march=armv7-a -mfloat-abi=softfp -mthumb 42 | armeabi-v7a: override LDFLAGS += -march=armv7-a -Wl,--fix-cortex-a8 43 | armeabi-v7a: all 44 | armeabi-v7a-neon: override CFLAGS += -mfpu=neon 45 | armeabi-v7a-neon: armeabi-v7a 46 | 47 | arm64-v8a: all 48 | 49 | %.a: 50 | $(LINK.c) -c $(filter %.c,$^) -o $@ 51 | 52 | runtime: 53 | mkdir $@ 54 | 55 | runtime/%.so: | runtime 56 | $(LINK.c) -shared $(filter %.c %.a,$^) $(LDLIBS) -o $@ 57 | 58 | $(bins): %: 59 | $(LINK.c) $(filter %.c %.a,$^) $(LDLIBS) -o $@ 60 | 61 | wrapper.a: private override CPPFLAGS += -D_GNU_SOURCE 62 | wrapper.a: private override CFLAGS += -fvisibility=hidden 63 | wrapper.a: src/wrapper/verbose.h src/wrapper/wrapper.c src/wrapper/wrapper.h 64 | 65 | runtime/libpthread.so: private override CPPFLAGS += -D_GNU_SOURCE 66 | runtime/libpthread.so: private override LDLIBS += -lpthread -lrt 67 | runtime/libpthread.so: src/libpthread.c 68 | runtime/libdl.so: private override CPPFLAGS += -D_GNU_SOURCE -DLINKER_DEBUG=1 -DRUNTIMEPATH='"$(PREFIX)$(LIBDIR)$(RUNTIMEDIR)"' 69 | runtime/libdl.so: private WARNINGS += -Wno-pedantic -Wno-variadic-macros -Wno-pointer-to-int-cast -Wno-int-to-pointer-cast 70 | runtime/libdl.so: private override LDLIBS += -ldl -lpthread 71 | runtime/libdl.so: wrapper.a src/linker/dlfcn.c src/linker/linker.c src/linker/linker_environ.c src/linker/rt.c src/linker/strlcpy.c 72 | runtime/libc.so: private override CPPFLAGS += -D_GNU_SOURCE 73 | runtime/libc.so: private override LDFLAGS += -Wl,-wrap,_IO_file_xsputn 74 | runtime/libc.so: private override CFLAGS += -Wno-deprecated-declarations 75 | runtime/libc.so: private override LDLIBS += `pkg-config --libs libbsd libunwind` 76 | runtime/libc.so: wrapper.a src/libc.c src/libc-stdio.c src/libc-sha1.c src/libc-bsd.c src/libc-antiantidebug.c 77 | runtime/libc.so: src/libc-ctype.h src/libc-sysconf.h src/libc-verbose.h 78 | runtime/libandroid.so: private override LDLIBS += `pkg-config --libs glfw3` 79 | runtime/libandroid.so: src/libandroid.c 80 | runtime/liblog.so: src/liblog.c 81 | runtime/libEGL.so: private override CPPFLAGS += -D_GNU_SOURCE 82 | runtime/libEGL.so: private override LDLIBS += -lEGL `pkg-config --libs glfw3` 83 | runtime/libEGL.so: src/libEGL.c 84 | runtime/libOpenSLES.so: private WARNINGS += -Wno-pedantic 85 | runtime/libOpenSLES.so: wrapper.a src/libOpenSLES.c 86 | 87 | runtime/libjvm.so: private override CPPFLAGS += -D_GNU_SOURCE 88 | runtime/libjvm.so: private WARNINGS += -Wno-pedantic 89 | runtime/libjvm.so: wrapper.a src/jvm/jvm.c 90 | runtime/libjvm-java.so: private override CPPFLAGS += -D_GNU_SOURCE 91 | runtime/libjvm-java.so: src/libjvm-java.c 92 | runtime/libjvm-android.so: src/libjvm-android.c 93 | runtime/libjvm-unity.so: src/libjvm-unity.c 94 | runtime/libjvm-misc.so: src/libjvm-misc.c 95 | 96 | # trick linker to link against unversioned libs 97 | libdl.so: runtime/libdl.so 98 | ln -s $< $@ 99 | libpthread.so: runtime/libpthread.so 100 | ln -s $< $@ 101 | 102 | andre: private override CPPFLAGS += -D_GNU_SOURCE 103 | andre: private override LDFLAGS += -L. -Wl,-Y,runtime,-rpath,$(PREFIX)$(LIBDIR)$(RUNTIMEDIR) 104 | andre: private override LDLIBS += -ldl -lpthread 105 | andre: private override LDLIBS += -ljvm -ljvm-java -ljvm-android -ljvm-unity -ljvm-misc 106 | andre: src/loader.c libdl.so libpthread.so 107 | andre: runtime/libpthread.so runtime/libc.so 108 | andre: runtime/libandroid.so runtime/liblog.so 109 | andre: runtime/libEGL.so runtime/libOpenSLES.so 110 | andre: runtime/libjvm.so runtime/libjvm-java.so runtime/libjvm-android.so runtime/libjvm-unity.so runtime/libjvm-misc.so 111 | 112 | install-bin: $(bins) 113 | install -Dm755 $^ -t "$(DESTDIR)$(PREFIX)$(BINDIR)" 114 | 115 | install-lib: $(libs) 116 | install -Dm755 $^ -t "$(DESTDIR)$(PREFIX)$(LIBDIR)$(RUNTIMEDIR)" 117 | 118 | install: install-bin install-lib 119 | 120 | clean: 121 | $(RM) $(bins) *.a 122 | $(RM) -r runtime 123 | 124 | .PHONY: all x86 x86_64 armeabi armeabi-v7a armeabi-v7a-neon arm64-v8a clean install 125 | .INTERMEDIATE: libdl.so libpthread.so 126 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # android2gnulinux 2 | 3 | AOSP/Bionic compatiblity layer for GLIBC systems 4 | 5 | ## Notes 6 | 7 | Currently heavy work in progress. Linker will be rewritten as it's 8 | utter crap. Need to add logging/tracing facility controlled from env. 9 | That's about it, otherwise it's just implementing stuff. `libjvm-*.so` 10 | implementations are not correct at all, but the point is to not make 11 | correct implementations yet, just to get some games run, which are pretty 12 | forgiving for incorrect implementation :D. 13 | 14 | ## Building 15 | 16 | ```shell 17 | # to compile for android ABI x86 18 | make x86 19 | ``` 20 | 21 | Other than x86 is currently untested and probably doesn't work. 22 | 23 | ## Running 24 | 25 | ```shell 26 | ./andre my-android-binary 27 | ./andre my-android-jni-lib.so 28 | sh andre-apk.sh my-android-unity-app.apk 29 | ``` 30 | 31 | `andre-apk.sh` currently assumes app that uses `libunity.so`. 32 | 33 | ## Notes about runtime libraries and porting 34 | 35 | AOSP/bionic libs in `runtime` (the non `libjvm-*.so` ones) can be used to 36 | port android software to GNU/linux also. The runtime libraries contain 37 | `bionic_` prefixed symbols for runtime compatibility only. Functions that 38 | are not implemented in glibc, but are in AOSP/bionic are implemented 39 | normally in these libraries. This means that the same libraries can be 40 | used for both, compiling and linking to GNU/linux android native code, and 41 | running AOSP/bionic linked code. The PORTING and RUNTIME capability is not 42 | optional compile-time, nor do we separate PORTING and RUNTIME libraries. 43 | This is for pure simplicity. 44 | 45 | If you have to load/use bionic linked libraries from your ported 46 | application, you can use the `libdl.so` that has `bionic_` prefixed 47 | versions of the usual `dlfcn.h` functions. 48 | 49 | If for some reason one wants minimal library for either PORTING or RUNTIME 50 | task, here are the rules you can apply for symbol removal: 51 | 52 | ``` 53 | PORTING: Remove all symbols with prefix `bionic_`. Don't do this if you need `bionic_dlopen` from `runtime/libdl.so`. 54 | RUNTIME: Remove the symbol if there also exists the same symbol with a `bionic_` prefix, retaining only the `bionic_` edition. 55 | ``` 56 | 57 | That said, the libraries are pretty small anyways. 58 | 59 | ## JNI and JVM implementations 60 | 61 | We implement the JNI interface and simulate a rather unusual JVM that 62 | only calls C functions. Native android code that uses JNI, thinks 63 | it's talking to java but in reality it's calling functions from the 64 | `runtime/libjvm-*.so` libraries. The `runtime/libjvm-*.so` libraries 65 | implement java apis referenced by the application in C. 66 | 67 | In future, there might be very small dalvik bytecode interpreter, that we 68 | can use to eliminate the need of porting internal java dependencies and 69 | implementing entrypoint for every native application. We would only have 70 | to implement the external java apis that exist in android system image in 71 | C, and yes, this also means you could run android java applications. 72 | 73 | If you are porting android application to GNU/Linux that heavily relies 74 | on JNI, you can use the `libjvm.so` to use the minimal JVM inside the 75 | application, without having to rewrite the JNI reliant code. At this 76 | moment however, you still have to manually do the initial JNI calls 77 | that setup and initialize your application. This may not be needed 78 | eventually, if we implemented what was described above (minimal dalvik 79 | bytecode interpreter). 80 | 81 | ## Related Work 82 | 83 | [apkenv](https://github.com/thp/apkenv.git) This is what inspired this 84 | project. The current linker code originates from this project (modified 85 | from AOSP). apkenv's in pretty messy state though and doesn't do clean 86 | implementation. It's still interesting approach and you should check it 87 | out. Also helpful resource for this project. 88 | 89 | [libhybris](https://github.com/libhybris/libhybris) Very badly documented 90 | project, but I guess it has some overlap with this project? Seems to be 91 | mainly aimed for using android GPU drivers on GNU/Linux. Also uses AOSP 92 | linker, probably this is the resource apkenv used. 93 | 94 | ## Contributing 95 | 96 | Currently it's not yet contribution friendly. When time comes, I'll write 97 | more detailed topic on this. Project also needs some regression testing 98 | for all the functions that will be implemented. As for implementing stuff, 99 | people should only implement the stuff some application needs. Lets not 100 | implement anything that doesn't get used. 101 | 102 | ## Debugging with apitrace 103 | 104 | Since apitrace and similiar OpenGL debuggers redirect the dlopen calls, 105 | you have to `LD_PRELOAD` the `runtime/libEGL.so` while running apitrace. 106 | `runtime/libEGL.so` is responsible for wrapping `eglGetDisplay` and 107 | `eglCreateWindowSurface` functions, so that valid native handles are 108 | passed to the real system EGL implementation. 109 | 110 | ``` 111 | LD_PRELOAD=runtime/libEGL.so apitrace -a egl ./app bioniclib.so 112 | ``` 113 | 114 | ## Q & A 115 | 116 | ### Why? I still don't get what this is for... 117 | 118 | Basically, most android games are just native libraries with a very small 119 | java entrypoint that does some boilerplate app setup, and few calls to the 120 | native library. Native library may communicate back to java through JNI, 121 | but usually the java parts are very small in these kinds of applications. 122 | Thus these kind of applications will work fine with even barebones JNI/JVM 123 | implementation which doesn't neccessary even have to be very "correct" :). 124 | To use the native libraries on GNU systems though we need to use custom 125 | linker as bionic's linker is incompatible with glibc. Similarly bionic 126 | libc is incompatible with glibc and we have to handle these differences to 127 | be able to use android libraries on GNU/linux. We also have to implement 128 | the system libraries that exists on android, but not on traditional 129 | GNU/Linux, such as the stuff in AOSP that handle window/context creation, 130 | input and such. These implementations can be valuable for porters, or even 131 | application developers as some interfaces may be very clean. 132 | 133 | ### Why not use dalvikvm? 134 | 135 | While we could use dalvikvm to handle the JNI and java, we still would 136 | have to reimplement all the android java apis to be GNU/Linux compatible, 137 | or run android services in container or something. This is probably 138 | what `anbox` and such projects do. The scope of this project is however 139 | something that does not need anything from android system. The minimal 140 | bytecode interpreter would be fun research project to see how little 141 | code we can achieve all this with. Of course java's standard library 142 | is quite large so the work for reimplementing java apis should not be 143 | underestimated. 144 | 145 | Our minimal JNI/JVM implementation is clearly separated from other 146 | AOSP/bionic components however, so it's perfectly possible for someone 147 | to use dalvikvm and android java libraries/services for the java bits 148 | instead. If someone's gonna do and maintain that work and it doesn't 149 | feel too clunky/hacky/invasive I have nothing against such code in this 150 | project. (aka, the JNI/JVM implementation is not hardcoded) 151 | 152 | ### Wait so this also implements java libraries in C, can we use these implementations from java? 153 | 154 | This is interesting and weird question at the same time. But yes, we 155 | could generate java classes that just specifies each method as native 156 | and thus calls our C implementation. However at current scope these 157 | implementations are not very useful. The goal is to just provide some 158 | barebones to get the interesting android applications to work. Correctness 159 | is not guaranteed! This project may be useful for NDK development however, 160 | basically anything where you don't use java much nor need a very "correct 161 | java implementation" :). 162 | 163 | ### How about arm libraries? 164 | 165 | You can use qemu. For hw acceleration, we could use custom libGLES libs 166 | that communicate with host system. Though such libraries may exist 167 | already, maybe even inside qemu project.. I haven't researched. 168 | -------------------------------------------------------------------------------- /andre-apk.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | argv0="$0" 4 | msg() { printf -- '%s: %s\n' "${argv0##*/}" "$@" 1>&2; } 5 | err() { msg "$@"; exit 1; } 6 | 7 | [ -z "$1" ] && err 'usage: ' 8 | pkgfile="$(realpath "$1")" 9 | 10 | arch="$(file ./andre | awk -F', ' '{print $2}')" 11 | case "$arch" in 12 | 'Intel 80386') 13 | arch="x86" 14 | ;; 15 | 'ARM') 16 | arch="armeabi-v7a" 17 | ;; 18 | *) 19 | err "dont know how to convert from elf arch '$arch' to android arch" 20 | ;; 21 | esac 22 | 23 | pkgname="$(aapt2 dump --file AndroidManifest.xml "$1" | sed -nr 's/.*A: package="([^ "]+).*/\1/p')" 24 | [ -z "$pkgname" ] && err "not a valid apk (missing package name)" 25 | 26 | tmpdir="$(mktemp -d)" 27 | trap 'rm -rf "$tmpdir"' EXIT 28 | unzip "$1" -d "$tmpdir" 29 | 30 | export ANDROID_PACKAGE_CODE_PATH="$pkgfile" 31 | export ANDROID_PACKAGE_NAME="$pkgname" 32 | 33 | # TODO: when we have first release, make this follow XDG spec 34 | export ANDROID_EXTERNAL_FILES_DIR="$PWD/local/data/$pkgname/files" 35 | export ANDROID_EXTERNAL_OBB_DIR="$PWD/local/data/$pkgname/obb" 36 | 37 | # XXX: We only work with unity stuff for now 38 | ./andre "$tmpdir/lib/$arch/libunity.so" 39 | -------------------------------------------------------------------------------- /android/libwrap.c: -------------------------------------------------------------------------------- 1 | // Need android-ndk, compile with: 2 | // i686-linux-android-gcc --sysroot=$ANDROID_NDK/platforms/android-9/arch-x86 -std=c99 -shared -I../src -DANDROID_X86_LINKER -DVERBOSE_FUNCTIONS libwrap.c ../src/wrapper/wrapper.c ../src/jvm/jvm.c -llog -o libwrap.so 3 | // Rename libwrap.so to the library's name you want to middle-man, and the original library to liborig.so 4 | // 5 | // We use logging thread to avoid putting android specific code to verbose/wrapper.h 6 | // Logging thread will catch stdout && stderr. 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include "jvm/jvm.h" 16 | #include "wrapper/wrapper.h" 17 | 18 | static int pfd[2]; 19 | 20 | static void* 21 | log_thread(void *arg) 22 | { 23 | char buf[255]; 24 | ssize_t r; 25 | while ((r = read(pfd[0], buf, sizeof(buf) - 1)) > 0) { 26 | r = (r > 0 && buf[r - 1] == '\n' ? r - 1 : r); 27 | buf[r] = 0; 28 | __android_log_write(ANDROID_LOG_INFO, "native", buf); 29 | } 30 | return NULL; 31 | } 32 | 33 | static void 34 | stdlog_workaround(void) 35 | { 36 | setvbuf(stdout, 0, _IOLBF, 0); 37 | setvbuf(stderr, 0, _IONBF, 0); 38 | pipe(pfd); 39 | dup2(pfd[1], 1); 40 | dup2(pfd[1], 2); 41 | pthread_t thread; 42 | pthread_create(&thread, 0, log_thread, NULL); 43 | pthread_detach(thread); 44 | } 45 | 46 | JNIEXPORT jint JNICALL 47 | JNI_OnLoad(JavaVM *vm, void *reserved) 48 | { 49 | stdlog_workaround(); 50 | 51 | __android_log_print(ANDROID_LOG_INFO, "native", "Loading liborig.so"); 52 | void *handle = dlopen("liborig.so", RTLD_NOW); 53 | assert(handle); 54 | 55 | jint (*JNI_OnLoad)(JavaVM*, void*) = dlsym(handle, "JNI_OnLoad"); 56 | assert(JNI_OnLoad); 57 | 58 | struct jvm jvm; 59 | jvm_init(&jvm); 60 | 61 | __android_log_print(ANDROID_LOG_INFO, "native", "Call liborig's JNI_OnLoad with fakevm"); 62 | JNI_OnLoad(&jvm.vm, NULL); 63 | 64 | // Sort of hack, may fail on some libraries maybe. 65 | // Some libs store the vm ^ in above call, we want it to use the real vm though. 66 | // We only pass fake vm in above call to know what natives it registered. 67 | JNI_OnLoad(vm, NULL); 68 | 69 | JNIEnv *env; 70 | if ((*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_6) != JNI_OK) 71 | return -1; 72 | 73 | __android_log_print(ANDROID_LOG_INFO, "native", "Wrapping natives methods"); 74 | 75 | jclass old_klass = jvm.methods[0].method.klass; 76 | JNINativeMethod methods[255]; 77 | for (size_t i = 0, c = 0; c < 255 && i < 255; ++i, ++c) { 78 | if (jvm.methods[i].method.klass != old_klass) { 79 | assert(old_klass > 0); 80 | jclass klass = (*env)->FindClass(env, jvm.objects[(intptr_t)old_klass - 1].klass.name.data); 81 | (*env)->RegisterNatives(env, klass, methods, c); 82 | old_klass = jvm.methods[i].method.klass; 83 | c = 0; 84 | } 85 | 86 | if (!jvm.methods[i].function) 87 | break; 88 | 89 | methods[c].name = jvm.methods[i].method.name.data; 90 | methods[c].signature = jvm.methods[i].method.signature.data; 91 | methods[c].fnPtr = wrapper_create(methods[c].name, jvm.methods[i].function); 92 | } 93 | 94 | return JNI_VERSION_1_6; 95 | } 96 | -------------------------------------------------------------------------------- /default.nix: -------------------------------------------------------------------------------- 1 | { pkgs ? (import {}).pkgsi686Linux }: 2 | 3 | pkgs.stdenv.mkDerivation { 4 | name = "android2gnulinux"; 5 | src = ./.; 6 | buildInputs = with pkgs; [ 7 | xorg.libX11.dev 8 | xorg.libXrandr.dev 9 | glfw 10 | ]; 11 | RUNTIMEDIR = "/andre/x86"; 12 | buildPhase = "make x86 PREFIX=$out"; 13 | installPhase = "make install PREFIX=$out"; 14 | } 15 | -------------------------------------------------------------------------------- /src/jvm/jvm.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include "jni.h" 4 | #include 5 | 6 | struct jvm_string { 7 | const char *data; 8 | size_t size; 9 | bool heap; // if on heap, then `data` should be freed 10 | }; 11 | 12 | struct jvm_array { 13 | void *data; 14 | size_t element_sz, size; // `size` == in elements, `size * element_sz` for bytes 15 | }; 16 | 17 | struct jvm_class { 18 | struct jvm_string name; 19 | }; 20 | 21 | struct jvm_method { 22 | jclass klass; 23 | struct jvm_string name, signature; 24 | }; 25 | 26 | struct jvm_object { 27 | jclass this_klass; 28 | 29 | union { 30 | struct jvm_array array; 31 | struct jvm_method method; 32 | struct jvm_class klass; 33 | struct jvm_string string; 34 | }; 35 | 36 | enum jvm_object_type { 37 | JVM_OBJECT_NONE, 38 | JVM_OBJECT_OPAQUE, 39 | JVM_OBJECT_ARRAY, 40 | JVM_OBJECT_METHOD, 41 | JVM_OBJECT_CLASS, 42 | JVM_OBJECT_STRING, 43 | JVM_OBJECT_LAST, 44 | } type; 45 | }; 46 | 47 | struct jvm_native_method { 48 | struct jvm_method method; 49 | void *function; 50 | }; 51 | 52 | struct jvm { 53 | // [0] object is created on `jvm_init` and it's a class object for defining the class of a class 54 | // every class object's `this_class` member points back to [0], causing recursion. 55 | // Every other object or class definition is created lazily as needed, only [0] is special. 56 | // `jobject`'s we return through JNI are actually (index+1) to this array, not pointers. 57 | struct jvm_object objects[4096]; 58 | 59 | // Native methods registered by the application. 60 | // Nothing special, but there's no need to access this array either really. 61 | // You can use `jvm_get_native_method` instead. 62 | struct jvm_native_method methods[255]; 63 | 64 | // These hold the function pointers for our JNI implementation. 65 | struct JNINativeInterface native; 66 | struct JNIInvokeInterface invoke; 67 | 68 | // JNI's api is weird.. pointer to a reference of a struct, OK! 69 | // Developers have to dereference these pointers to call methods from an ... reference. 70 | // NOTE: These are pointers, and JNI interface passes pointers to these pointers! 71 | JNIEnv env; // points to native 72 | JavaVM vm; // points to invoke 73 | }; 74 | 75 | const char* 76 | jvm_get_class_name(struct jvm *jvm, jobject object); 77 | 78 | void* 79 | jvm_get_native_method(struct jvm *jvm, const char *klass, const char *method); 80 | 81 | void 82 | jvm_release(struct jvm *jvm); 83 | 84 | void 85 | jvm_init(struct jvm *jvm); 86 | 87 | struct jvm* 88 | jnienv_get_jvm(JNIEnv *env); 89 | -------------------------------------------------------------------------------- /src/libEGL.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | #define GLFW_INCLUDE_NONE 6 | #include 7 | #define GLFW_EXPOSE_NATIVE_X11 8 | #include 9 | 10 | struct ANativeWindow { 11 | char header[4]; 12 | GLFWwindow *glfw; 13 | }; 14 | 15 | EGLSurface 16 | eglCreateWindowSurface(EGLDisplay display, EGLConfig config, NativeWindowType native_window, EGLint const *attrib_list) 17 | { 18 | static union { EGLSurface (*fun)(EGLDisplay, EGLConfig, NativeWindowType, EGLint const*); void *ptr; } orig; 19 | if (!orig.ptr) orig.ptr = dlsym(RTLD_NEXT, "eglCreateWindowSurface"); 20 | struct ANativeWindow *window = (struct ANativeWindow*)native_window; 21 | return orig.fun(display, config, (!memcmp(window->header, "andr", sizeof(window->header)) ? glfwGetX11Window(window->glfw) : native_window), attrib_list); 22 | } 23 | -------------------------------------------------------------------------------- /src/libOpenSLES.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include "wrapper/wrapper.h" 3 | #include "wrapper/verbose.h" 4 | 5 | // https://developer.android.com/ndk/guides/audio/opensl/opensl-for-android 6 | // https://www.khronos.org/registry/OpenSL-ES/specs/OpenSL_ES_Specification_1.1.pdf 7 | 8 | typedef uint8_t SLuint8; 9 | typedef uint16_t SLuint16; 10 | typedef uint32_t SLuint32; 11 | typedef SLuint8 SLchar; 12 | typedef SLuint32 SLboolean; 13 | typedef SLuint32 SLresult; 14 | 15 | #define SL_BOOLEAN_FALSE ((SLboolean) 0x00000000) 16 | #define SL_BOOLEAN_TRUE ((SLboolean) 0x00000001) 17 | 18 | #define SL_RESULT_SUCCESS ((SLuint32) 0x00000000) 19 | #define SL_RESULT_PRECONDITIONS_VIOLATED ((SLuint32) 0x00000001) 20 | #define SL_RESULT_PARAMETER_INVALID ((SLuint32) 0x00000002) 21 | #define SL_RESULT_MEMORY_FAILURE ((SLuint32) 0x00000003) 22 | #define SL_RESULT_RESOURCE_ERROR ((SLuint32) 0x00000004) 23 | #define SL_RESULT_RESOURCE_LOST ((SLuint32) 0x00000005) 24 | #define SL_RESULT_IO_ERROR ((SLuint32) 0x00000006) 25 | #define SL_RESULT_BUFFER_INSUFFICIENT ((SLuint32) 0x00000007) 26 | #define SL_RESULT_CONTENT_CORRUPTED ((SLuint32) 0x00000008) 27 | #define SL_RESULT_CONTENT_UNSUPPORTED ((SLuint32) 0x00000009) 28 | #define SL_RESULT_CONTENT_NOT_FOUND ((SLuint32) 0x0000000A) 29 | #define SL_RESULT_PERMISSION_DENIED ((SLuint32) 0x0000000B) 30 | #define SL_RESULT_FEATURE_UNSUPPORTED ((SLuint32) 0x0000000C) 31 | #define SL_RESULT_INTERNAL_ERROR ((SLuint32) 0x0000000D) 32 | #define SL_RESULT_UNKNOWN_ERROR ((SLuint32) 0x0000000E) 33 | #define SL_RESULT_OPERATION_ABORTED ((SLuint32) 0x0000000F) 34 | #define SL_RESULT_CONTROL_LOST ((SLuint32) 0x00000010) 35 | 36 | #define SL_OBJECT_STATE_UNREALIZED ((SLuint32) 0x00000001) 37 | #define SL_OBJECT_STATE_REALIZED ((SLuint32) 0x00000002) 38 | #define SL_OBJECT_STATE_SUSPENDED ((SLuint32) 0x00000003) 39 | 40 | #define SL_DEFAULTDEVICEID_LED ((SLuint32) 0xFFFFFFFD) 41 | #define SL_DEFAULTDEVICEID_VIBRA ((SLuint32) 0xFFFFFFFC) 42 | 43 | struct SLInterfaceID { 44 | SLuint32 time_low; 45 | SLuint16 time_mid; 46 | SLuint16 time_hi_and_version; 47 | SLuint16 clock_seq; 48 | uint8_t node[6]; 49 | }; 50 | 51 | struct SLInterfaceID *SL_IID_BUFFERQUEUE; 52 | struct SLInterfaceID *SL_IID_ENGINE; 53 | struct SLInterfaceID *SL_IID_PLAY; 54 | struct SLInterfaceID *SL_IID_VOLUME; 55 | 56 | struct SLObjectItf { 57 | SLresult (*Realize)(struct SLObjectItf**, SLboolean); 58 | SLresult (*Resume)(struct SLObjectItf**, SLboolean); 59 | SLresult (*GetState)(struct SLObjectItf**, SLuint32*); 60 | SLresult (*GetInterface)(struct SLObjectItf**, const struct SLInterfaceID*, struct SLObjectItf***); 61 | SLresult (*RegisterCallback)(struct SLObjectItf**, void*, void*); 62 | SLresult (*AbortAsyncOperation)(struct SLObjectItf**); 63 | SLresult (*Destroy)(struct SLObjectItf**); 64 | SLresult (*SetPriority)(struct SLObjectItf**, SLuint32, SLboolean); 65 | SLresult (*GetPriority)(struct SLObjectItf**, SLuint32*, SLboolean*); 66 | SLresult (*SetLossOfControlInterfaces)(struct SLObjectItf**, SLuint16, const struct SLInterfaceID**, SLboolean); 67 | }; 68 | 69 | static struct SLObjectItf** 70 | sl_object(void); 71 | 72 | struct SLEngineItf { 73 | SLresult (*CreateLEDDevice)(struct SLEngineItf**, struct SLObjectItf***, SLuint32, SLuint32, const struct SLInterfaceID**, const SLboolean*); 74 | SLresult (*CreateVibraDevice)(struct SLEngineItf**, struct SLObjectItf***, SLuint32, SLuint32, const struct SLInterfaceID**, const SLboolean*); 75 | SLresult (*CreateAudioPlayer)(struct SLEngineItf**, struct SLObjectItf***, void*, void*, SLuint32, const struct SLInterfaceID**, const SLboolean*); 76 | SLresult (*CreateAudioRecorder)(struct SLEngineItf**, struct SLObjectItf***, void*, void*, SLuint32, const struct SLInterfaceID**, const SLboolean*); 77 | SLresult (*CreateMidiPlayer)(struct SLEngineItf**, struct SLObjectItf***, void*, void*, void*, void*, void*, SLuint32, const struct SLInterfaceID**, const SLboolean*); 78 | SLresult (*CreateListener)(struct SLEngineItf**, struct SLObjectItf***, SLuint32, const struct SLInterfaceID**, const SLboolean*); 79 | SLresult (*Create3DGroup)(struct SLEngineItf**, struct SLObjectItf***, SLuint32, const struct SLInterfaceID**, const SLboolean*); 80 | SLresult (*CreateOutputMix)(struct SLEngineItf**, struct SLObjectItf***, SLuint32, const struct SLInterfaceID**, const SLboolean*); 81 | SLresult (*CreateMetadataExtractor)(struct SLEngineItf**, struct SLObjectItf***, void*, SLuint32, const struct SLInterfaceID**, const SLboolean*); 82 | SLresult (*CreateExtensionObject)(struct SLEngineItf**, struct SLObjectItf***, void*, SLuint32, SLuint32, const struct SLInterfaceID**, const SLboolean*); 83 | SLresult (*QueryNumSupportedInterfaces)(struct SLEngineItf**, SLuint32, SLuint32*); 84 | SLresult (*QuerySupportedInterfaces)(struct SLEngineItf**, SLuint32, SLuint32, const struct SLInterfaceID**); 85 | SLresult (*QueryNumSupportedExtensions)(struct SLEngineItf**, SLuint32, SLuint32*); 86 | SLresult (*QuerySupportedExtensions)(struct SLEngineItf**, SLuint32, const char*, SLuint16*); 87 | SLresult (*IsExtensionSupported)(struct SLEngineItf**, const char*, SLboolean*); 88 | }; 89 | 90 | static SLresult 91 | sl_engine_create_led_device(struct SLEngineItf **engine, struct SLObjectItf ***device, SLuint32 device_id, SLuint32 num_interfaces, const struct SLInterfaceID **interface_ids, const SLboolean *interface_required) 92 | { 93 | verbose("%p, %p, %u, %u %p, %p", (void*)engine, (void*)device, device_id, num_interfaces, (void*)interface_ids, (void*)interface_required); 94 | 95 | if (!device || device_id != SL_DEFAULTDEVICEID_LED) 96 | return SL_RESULT_PARAMETER_INVALID; 97 | 98 | *device = sl_object(); 99 | return SL_RESULT_SUCCESS; 100 | } 101 | 102 | static SLresult 103 | sl_engine_create_vibra_device(struct SLEngineItf **engine, struct SLObjectItf ***device, SLuint32 device_id, SLuint32 num_interfaces, const struct SLInterfaceID **interface_ids, const SLboolean *interface_required) 104 | { 105 | verbose("%p, %p, %u, %u %p, %p", (void*)engine, (void*)device, device_id, num_interfaces, (void*)interface_ids, (void*)interface_required); 106 | 107 | if (!device || device_id != SL_DEFAULTDEVICEID_VIBRA) 108 | return SL_RESULT_PARAMETER_INVALID; 109 | 110 | *device = sl_object(); 111 | return SL_RESULT_SUCCESS; 112 | } 113 | 114 | static SLresult 115 | sl_engine_create_audio_player(struct SLEngineItf **engine, struct SLObjectItf ***device, void *src, void *snk, SLuint32 num_interfaces, const struct SLInterfaceID **interface_ids, const SLboolean *interface_required) 116 | { 117 | verbose("%p, %p, %p, %p, %u %p, %p", (void*)engine, (void*)device, src, snk, num_interfaces, (void*)interface_ids, (void*)interface_required); 118 | 119 | if (!device) 120 | return SL_RESULT_PARAMETER_INVALID; 121 | 122 | *device = sl_object(); 123 | return SL_RESULT_SUCCESS; 124 | } 125 | 126 | static SLresult 127 | sl_engine_create_audio_recorder(struct SLEngineItf **engine, struct SLObjectItf ***device, void *src, void *snk, SLuint32 num_interfaces, const struct SLInterfaceID **interface_ids, const SLboolean *interface_required) 128 | { 129 | verbose("%p, %p, %p, %p, %u %p, %p", (void*)engine, (void*)device, src, snk, num_interfaces, (void*)interface_ids, (void*)interface_required); 130 | 131 | if (!device) 132 | return SL_RESULT_PARAMETER_INVALID; 133 | 134 | *device = sl_object(); 135 | return SL_RESULT_SUCCESS; 136 | } 137 | 138 | static SLresult 139 | sl_engine_create_midi_player(struct SLEngineItf **engine, struct SLObjectItf ***device, void *midi_src, void *bank_src, void *audio_out, void *vibra, void *led_array, SLuint32 num_interfaces, const struct SLInterfaceID **interface_ids, const SLboolean *interface_required) 140 | { 141 | verbose("%p, %p, %p, %p, %p, %p, %p, %u %p, %p", (void*)engine, (void*)device, midi_src, bank_src, audio_out, vibra, led_array, num_interfaces, (void*)interface_ids, (void*)interface_required); 142 | 143 | if (!device) 144 | return SL_RESULT_PARAMETER_INVALID; 145 | 146 | *device = sl_object(); 147 | return SL_RESULT_SUCCESS; 148 | } 149 | 150 | static SLresult 151 | sl_engine_create_listener(struct SLEngineItf **engine, struct SLObjectItf ***device, SLuint32 num_interfaces, const struct SLInterfaceID **interface_ids, const SLboolean *interface_required) 152 | { 153 | verbose("%p, %p, %u, %p, %p", (void*)engine, (void*)device, num_interfaces, (void*)interface_ids, (void*)interface_required); 154 | 155 | if (!device) 156 | return SL_RESULT_PARAMETER_INVALID; 157 | 158 | *device = sl_object(); 159 | return SL_RESULT_SUCCESS; 160 | } 161 | 162 | static SLresult 163 | sl_engine_create_3d_group(struct SLEngineItf **engine, struct SLObjectItf ***device, SLuint32 num_interfaces, const struct SLInterfaceID **interface_ids, const SLboolean *interface_required) 164 | { 165 | verbose("%p, %p, %u, %p, %p", (void*)engine, (void*)device, num_interfaces, (void*)interface_ids, (void*)interface_required); 166 | 167 | if (!device) 168 | return SL_RESULT_PARAMETER_INVALID; 169 | 170 | *device = sl_object(); 171 | return SL_RESULT_SUCCESS; 172 | } 173 | 174 | static SLresult 175 | sl_engine_create_output_mix(struct SLEngineItf **engine, struct SLObjectItf ***device, SLuint32 num_interfaces, const struct SLInterfaceID **interface_ids, const SLboolean *interface_required) 176 | { 177 | verbose("%p, %p, %u, %p, %p", (void*)engine, (void*)device, num_interfaces, (void*)interface_ids, (void*)interface_required); 178 | 179 | if (!device) 180 | return SL_RESULT_PARAMETER_INVALID; 181 | 182 | *device = sl_object(); 183 | return SL_RESULT_SUCCESS; 184 | } 185 | 186 | static SLresult 187 | sl_engine_create_metadata_extractor(struct SLEngineItf **engine, struct SLObjectItf ***device, void *source, SLuint32 num_interfaces, const struct SLInterfaceID **interface_ids, const SLboolean *interface_required) 188 | { 189 | verbose("%p, %p, %p, %u, %p, %p", (void*)engine, (void*)device, source, num_interfaces, (void*)interface_ids, (void*)interface_required); 190 | 191 | if (!device || !source) 192 | return SL_RESULT_PARAMETER_INVALID; 193 | 194 | *device = sl_object(); 195 | return SL_RESULT_SUCCESS; 196 | } 197 | 198 | static SLresult 199 | sl_engine_create_extension_object(struct SLEngineItf **engine, struct SLObjectItf ***device, void *params, SLuint32 num_interfaces, const struct SLInterfaceID **interface_ids, const SLboolean *interface_required) 200 | { 201 | verbose("%p, %p, %p, %u, %p, %p", (void*)engine, (void*)device, params, num_interfaces, (void*)interface_ids, (void*)interface_required); 202 | 203 | if (!device || !params) 204 | return SL_RESULT_PARAMETER_INVALID; 205 | 206 | *device = sl_object(); 207 | return SL_RESULT_SUCCESS; 208 | } 209 | 210 | static SLresult 211 | sl_engine_query_num_supported_interfaces(struct SLEngineItf **engine, SLuint32 *out_num_supported) 212 | { 213 | verbose("%p, %p", (void*)engine, (void*)out_num_supported); 214 | 215 | if (!out_num_supported) 216 | return SL_RESULT_PARAMETER_INVALID; 217 | 218 | *out_num_supported = 0; 219 | return SL_RESULT_SUCCESS; 220 | } 221 | 222 | static SLresult 223 | sl_engine_query_supported_interfaces(struct SLEngineItf **engine, SLuint32 index, const SLchar *name, SLuint16 *out_name_len) 224 | { 225 | verbose("%p, %u, %s, %p", (void*)engine, index, name, (void*)out_name_len); 226 | 227 | if (!name || !out_name_len) 228 | return SL_RESULT_PARAMETER_INVALID; 229 | 230 | *out_name_len = 0; 231 | return SL_RESULT_SUCCESS; 232 | } 233 | 234 | static SLresult 235 | sl_engine_query_num_supported_extensions(struct SLEngineItf **engine, SLuint32 *out_num_supported) 236 | { 237 | verbose("%p, %p", (void*)engine, (void*)out_num_supported); 238 | 239 | if (!out_num_supported) 240 | return SL_RESULT_PARAMETER_INVALID; 241 | 242 | *out_num_supported = 0; 243 | return SL_RESULT_SUCCESS; 244 | } 245 | 246 | static SLresult 247 | sl_engine_query_supported_extensions(struct SLEngineItf **engine, SLuint32 index, const SLchar *name, SLuint16 *out_name_len) 248 | { 249 | verbose("%p, %u, %s, %p", (void*)engine, index, name, (void*)out_name_len); 250 | 251 | if (!name || !out_name_len) 252 | return SL_RESULT_PARAMETER_INVALID; 253 | 254 | *out_name_len = 0; 255 | return SL_RESULT_SUCCESS; 256 | } 257 | 258 | static SLresult 259 | sl_engine_is_extension_supported(struct SLEngineItf **engine, const SLchar *name, SLboolean *out_supported) 260 | { 261 | verbose("%p, %s, %p", (void*)engine, name, (void*)out_supported); 262 | 263 | if (!name || !out_supported) 264 | return SL_RESULT_PARAMETER_INVALID; 265 | 266 | *out_supported = SL_BOOLEAN_FALSE; 267 | return SL_RESULT_SUCCESS; 268 | } 269 | 270 | static struct SLEngineItf** 271 | sl_engine(void) 272 | { 273 | static struct SLEngineItf itf, *itfp; 274 | if (!itfp) { 275 | #define WRAP(x) wrapper_create(#x, x) 276 | itf.CreateLEDDevice = WRAP(sl_engine_create_led_device); 277 | itf.CreateVibraDevice = WRAP(sl_engine_create_vibra_device); 278 | itf.CreateAudioPlayer = WRAP(sl_engine_create_audio_player); 279 | itf.CreateAudioRecorder = WRAP(sl_engine_create_audio_recorder); 280 | itf.CreateMidiPlayer = WRAP(sl_engine_create_midi_player); 281 | itf.CreateListener = WRAP(sl_engine_create_listener); 282 | itf.Create3DGroup = WRAP(sl_engine_create_3d_group); 283 | itf.CreateOutputMix = WRAP(sl_engine_create_output_mix); 284 | itf.CreateMetadataExtractor = WRAP(sl_engine_create_metadata_extractor); 285 | itf.CreateExtensionObject = WRAP(sl_engine_create_extension_object); 286 | itf.QueryNumSupportedInterfaces = WRAP(sl_engine_query_num_supported_interfaces); 287 | itf.QuerySupportedInterfaces = WRAP(sl_engine_query_supported_interfaces); 288 | itf.QueryNumSupportedExtensions = WRAP(sl_engine_query_num_supported_extensions); 289 | itf.QuerySupportedExtensions = WRAP(sl_engine_query_supported_extensions); 290 | itf.IsExtensionSupported = WRAP(sl_engine_is_extension_supported); 291 | #undef WRAP 292 | itfp = &itf; 293 | } 294 | return &itfp; 295 | } 296 | 297 | static SLresult 298 | sl_object_realize(struct SLObjectItf **object, SLboolean async) 299 | { 300 | verbose("%p, %u", (void*)object, async); 301 | return SL_RESULT_SUCCESS; 302 | } 303 | 304 | static SLresult 305 | sl_object_resume(struct SLObjectItf **object, SLboolean async) 306 | { 307 | verbose("%p, %u", (void*)object, async); 308 | return SL_RESULT_SUCCESS; 309 | } 310 | 311 | static SLresult 312 | sl_object_get_state(struct SLObjectItf **object, SLuint32 *out_state) 313 | { 314 | verbose("%p, %p", (void*)object, (void*)out_state); 315 | 316 | if (!out_state) 317 | return SL_RESULT_PARAMETER_INVALID; 318 | 319 | *out_state = SL_OBJECT_STATE_REALIZED; 320 | return SL_RESULT_SUCCESS; 321 | } 322 | 323 | static SLresult 324 | sl_object_get_interface(struct SLObjectItf **object, const struct SLInterfaceID *iid, struct SLObjectItf ***out_interface) 325 | { 326 | verbose("%p, %p", (void*)object, (void*)out_interface); 327 | 328 | if (iid == SL_IID_ENGINE) { 329 | *out_interface = (struct SLObjectItf**)sl_engine(); 330 | } else { 331 | return SL_RESULT_PARAMETER_INVALID; 332 | } 333 | 334 | return SL_RESULT_SUCCESS; 335 | } 336 | 337 | static SLresult 338 | sl_object_register_callback(struct SLObjectItf **object, void *cb, void *ctx) 339 | { 340 | verbose("%p, %p, %p", (void*)object, cb, ctx); 341 | return SL_RESULT_SUCCESS; 342 | } 343 | 344 | static SLresult 345 | sl_object_abort_async_operation(struct SLObjectItf **object) 346 | { 347 | verbose("%p", (void*)object); 348 | return SL_RESULT_SUCCESS; 349 | } 350 | 351 | static SLresult 352 | sl_object_destroy(struct SLObjectItf **object) 353 | { 354 | verbose("%p", (void*)object); 355 | return SL_RESULT_SUCCESS; 356 | } 357 | 358 | static SLresult 359 | sl_object_set_priority(struct SLObjectItf **object, SLuint32 priority, SLboolean preemptable) 360 | { 361 | verbose("%p, %u, %u", (void*)object, priority, preemptable); 362 | return SL_RESULT_SUCCESS; 363 | } 364 | 365 | static SLresult 366 | sl_object_get_priority(struct SLObjectItf **object, SLuint32 *out_priority, SLboolean *out_preemptable) 367 | { 368 | verbose("%p, %p, %p", (void*)object, (void*)out_priority, (void*)out_preemptable); 369 | 370 | if (!out_priority || !out_preemptable) 371 | return SL_RESULT_PARAMETER_INVALID; 372 | 373 | *out_priority = 0; 374 | *out_preemptable = SL_BOOLEAN_FALSE; 375 | return SL_RESULT_SUCCESS; 376 | } 377 | 378 | static SLresult 379 | sl_object_set_loss_of_control_interfaces(struct SLObjectItf **object, SLuint16 num_interfaces, struct SLInterfaceID **interface_ids, SLboolean enabled) 380 | { 381 | verbose("%p, %u, %p, %u", (void*)object, num_interfaces, (void*)interface_ids, enabled); 382 | return SL_RESULT_SUCCESS; 383 | } 384 | 385 | static struct SLObjectItf** 386 | sl_object(void) 387 | { 388 | static struct SLObjectItf itf, *itfp; 389 | if (!itfp) { 390 | #define WRAP(x) wrapper_create(#x, x) 391 | itf.Realize = WRAP(sl_object_realize); 392 | itf.Resume = WRAP(sl_object_resume); 393 | itf.GetState = WRAP(sl_object_get_state); 394 | itf.GetInterface = WRAP(sl_object_get_interface); 395 | itf.RegisterCallback = WRAP(sl_object_register_callback); 396 | itf.AbortAsyncOperation = WRAP(sl_object_abort_async_operation); 397 | itf.Destroy = WRAP(sl_object_destroy); 398 | itf.SetPriority = WRAP(sl_object_set_priority); 399 | itf.GetPriority = WRAP(sl_object_get_priority); 400 | itf.SetLossOfControlInterfaces = WRAP(sl_object_set_loss_of_control_interfaces); 401 | #undef WRAP 402 | itfp = &itf; 403 | } 404 | return &itfp; 405 | } 406 | 407 | SLresult 408 | slCreateEngine(struct SLObjectItf ***engine, SLuint32 num_options, void *options, SLuint32 num_interfaces, const struct SLInterfaceID **interface_ids, const SLboolean *interface_required) 409 | { 410 | verbose("%p, %u, %p, %u, %p, %p", (void*)engine, num_options, options, num_interfaces, (void*)interface_ids, (void*)interface_required); 411 | 412 | if (!engine) 413 | return SL_RESULT_PARAMETER_INVALID; 414 | 415 | *engine = sl_object(); 416 | return SL_RESULT_SUCCESS; 417 | } 418 | -------------------------------------------------------------------------------- /src/libandroid.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #define GLFW_INCLUDE_NONE 9 | #include 10 | 11 | #include "jvm/jni.h" 12 | 13 | // https://android.googlesource.com/platform/bionic/+/master/docs/32-bit-abi.md 14 | typedef uint32_t bionic_off_t; 15 | 16 | // AAsset 17 | 18 | struct AAsset { 19 | char nop; 20 | }; 21 | 22 | void 23 | AAsset_close(struct AAsset *asset) 24 | { 25 | free(asset); 26 | } 27 | 28 | bionic_off_t 29 | AAsset_getLength(struct AAsset *asset) 30 | { 31 | return 0; 32 | } 33 | 34 | bionic_off_t 35 | AAsset_seek(struct AAsset *asset, bionic_off_t offset, int whence) 36 | { 37 | return 0; 38 | } 39 | 40 | 41 | int 42 | AAsset_read(struct AAsset *asset, void *buf, size_t count) 43 | { 44 | return 0; 45 | } 46 | 47 | // AAssetManager 48 | 49 | struct AAssetManager { 50 | char nop; 51 | }; 52 | 53 | struct AAssetManager* 54 | AAssetManager_fromJava(JNIEnv *env, jobject assetManager) 55 | { 56 | return calloc(1, sizeof(struct AAssetManager)); 57 | } 58 | 59 | struct AAsset* 60 | AAssetManager_open(struct AAssetManager *amgr, const char *filename, int mode) 61 | { 62 | return calloc(1, sizeof(struct AAsset)); 63 | } 64 | 65 | // AConfiguration 66 | 67 | struct AConfiguration { 68 | char nop; 69 | }; 70 | 71 | struct AConfiguration* 72 | AConfiguration_new(void) 73 | { 74 | return calloc(1, sizeof(struct AConfiguration)); 75 | } 76 | 77 | void 78 | AConfiguration_delete(struct AConfiguration *config) 79 | { 80 | free(config); 81 | } 82 | 83 | void 84 | AConfiguration_fromAssetManager(struct AConfiguration *out, struct AAssetManager *am) 85 | { 86 | } 87 | 88 | // ALooper 89 | 90 | static struct ALooper { 91 | char nop; 92 | } thread_looper; 93 | 94 | typedef void* ALooper_callbackFunc; 95 | 96 | struct ALooper* 97 | ALooper_forThread(void) 98 | { 99 | return &thread_looper; 100 | } 101 | 102 | struct ALooper* 103 | ALooper_prepare(int opts) 104 | { 105 | return &thread_looper; 106 | } 107 | 108 | void 109 | ALooper_wake(struct ALooper *looper) 110 | { 111 | } 112 | 113 | int 114 | ALooper_pollAll(int timeoutMillis, int *outFd, int *outEvents, void **outData) 115 | { 116 | return 0; 117 | } 118 | 119 | int 120 | ALooper_pollOnce(int timeoutMillis, int *outFd, int *outEvents, void **outData) 121 | { 122 | return 0; 123 | } 124 | 125 | // ASensor 126 | 127 | struct ASensor { 128 | char nop; 129 | }; 130 | 131 | const char* 132 | ASensor_getName(struct ASensor const *sensor) 133 | { 134 | return NULL; 135 | } 136 | 137 | const char* 138 | ASensor_getVendor(struct ASensor const *sensor) 139 | { 140 | return NULL; 141 | } 142 | 143 | int 144 | ASensor_getType(struct ASensor const *sensor) 145 | { 146 | return 0; 147 | } 148 | 149 | float 150 | ASensor_getResolution(struct ASensor const *sensor) 151 | { 152 | return 0; 153 | } 154 | 155 | int 156 | ASensor_getMinDelay(struct ASensor const *sensor) 157 | { 158 | return 0; 159 | } 160 | 161 | struct ASensorEvent { 162 | char nop; 163 | }; 164 | 165 | struct ASensorEventQueue { 166 | char nop; 167 | }; 168 | 169 | int 170 | ASensorEventQueue_enableSensor(struct ASensorEventQueue *queue, struct ASensor const *sensor) 171 | { 172 | return 0; 173 | } 174 | 175 | int 176 | ASensorEventQueue_disableSensor(struct ASensorEventQueue *queue, struct ASensor const *sensor) 177 | { 178 | return 0; 179 | } 180 | 181 | int 182 | ASensorEventQueue_setEventRate(struct ASensorEventQueue *queue, struct ASensor const *sensor, int32_t usec) 183 | { 184 | return 0; 185 | } 186 | 187 | int 188 | ASensorEventQueue_hasEvents(struct ASensorEventQueue *queue) 189 | { 190 | return 0; 191 | } 192 | 193 | size_t 194 | ASensorEventQueue_getEvents(struct ASensorEventQueue *queue, struct ASensorEvent *events, size_t count) 195 | { 196 | return 0; 197 | } 198 | 199 | struct ASensorManager { 200 | char nop; 201 | }; 202 | 203 | struct ASensorList { 204 | char nop; 205 | }; 206 | 207 | struct ASensorManager* 208 | ASensorManager_getInstance() 209 | { 210 | return NULL; 211 | } 212 | 213 | struct ASensor const* 214 | ASensorManager_getDefaultSensor(struct ASensorManager *manager, int type) 215 | { 216 | return NULL; 217 | } 218 | 219 | int 220 | ASensorManager_getSensorList(struct ASensorManager *manager, struct ASensorList *list) 221 | { 222 | return 0; 223 | } 224 | 225 | struct ASensorEventQueue* 226 | ASensorManager_createEventQueue(struct ASensorManager *manager, struct ALooper *looper, int ident, ALooper_callbackFunc callback, void *data) 227 | { 228 | return NULL; 229 | } 230 | 231 | int 232 | ASensorManager_destroyEventQueue(struct ASensorManager *manager, struct ASensorEventQueue *queue) 233 | { 234 | return 0; 235 | } 236 | 237 | // AInput 238 | 239 | struct AInputEvent { 240 | char nop; 241 | }; 242 | 243 | int32_t 244 | AInputEvent_getType(const struct AInputEvent *event) 245 | { 246 | return 0; 247 | } 248 | 249 | int32_t 250 | AInputEvent_getDeviceId(const struct AInputEvent *event) 251 | { 252 | return 0; 253 | } 254 | 255 | int32_t 256 | AInputEvent_getSource(const struct AInputEvent *event) 257 | { 258 | return 0; 259 | } 260 | 261 | int32_t 262 | AMotionEvent_getEdgeFlags(const struct AInputEvent *motion_event) 263 | { 264 | return 0; 265 | } 266 | 267 | float 268 | AMotionEvent_getTouchMajor(const struct AInputEvent *motion_event, size_t pointer_index) 269 | { 270 | return 0; 271 | } 272 | 273 | float 274 | AMotionEvent_getTouchMinor(const struct AInputEvent *motion_event, size_t pointer_index) 275 | { 276 | return 0; 277 | } 278 | 279 | int32_t 280 | AMotionEvent_getPointerId(const struct AInputEvent *motion_event, size_t pointer_index) 281 | { 282 | return 0; 283 | } 284 | 285 | int64_t 286 | AMotionEvent_getDownTime(const struct AInputEvent *motion_event) 287 | { 288 | return 0; 289 | } 290 | 291 | size_t 292 | AMotionEvent_getPointerCount(const struct AInputEvent *motion_event) 293 | { 294 | return 0; 295 | } 296 | 297 | float 298 | AMotionEvent_getXPrecision(const struct AInputEvent *motion_event) 299 | { 300 | return 0; 301 | } 302 | 303 | float 304 | AMotionEvent_getYPrecision(const struct AInputEvent *motion_event) 305 | { 306 | return 0; 307 | } 308 | 309 | float 310 | AMotionEvent_getToolMajor(const struct AInputEvent *motion_event, size_t pointer_index) 311 | { 312 | return 0; 313 | } 314 | 315 | float 316 | AMotionEvent_getToolMinor(const struct AInputEvent *motion_event, size_t pointer_index) 317 | { 318 | return 0; 319 | } 320 | 321 | float 322 | AMotionEvent_getX(const struct AInputEvent *motion_event, size_t pointer_index) 323 | { 324 | return 0; 325 | } 326 | 327 | float 328 | AMotionEvent_getY(const struct AInputEvent *motion_event, size_t pointer_index) 329 | { 330 | return 0; 331 | } 332 | 333 | float 334 | AMotionEvent_getSize(const struct AInputEvent *motion_event, size_t pointer_index) 335 | { 336 | return 0; 337 | } 338 | 339 | float 340 | AMotionEvent_getPressure(const struct AInputEvent *motion_event, size_t pointer_index) 341 | { 342 | return 0; 343 | } 344 | 345 | int64_t 346 | AMotionEvent_getEventTime(const struct AInputEvent *motion_event) 347 | { 348 | return 0; 349 | } 350 | 351 | int32_t 352 | AMotionEvent_getFlags(const struct AInputEvent *motion_event) 353 | { 354 | return 0; 355 | } 356 | 357 | int32_t 358 | AMotionEvent_getMetaState(const struct AInputEvent *motion_event) 359 | { 360 | return 0; 361 | } 362 | 363 | int32_t 364 | AMotionEvent_getAction(const struct AInputEvent *motion_event) 365 | { 366 | return 0; 367 | } 368 | 369 | size_t 370 | AMotionEvent_getHistorySize(const struct AInputEvent *motion_event) 371 | { 372 | return 0; 373 | } 374 | 375 | int64_t 376 | AMotionEvent_getHistoricalEventTime(const struct AInputEvent *motion_event, size_t history_index) 377 | { 378 | return 0; 379 | } 380 | 381 | size_t 382 | AMotionEvent_getHistoricalSize(const struct AInputEvent *motion_event, size_t pointer_index, size_t history_index) 383 | { 384 | return 0; 385 | } 386 | 387 | float 388 | AMotionEvent_getHistoricalPressure(const struct AInputEvent *motion_event, size_t pointer_index, size_t history_index) 389 | { 390 | return 0; 391 | } 392 | 393 | float 394 | AMotionEvent_getHistoricalX(const struct AInputEvent *motion_event, size_t pointer_index, size_t history_index) 395 | { 396 | return 0; 397 | } 398 | 399 | float 400 | AMotionEvent_getHistoricalY(const struct AInputEvent *motion_event, size_t pointer_index, size_t history_index) 401 | { 402 | return 0; 403 | } 404 | 405 | float 406 | AMotionEvent_getOrientation(const struct AInputEvent *motion_event, size_t pointer_index) 407 | { 408 | return 0; 409 | } 410 | 411 | int32_t 412 | AKeyEvent_getKeyCode(const struct AInputEvent *key_event) 413 | { 414 | return 0; 415 | } 416 | 417 | int32_t 418 | AKeyEvent_getMetaState(const struct AInputEvent *key_event) 419 | { 420 | return 0; 421 | } 422 | 423 | int32_t 424 | AKeyEvent_getAction(const struct AInputEvent *key_event) 425 | { 426 | return 0; 427 | } 428 | 429 | struct AInputQueue { 430 | char nop; 431 | }; 432 | 433 | void 434 | AInputQueue_attachLooper(struct AInputQueue *queue, struct ALooper *looper, int ident, ALooper_callbackFunc callback, void *data) 435 | { 436 | } 437 | 438 | void 439 | AInputQueue_detachLooper(struct AInputQueue *queue) 440 | { 441 | } 442 | 443 | int32_t 444 | AInputQueue_hasEvents(struct AInputQueue *queue) 445 | { 446 | return 0; 447 | } 448 | 449 | int32_t 450 | AInputQueue_getEvent(struct AInputQueue *queue, struct AInputEvent **outEvent) 451 | { 452 | return 0; 453 | } 454 | 455 | int32_t 456 | AInputQueue_preDispatchEvent(struct AInputQueue *queue, struct AInputEvent *event) 457 | { 458 | return 0; 459 | } 460 | 461 | void 462 | AInputQueue_finishEvent(struct AInputQueue *queue, struct AInputEvent *event, int handled) 463 | { 464 | } 465 | 466 | // ANative 467 | 468 | struct ANativeWindow { 469 | char header[4]; 470 | GLFWwindow *glfw; 471 | }; 472 | 473 | enum { 474 | WINDOW_FORMAT_RGBA_8888 = 1, 475 | WINDOW_FORMAT_RGBX_8888 = 2, 476 | WINDOW_FORMAT_RGB_565 = 4, 477 | }; 478 | 479 | struct ANativeWindow_Buffer { 480 | // The number of pixels that are show horizontally. 481 | int32_t width; 482 | 483 | // The number of pixels that are shown vertically. 484 | int32_t height; 485 | 486 | // The number of *pixels* that a line in the buffer takes in 487 | // memory. This may be >= width. 488 | int32_t stride; 489 | 490 | // The format of the buffer. One of WINDOW_FORMAT_* 491 | int32_t format; 492 | 493 | // The actual bits. 494 | void* bits; 495 | 496 | // Do not touch. 497 | uint32_t reserved[6]; 498 | }; 499 | 500 | struct ARect { 501 | int32_t left, top, right, bottom; 502 | }; 503 | 504 | static void 505 | glfw_error_cb(int code, const char *error) 506 | { 507 | fprintf(stderr, "glfw: (%d) %s\n", code, error); 508 | } 509 | 510 | struct ANativeWindow* 511 | ANativeWindow_fromSurface(JNIEnv* env, jobject surface) 512 | { 513 | assert(env && surface); 514 | 515 | struct ANativeWindow *window; 516 | if (!(window = calloc(1, sizeof(*window)))) 517 | return NULL; 518 | 519 | memcpy(window->header, "andr", sizeof(window->header)); 520 | 521 | glfwInit(); 522 | fprintf(stderr, "glfw: %s\n", glfwGetVersionString()); 523 | glfwSetErrorCallback(glfw_error_cb); 524 | glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); 525 | window->glfw = glfwCreateWindow(1024, 768, "ANativeWindow", NULL, NULL); 526 | assert(window->glfw); 527 | return window; 528 | } 529 | 530 | void 531 | ANativeWindow_acquire(struct ANativeWindow *window) 532 | { 533 | assert(window); 534 | // FIXME: refcount 535 | } 536 | 537 | void 538 | ANativeWindow_release(struct ANativeWindow *window) 539 | { 540 | assert(window); 541 | // FIXME: refcount 542 | } 543 | 544 | int32_t 545 | ANativeWindow_getWidth(struct ANativeWindow *window) 546 | { 547 | assert(window); 548 | int v = 0; 549 | glfwGetWindowSize(window->glfw, &v, NULL); 550 | return v; 551 | } 552 | 553 | int32_t 554 | ANativeWindow_getHeight(struct ANativeWindow *window) 555 | { 556 | assert(window); 557 | int v = 0; 558 | glfwGetWindowSize(window->glfw, NULL, &v); 559 | return v; 560 | } 561 | 562 | int32_t 563 | ANativeWindow_setBuffersGeometry(struct ANativeWindow *window, int32_t width, int32_t height, int32_t format) 564 | { 565 | assert(window); 566 | return 0; 567 | } 568 | 569 | int32_t 570 | ANativeWindow_lock(struct ANativeWindow *window, struct ANativeWindow_Buffer *outBuffer, struct ARect *inOutDirtyBounds) 571 | { 572 | assert(window); 573 | *outBuffer = (struct ANativeWindow_Buffer){0}; 574 | return 0; 575 | } 576 | 577 | int32_t 578 | ANativeWindow_unlockAndPost(struct ANativeWindow *window) 579 | { 580 | assert(window); 581 | return 0; 582 | } 583 | -------------------------------------------------------------------------------- /src/libc-antiantidebug.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int 7 | bionic_open(const char *path, int oflag, ...) 8 | { 9 | // Hide TracerPid from /proc/self/status for hideous apps that check for debugger. 10 | // Note, since /proc/self/status doesn't get updated anymore, this may break some stuff. 11 | // XXX: Turn this ON/OFF with env var maybe? 12 | if (!strcmp(path, "/proc/self/status")) { 13 | static FILE *faked = NULL; 14 | 15 | if (!faked) { 16 | static char status[4096]; 17 | 18 | { 19 | FILE *f = fopen(path, "rb"); 20 | assert(f && "/proc/self/status failed to open :/"); 21 | const size_t ret = fread(status, 1, sizeof(status), f); 22 | assert(ret <= sizeof(status) && "/proc/self/status doesn't fit in 4096 bytes :/"); 23 | fclose(f); 24 | } 25 | 26 | for (char *s, *e; (s = strstr(status, "TracerPid:\t"));) { 27 | for (e = s; (size_t)(e - status) < sizeof(status) && *e && *e != '\n'; ++e); 28 | memmove(s, e, sizeof(status) - (e - status)); 29 | break; 30 | } 31 | 32 | faked = fmemopen(status, sizeof(status), "rb"); 33 | assert(faked && "fmemopen failed :/"); 34 | } 35 | 36 | return fileno(faked); 37 | } 38 | 39 | return open(path, oflag); 40 | } 41 | -------------------------------------------------------------------------------- /src/libc-bsd.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | extern const char *__progname; 5 | 6 | static char* 7 | strrchr_safe(const char *s, int c) 8 | { 9 | char *r = (char*)strrchr(s, c); 10 | return (r ? r : (char*)s); 11 | } 12 | 13 | const char* 14 | bionic_getprogname(void) 15 | { 16 | return __progname; 17 | } 18 | 19 | void 20 | bionic_setprogname(const char *progname) 21 | { 22 | __progname = strrchr_safe(progname, '/') + 1; 23 | } 24 | 25 | -------------------------------------------------------------------------------- /src/libc-ctype.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define C_TYPE_NUM_CHARS 256 4 | 5 | #define _U 0x01 6 | #define _L 0x02 7 | #define _D 0x04 8 | #define _S 0x08 9 | #define _P 0x10 10 | #define _C 0x20 11 | #define _X 0x40 12 | #define _B 0x80 13 | #define _R (_P|_U|_L|_D|_B) 14 | #define _A (_L|_U) 15 | 16 | /* _N was added to NDK r10 and is expected by gnu-libstdc++ */ 17 | #define _N _D 18 | 19 | static const char ctype[1 + C_TYPE_NUM_CHARS] = { 20 | 0, 21 | _C, _C, _C, _C, _C, _C, _C, _C, 22 | _C, _C|_S, _C|_S, _C|_S, _C|_S, _C|_S, _C, _C, 23 | _C, _C, _C, _C, _C, _C, _C, _C, 24 | _C, _C, _C, _C, _C, _C, _C, _C, 25 | _S|(char)_B, _P, _P, _P, _P, _P, _P, _P, 26 | _P, _P, _P, _P, _P, _P, _P, _P, 27 | _N, _N, _N, _N, _N, _N, _N, _N, 28 | _N, _N, _P, _P, _P, _P, _P, _P, 29 | _P, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U|_X, _U, 30 | _U, _U, _U, _U, _U, _U, _U, _U, 31 | _U, _U, _U, _U, _U, _U, _U, _U, 32 | _U, _U, _U, _P, _P, _P, _P, _P, 33 | _P, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L|_X, _L, 34 | _L, _L, _L, _L, _L, _L, _L, _L, 35 | _L, _L, _L, _L, _L, _L, _L, _L, 36 | _L, _L, _L, _P, _P, _P, _P, _C, 37 | 38 | 0, 0, 0, 0, 0, 0, 0, 0, /* 80 */ 39 | 0, 0, 0, 0, 0, 0, 0, 0, /* 88 */ 40 | 0, 0, 0, 0, 0, 0, 0, 0, /* 90 */ 41 | 0, 0, 0, 0, 0, 0, 0, 0, /* 98 */ 42 | 0, 0, 0, 0, 0, 0, 0, 0, /* A0 */ 43 | 0, 0, 0, 0, 0, 0, 0, 0, /* A8 */ 44 | 0, 0, 0, 0, 0, 0, 0, 0, /* B0 */ 45 | 0, 0, 0, 0, 0, 0, 0, 0, /* B8 */ 46 | 0, 0, 0, 0, 0, 0, 0, 0, /* C0 */ 47 | 0, 0, 0, 0, 0, 0, 0, 0, /* C8 */ 48 | 0, 0, 0, 0, 0, 0, 0, 0, /* D0 */ 49 | 0, 0, 0, 0, 0, 0, 0, 0, /* D8 */ 50 | 0, 0, 0, 0, 0, 0, 0, 0, /* E0 */ 51 | 0, 0, 0, 0, 0, 0, 0, 0, /* E8 */ 52 | 0, 0, 0, 0, 0, 0, 0, 0, /* F0 */ 53 | 0, 0, 0, 0, 0, 0, 0, 0 /* F8 */ 54 | }; 55 | 56 | const char *bionic__ctype_ = ctype; 57 | 58 | static const short tolower_tab[1 + C_TYPE_NUM_CHARS] = { 59 | EOF, 60 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 61 | 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 62 | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 63 | 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 64 | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 65 | 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 66 | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 67 | 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 68 | 0x40, 'a', 'b', 'c', 'd', 'e', 'f', 'g', 69 | 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 70 | 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 71 | 'x', 'y', 'z', 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 72 | 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 73 | 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 74 | 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 75 | 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 76 | 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 77 | 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 78 | 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 79 | 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 80 | 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 81 | 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 82 | 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 83 | 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 84 | 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 85 | 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 86 | 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 87 | 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 88 | 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 89 | 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 90 | 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 91 | 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff 92 | }; 93 | 94 | const short *bionic__tolower_tab_ = tolower_tab; 95 | 96 | static const short toupper_tab[1 + C_TYPE_NUM_CHARS] = { 97 | EOF, 98 | 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 99 | 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 100 | 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 101 | 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 102 | 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 103 | 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 104 | 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 105 | 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 106 | 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 107 | 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 108 | 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 109 | 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 110 | 0x60, 'A', 'B', 'C', 'D', 'E', 'F', 'G', 111 | 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 112 | 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 113 | 'X', 'Y', 'Z', 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 114 | 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 115 | 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 116 | 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 117 | 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 118 | 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 119 | 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 120 | 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 121 | 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 122 | 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 123 | 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 124 | 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 125 | 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 126 | 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 127 | 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 128 | 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 129 | 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff 130 | }; 131 | 132 | const short *bionic__toupper_tab_ = toupper_tab; 133 | 134 | #undef _U 135 | #undef _L 136 | #undef _D 137 | #undef _S 138 | #undef _P 139 | #undef _C 140 | #undef _X 141 | #undef _B 142 | #undef _R 143 | #undef _A 144 | #undef _N 145 | #undef C_TYPE_NUM_CHARS 146 | -------------------------------------------------------------------------------- /src/libc-sha1.c: -------------------------------------------------------------------------------- 1 | /* 2 | SHA-1 in C 3 | By Steve Reid 4 | 100% Public Domain 5 | */ 6 | 7 | #include 8 | 9 | typedef struct 10 | { 11 | uint32_t state[5]; 12 | uint32_t count[2]; 13 | unsigned char buffer[64]; 14 | } SHA1_CTX; 15 | 16 | /* 17 | Test Vectors (from FIPS PUB 180-1) 18 | "abc" 19 | A9993E36 4706816A BA3E2571 7850C26C 9CD0D89D 20 | "abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq" 21 | 84983E44 1C3BD26E BAAE4AA1 F95129E5 E54670F1 22 | A million repetitions of "a" 23 | 34AA973C D4C4DAA4 F61EEB2B DBAD2731 6534016F 24 | */ 25 | 26 | /* #define LITTLE_ENDIAN * This should be #define'd already, if true. */ 27 | /* #define SHA1HANDSOFF * Copies data before messing with it. */ 28 | 29 | #define SHA1HANDSOFF 30 | 31 | #include 32 | #include 33 | 34 | #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) 35 | 36 | /* blk0() and blk() perform the initial expand. */ 37 | /* I got the idea of expanding during the round function from SSLeay */ 38 | #if BYTE_ORDER == LITTLE_ENDIAN 39 | #define blk0(i) (block->l[i] = (rol(block->l[i],24)&0xFF00FF00) \ 40 | |(rol(block->l[i],8)&0x00FF00FF)) 41 | #elif BYTE_ORDER == BIG_ENDIAN 42 | #define blk0(i) block->l[i] 43 | #else 44 | #error "Endianness not defined!" 45 | #endif 46 | #define blk(i) (block->l[i&15] = rol(block->l[(i+13)&15]^block->l[(i+8)&15] \ 47 | ^block->l[(i+2)&15]^block->l[i&15],1)) 48 | 49 | /* (R0+R1), R2, R3, R4 are the different operations used in SHA1 */ 50 | #define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30); 51 | #define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30); 52 | #define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30); 53 | #define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30); 54 | #define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30); 55 | 56 | 57 | /* Hash a single 512-bit block. This is the core of the algorithm. */ 58 | 59 | void SHA1Transform( 60 | uint32_t state[5], 61 | const unsigned char buffer[64] 62 | ) 63 | { 64 | uint32_t a, b, c, d, e; 65 | 66 | typedef union 67 | { 68 | unsigned char c[64]; 69 | uint32_t l[16]; 70 | } CHAR64LONG16; 71 | 72 | #ifdef SHA1HANDSOFF 73 | CHAR64LONG16 block[1]; /* use array to appear as a pointer */ 74 | 75 | memcpy(block, buffer, 64); 76 | #else 77 | /* The following had better never be used because it causes the 78 | * pointer-to-const buffer to be cast into a pointer to non-const. 79 | * And the result is written through. I threw a "const" in, hoping 80 | * this will cause a diagnostic. 81 | */ 82 | CHAR64LONG16 *block = (const CHAR64LONG16 *) buffer; 83 | #endif 84 | /* Copy context->state[] to working vars */ 85 | a = state[0]; 86 | b = state[1]; 87 | c = state[2]; 88 | d = state[3]; 89 | e = state[4]; 90 | /* 4 rounds of 20 operations each. Loop unrolled. */ 91 | R0(a, b, c, d, e, 0); 92 | R0(e, a, b, c, d, 1); 93 | R0(d, e, a, b, c, 2); 94 | R0(c, d, e, a, b, 3); 95 | R0(b, c, d, e, a, 4); 96 | R0(a, b, c, d, e, 5); 97 | R0(e, a, b, c, d, 6); 98 | R0(d, e, a, b, c, 7); 99 | R0(c, d, e, a, b, 8); 100 | R0(b, c, d, e, a, 9); 101 | R0(a, b, c, d, e, 10); 102 | R0(e, a, b, c, d, 11); 103 | R0(d, e, a, b, c, 12); 104 | R0(c, d, e, a, b, 13); 105 | R0(b, c, d, e, a, 14); 106 | R0(a, b, c, d, e, 15); 107 | R1(e, a, b, c, d, 16); 108 | R1(d, e, a, b, c, 17); 109 | R1(c, d, e, a, b, 18); 110 | R1(b, c, d, e, a, 19); 111 | R2(a, b, c, d, e, 20); 112 | R2(e, a, b, c, d, 21); 113 | R2(d, e, a, b, c, 22); 114 | R2(c, d, e, a, b, 23); 115 | R2(b, c, d, e, a, 24); 116 | R2(a, b, c, d, e, 25); 117 | R2(e, a, b, c, d, 26); 118 | R2(d, e, a, b, c, 27); 119 | R2(c, d, e, a, b, 28); 120 | R2(b, c, d, e, a, 29); 121 | R2(a, b, c, d, e, 30); 122 | R2(e, a, b, c, d, 31); 123 | R2(d, e, a, b, c, 32); 124 | R2(c, d, e, a, b, 33); 125 | R2(b, c, d, e, a, 34); 126 | R2(a, b, c, d, e, 35); 127 | R2(e, a, b, c, d, 36); 128 | R2(d, e, a, b, c, 37); 129 | R2(c, d, e, a, b, 38); 130 | R2(b, c, d, e, a, 39); 131 | R3(a, b, c, d, e, 40); 132 | R3(e, a, b, c, d, 41); 133 | R3(d, e, a, b, c, 42); 134 | R3(c, d, e, a, b, 43); 135 | R3(b, c, d, e, a, 44); 136 | R3(a, b, c, d, e, 45); 137 | R3(e, a, b, c, d, 46); 138 | R3(d, e, a, b, c, 47); 139 | R3(c, d, e, a, b, 48); 140 | R3(b, c, d, e, a, 49); 141 | R3(a, b, c, d, e, 50); 142 | R3(e, a, b, c, d, 51); 143 | R3(d, e, a, b, c, 52); 144 | R3(c, d, e, a, b, 53); 145 | R3(b, c, d, e, a, 54); 146 | R3(a, b, c, d, e, 55); 147 | R3(e, a, b, c, d, 56); 148 | R3(d, e, a, b, c, 57); 149 | R3(c, d, e, a, b, 58); 150 | R3(b, c, d, e, a, 59); 151 | R4(a, b, c, d, e, 60); 152 | R4(e, a, b, c, d, 61); 153 | R4(d, e, a, b, c, 62); 154 | R4(c, d, e, a, b, 63); 155 | R4(b, c, d, e, a, 64); 156 | R4(a, b, c, d, e, 65); 157 | R4(e, a, b, c, d, 66); 158 | R4(d, e, a, b, c, 67); 159 | R4(c, d, e, a, b, 68); 160 | R4(b, c, d, e, a, 69); 161 | R4(a, b, c, d, e, 70); 162 | R4(e, a, b, c, d, 71); 163 | R4(d, e, a, b, c, 72); 164 | R4(c, d, e, a, b, 73); 165 | R4(b, c, d, e, a, 74); 166 | R4(a, b, c, d, e, 75); 167 | R4(e, a, b, c, d, 76); 168 | R4(d, e, a, b, c, 77); 169 | R4(c, d, e, a, b, 78); 170 | R4(b, c, d, e, a, 79); 171 | /* Add the working vars back into context.state[] */ 172 | state[0] += a; 173 | state[1] += b; 174 | state[2] += c; 175 | state[3] += d; 176 | state[4] += e; 177 | /* Wipe variables */ 178 | a = b = c = d = e = 0; 179 | #ifdef SHA1HANDSOFF 180 | memset(block, '\0', sizeof(block)); 181 | #endif 182 | } 183 | 184 | 185 | /* SHA1Init - Initialize new context */ 186 | 187 | void SHA1Init( 188 | SHA1_CTX * context 189 | ) 190 | { 191 | /* SHA1 initialization constants */ 192 | context->state[0] = 0x67452301; 193 | context->state[1] = 0xEFCDAB89; 194 | context->state[2] = 0x98BADCFE; 195 | context->state[3] = 0x10325476; 196 | context->state[4] = 0xC3D2E1F0; 197 | context->count[0] = context->count[1] = 0; 198 | } 199 | 200 | 201 | /* Run your data through this. */ 202 | 203 | void SHA1Update( 204 | SHA1_CTX * context, 205 | const unsigned char *data, 206 | uint32_t len 207 | ) 208 | { 209 | uint32_t i; 210 | 211 | uint32_t j; 212 | 213 | j = context->count[0]; 214 | if ((context->count[0] += len << 3) < j) 215 | context->count[1]++; 216 | context->count[1] += (len >> 29); 217 | j = (j >> 3) & 63; 218 | if ((j + len) > 63) 219 | { 220 | memcpy(&context->buffer[j], data, (i = 64 - j)); 221 | SHA1Transform(context->state, context->buffer); 222 | for (; i + 63 < len; i += 64) 223 | { 224 | SHA1Transform(context->state, &data[i]); 225 | } 226 | j = 0; 227 | } 228 | else 229 | i = 0; 230 | memcpy(&context->buffer[j], &data[i], len - i); 231 | } 232 | 233 | 234 | /* Add padding and return the message digest. */ 235 | 236 | void SHA1Final( 237 | unsigned char digest[20], 238 | SHA1_CTX * context 239 | ) 240 | { 241 | unsigned i; 242 | 243 | unsigned char finalcount[8]; 244 | 245 | unsigned char c; 246 | 247 | #if 0 /* untested "improvement" by DHR */ 248 | /* Convert context->count to a sequence of bytes 249 | * in finalcount. Second element first, but 250 | * big-endian order within element. 251 | * But we do it all backwards. 252 | */ 253 | unsigned char *fcp = &finalcount[8]; 254 | 255 | for (i = 0; i < 2; i++) 256 | { 257 | uint32_t t = context->count[i]; 258 | 259 | int j; 260 | 261 | for (j = 0; j < 4; t >>= 8, j++) 262 | *--fcp = (unsigned char) t} 263 | #else 264 | for (i = 0; i < 8; i++) 265 | { 266 | finalcount[i] = (unsigned char) ((context->count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255); /* Endian independent */ 267 | } 268 | #endif 269 | c = 0200; 270 | SHA1Update(context, &c, 1); 271 | while ((context->count[0] & 504) != 448) 272 | { 273 | c = 0000; 274 | SHA1Update(context, &c, 1); 275 | } 276 | SHA1Update(context, finalcount, 8); /* Should cause a SHA1Transform() */ 277 | for (i = 0; i < 20; i++) 278 | { 279 | digest[i] = (unsigned char) 280 | ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); 281 | } 282 | /* Wipe variables */ 283 | memset(context, '\0', sizeof(*context)); 284 | memset(&finalcount, '\0', sizeof(finalcount)); 285 | } 286 | 287 | void SHA1( 288 | char *hash_out, 289 | const char *str, 290 | int len) 291 | { 292 | SHA1_CTX ctx; 293 | int ii; 294 | 295 | SHA1Init(&ctx); 296 | for (ii=0; ii 2 | 3 | struct bionic___sFILE { 4 | #if defined(__LP64__) 5 | char __private[152]; 6 | #else 7 | char __private[84]; 8 | #endif 9 | } __attribute__((aligned(sizeof(void*)))); 10 | 11 | // Bionic standard stream support pre-M Android 12 | // Post-M it's saner and they point to stdin/stdout/stderr symbols instead 13 | const struct bionic___sFILE bionic___sF[3] = { 14 | {{ 's', 't', 'd', 'i', 'n' }}, 15 | {{ 's', 't', 'd', 'o', 'u', 't' }}, 16 | {{ 's', 't', 'd', 'e', 'r', 'r' }} 17 | }; 18 | 19 | static inline FILE* 20 | bionic_file_to_glibc_file(FILE *f) 21 | { 22 | if (f == (void*)&bionic___sF[0]) 23 | return stdin; 24 | else if (f == (void*)&bionic___sF[1]) 25 | return stdout; 26 | else if (f == (void*)&bionic___sF[2]) 27 | return stderr; 28 | return f; 29 | } 30 | 31 | // libstdc++ uses these directly for standard streams, thus we need to wrap em 32 | // and IO_file wraps aren't enough. 33 | 34 | int 35 | bionic_fflush(FILE *f) 36 | { 37 | return fflush(bionic_file_to_glibc_file(f)); 38 | } 39 | 40 | size_t 41 | bionic_fwrite(const void *ptr, size_t size, size_t nmemb, FILE *stream) 42 | { 43 | return fwrite(ptr, size, nmemb, bionic_file_to_glibc_file(stream)); 44 | } 45 | 46 | int 47 | bionic_putc(int ch, FILE *f) 48 | { 49 | return putc(ch, bionic_file_to_glibc_file(f)); 50 | } 51 | 52 | // Wrapping internal glibc VTABLE functions to handle bionic's pre-M crap 53 | // We define __real_IO_file_xsputn in libc.c so linker will link our library, 54 | // it's not used however for anything. 55 | 56 | extern size_t 57 | __real_IO_file_xsputn(FILE *f, const void *buf, size_t n); 58 | 59 | size_t 60 | __wrap_IO_file_xsputn(FILE *f, const void *buf, size_t n) 61 | { 62 | return __real_IO_file_xsputn(bionic_file_to_glibc_file(f), buf, n); 63 | } 64 | -------------------------------------------------------------------------------- /src/libc-sysconf.h: -------------------------------------------------------------------------------- 1 | // generated with: 2 | // grep '^#define _SC' | awk 'BEGIN { print "static inline int\nbionic_sysconf_to_glibc_sysconf(int name)\n{\n switch (name) {" } { printf "#ifdef %s\n case %s: return %s;\n#endif\n", $2, $3, $2 } END { print " default:\n fprintf(stderr, \"sysconf constant (%d) is not mapped\\n\", name);\n abort();\n }\n return 0xFFFF;\n}" }' 3 | // from bionic's bits/sysconf.h 4 | 5 | static inline int 6 | bionic_sysconf_to_glibc_sysconf(int name) 7 | { 8 | switch (name) { 9 | #ifdef _SC_ARG_MAX 10 | case 0x0000: return _SC_ARG_MAX; 11 | #endif 12 | #ifdef _SC_BC_BASE_MAX 13 | case 0x0001: return _SC_BC_BASE_MAX; 14 | #endif 15 | #ifdef _SC_BC_DIM_MAX 16 | case 0x0002: return _SC_BC_DIM_MAX; 17 | #endif 18 | #ifdef _SC_BC_SCALE_MAX 19 | case 0x0003: return _SC_BC_SCALE_MAX; 20 | #endif 21 | #ifdef _SC_BC_STRING_MAX 22 | case 0x0004: return _SC_BC_STRING_MAX; 23 | #endif 24 | #ifdef _SC_CHILD_MAX 25 | case 0x0005: return _SC_CHILD_MAX; 26 | #endif 27 | #ifdef _SC_CLK_TCK 28 | case 0x0006: return _SC_CLK_TCK; 29 | #endif 30 | #ifdef _SC_COLL_WEIGHTS_MAX 31 | case 0x0007: return _SC_COLL_WEIGHTS_MAX; 32 | #endif 33 | #ifdef _SC_EXPR_NEST_MAX 34 | case 0x0008: return _SC_EXPR_NEST_MAX; 35 | #endif 36 | #ifdef _SC_LINE_MAX 37 | case 0x0009: return _SC_LINE_MAX; 38 | #endif 39 | #ifdef _SC_NGROUPS_MAX 40 | case 0x000a: return _SC_NGROUPS_MAX; 41 | #endif 42 | #ifdef _SC_OPEN_MAX 43 | case 0x000b: return _SC_OPEN_MAX; 44 | #endif 45 | #ifdef _SC_PASS_MAX 46 | case 0x000c: return _SC_PASS_MAX; 47 | #endif 48 | #ifdef _SC_2_C_BIND 49 | case 0x000d: return _SC_2_C_BIND; 50 | #endif 51 | #ifdef _SC_2_C_DEV 52 | case 0x000e: return _SC_2_C_DEV; 53 | #endif 54 | #ifdef _SC_2_C_VERSION 55 | case 0x000f: return _SC_2_C_VERSION; 56 | #endif 57 | #ifdef _SC_2_CHAR_TERM 58 | case 0x0010: return _SC_2_CHAR_TERM; 59 | #endif 60 | #ifdef _SC_2_FORT_DEV 61 | case 0x0011: return _SC_2_FORT_DEV; 62 | #endif 63 | #ifdef _SC_2_FORT_RUN 64 | case 0x0012: return _SC_2_FORT_RUN; 65 | #endif 66 | #ifdef _SC_2_LOCALEDEF 67 | case 0x0013: return _SC_2_LOCALEDEF; 68 | #endif 69 | #ifdef _SC_2_SW_DEV 70 | case 0x0014: return _SC_2_SW_DEV; 71 | #endif 72 | #ifdef _SC_2_UPE 73 | case 0x0015: return _SC_2_UPE; 74 | #endif 75 | #ifdef _SC_2_VERSION 76 | case 0x0016: return _SC_2_VERSION; 77 | #endif 78 | #ifdef _SC_JOB_CONTROL 79 | case 0x0017: return _SC_JOB_CONTROL; 80 | #endif 81 | #ifdef _SC_SAVED_IDS 82 | case 0x0018: return _SC_SAVED_IDS; 83 | #endif 84 | #ifdef _SC_VERSION 85 | case 0x0019: return _SC_VERSION; 86 | #endif 87 | #ifdef _SC_RE_DUP_MAX 88 | case 0x001a: return _SC_RE_DUP_MAX; 89 | #endif 90 | #ifdef _SC_STREAM_MAX 91 | case 0x001b: return _SC_STREAM_MAX; 92 | #endif 93 | #ifdef _SC_TZNAME_MAX 94 | case 0x001c: return _SC_TZNAME_MAX; 95 | #endif 96 | #ifdef _SC_XOPEN_CRYPT 97 | case 0x001d: return _SC_XOPEN_CRYPT; 98 | #endif 99 | #ifdef _SC_XOPEN_ENH_I18N 100 | case 0x001e: return _SC_XOPEN_ENH_I18N; 101 | #endif 102 | #ifdef _SC_XOPEN_SHM 103 | case 0x001f: return _SC_XOPEN_SHM; 104 | #endif 105 | #ifdef _SC_XOPEN_VERSION 106 | case 0x0020: return _SC_XOPEN_VERSION; 107 | #endif 108 | #ifdef _SC_XOPEN_XCU_VERSION 109 | case 0x0021: return _SC_XOPEN_XCU_VERSION; 110 | #endif 111 | #ifdef _SC_XOPEN_REALTIME 112 | case 0x0022: return _SC_XOPEN_REALTIME; 113 | #endif 114 | #ifdef _SC_XOPEN_REALTIME_THREADS 115 | case 0x0023: return _SC_XOPEN_REALTIME_THREADS; 116 | #endif 117 | #ifdef _SC_XOPEN_LEGACY 118 | case 0x0024: return _SC_XOPEN_LEGACY; 119 | #endif 120 | #ifdef _SC_ATEXIT_MAX 121 | case 0x0025: return _SC_ATEXIT_MAX; 122 | #endif 123 | #ifdef _SC_IOV_MAX 124 | case 0x0026: return _SC_IOV_MAX; 125 | #endif 126 | #ifdef _SC_PAGESIZE 127 | case 0x0027: return _SC_PAGESIZE; 128 | #endif 129 | #ifdef _SC_PAGE_SIZE 130 | case 0x0028: return _SC_PAGE_SIZE; 131 | #endif 132 | #ifdef _SC_XOPEN_UNIX 133 | case 0x0029: return _SC_XOPEN_UNIX; 134 | #endif 135 | #ifdef _SC_XBS5_ILP32_OFF32 136 | case 0x002a: return _SC_XBS5_ILP32_OFF32; 137 | #endif 138 | #ifdef _SC_XBS5_ILP32_OFFBIG 139 | case 0x002b: return _SC_XBS5_ILP32_OFFBIG; 140 | #endif 141 | #ifdef _SC_XBS5_LP64_OFF64 142 | case 0x002c: return _SC_XBS5_LP64_OFF64; 143 | #endif 144 | #ifdef _SC_XBS5_LPBIG_OFFBIG 145 | case 0x002d: return _SC_XBS5_LPBIG_OFFBIG; 146 | #endif 147 | #ifdef _SC_AIO_LISTIO_MAX 148 | case 0x002e: return _SC_AIO_LISTIO_MAX; 149 | #endif 150 | #ifdef _SC_AIO_MAX 151 | case 0x002f: return _SC_AIO_MAX; 152 | #endif 153 | #ifdef _SC_AIO_PRIO_DELTA_MAX 154 | case 0x0030: return _SC_AIO_PRIO_DELTA_MAX; 155 | #endif 156 | #ifdef _SC_DELAYTIMER_MAX 157 | case 0x0031: return _SC_DELAYTIMER_MAX; 158 | #endif 159 | #ifdef _SC_MQ_OPEN_MAX 160 | case 0x0032: return _SC_MQ_OPEN_MAX; 161 | #endif 162 | #ifdef _SC_MQ_PRIO_MAX 163 | case 0x0033: return _SC_MQ_PRIO_MAX; 164 | #endif 165 | #ifdef _SC_RTSIG_MAX 166 | case 0x0034: return _SC_RTSIG_MAX; 167 | #endif 168 | #ifdef _SC_SEM_NSEMS_MAX 169 | case 0x0035: return _SC_SEM_NSEMS_MAX; 170 | #endif 171 | #ifdef _SC_SEM_VALUE_MAX 172 | case 0x0036: return _SC_SEM_VALUE_MAX; 173 | #endif 174 | #ifdef _SC_SIGQUEUE_MAX 175 | case 0x0037: return _SC_SIGQUEUE_MAX; 176 | #endif 177 | #ifdef _SC_TIMER_MAX 178 | case 0x0038: return _SC_TIMER_MAX; 179 | #endif 180 | #ifdef _SC_ASYNCHRONOUS_IO 181 | case 0x0039: return _SC_ASYNCHRONOUS_IO; 182 | #endif 183 | #ifdef _SC_FSYNC 184 | case 0x003a: return _SC_FSYNC; 185 | #endif 186 | #ifdef _SC_MAPPED_FILES 187 | case 0x003b: return _SC_MAPPED_FILES; 188 | #endif 189 | #ifdef _SC_MEMLOCK 190 | case 0x003c: return _SC_MEMLOCK; 191 | #endif 192 | #ifdef _SC_MEMLOCK_RANGE 193 | case 0x003d: return _SC_MEMLOCK_RANGE; 194 | #endif 195 | #ifdef _SC_MEMORY_PROTECTION 196 | case 0x003e: return _SC_MEMORY_PROTECTION; 197 | #endif 198 | #ifdef _SC_MESSAGE_PASSING 199 | case 0x003f: return _SC_MESSAGE_PASSING; 200 | #endif 201 | #ifdef _SC_PRIORITIZED_IO 202 | case 0x0040: return _SC_PRIORITIZED_IO; 203 | #endif 204 | #ifdef _SC_PRIORITY_SCHEDULING 205 | case 0x0041: return _SC_PRIORITY_SCHEDULING; 206 | #endif 207 | #ifdef _SC_REALTIME_SIGNALS 208 | case 0x0042: return _SC_REALTIME_SIGNALS; 209 | #endif 210 | #ifdef _SC_SEMAPHORES 211 | case 0x0043: return _SC_SEMAPHORES; 212 | #endif 213 | #ifdef _SC_SHARED_MEMORY_OBJECTS 214 | case 0x0044: return _SC_SHARED_MEMORY_OBJECTS; 215 | #endif 216 | #ifdef _SC_SYNCHRONIZED_IO 217 | case 0x0045: return _SC_SYNCHRONIZED_IO; 218 | #endif 219 | #ifdef _SC_TIMERS 220 | case 0x0046: return _SC_TIMERS; 221 | #endif 222 | #ifdef _SC_GETGR_R_SIZE_MAX 223 | case 0x0047: return _SC_GETGR_R_SIZE_MAX; 224 | #endif 225 | #ifdef _SC_GETPW_R_SIZE_MAX 226 | case 0x0048: return _SC_GETPW_R_SIZE_MAX; 227 | #endif 228 | #ifdef _SC_LOGIN_NAME_MAX 229 | case 0x0049: return _SC_LOGIN_NAME_MAX; 230 | #endif 231 | #ifdef _SC_THREAD_DESTRUCTOR_ITERATIONS 232 | case 0x004a: return _SC_THREAD_DESTRUCTOR_ITERATIONS; 233 | #endif 234 | #ifdef _SC_THREAD_KEYS_MAX 235 | case 0x004b: return _SC_THREAD_KEYS_MAX; 236 | #endif 237 | #ifdef _SC_THREAD_STACK_MIN 238 | case 0x004c: return _SC_THREAD_STACK_MIN; 239 | #endif 240 | #ifdef _SC_THREAD_THREADS_MAX 241 | case 0x004d: return _SC_THREAD_THREADS_MAX; 242 | #endif 243 | #ifdef _SC_TTY_NAME_MAX 244 | case 0x004e: return _SC_TTY_NAME_MAX; 245 | #endif 246 | #ifdef _SC_THREADS 247 | case 0x004f: return _SC_THREADS; 248 | #endif 249 | #ifdef _SC_THREAD_ATTR_STACKADDR 250 | case 0x0050: return _SC_THREAD_ATTR_STACKADDR; 251 | #endif 252 | #ifdef _SC_THREAD_ATTR_STACKSIZE 253 | case 0x0051: return _SC_THREAD_ATTR_STACKSIZE; 254 | #endif 255 | #ifdef _SC_THREAD_PRIORITY_SCHEDULING 256 | case 0x0052: return _SC_THREAD_PRIORITY_SCHEDULING; 257 | #endif 258 | #ifdef _SC_THREAD_PRIO_INHERIT 259 | case 0x0053: return _SC_THREAD_PRIO_INHERIT; 260 | #endif 261 | #ifdef _SC_THREAD_PRIO_PROTECT 262 | case 0x0054: return _SC_THREAD_PRIO_PROTECT; 263 | #endif 264 | #ifdef _SC_THREAD_SAFE_FUNCTIONS 265 | case 0x0055: return _SC_THREAD_SAFE_FUNCTIONS; 266 | #endif 267 | #ifdef _SC_NPROCESSORS_CONF 268 | case 0x0060: return _SC_NPROCESSORS_CONF; 269 | #endif 270 | #ifdef _SC_NPROCESSORS_ONLN 271 | case 0x0061: return _SC_NPROCESSORS_ONLN; 272 | #endif 273 | #ifdef _SC_PHYS_PAGES 274 | case 0x0062: return _SC_PHYS_PAGES; 275 | #endif 276 | #ifdef _SC_AVPHYS_PAGES 277 | case 0x0063: return _SC_AVPHYS_PAGES; 278 | #endif 279 | #ifdef _SC_MONOTONIC_CLOCK 280 | case 0x0064: return _SC_MONOTONIC_CLOCK; 281 | #endif 282 | #ifdef _SC_2_PBS 283 | case 0x0065: return _SC_2_PBS; 284 | #endif 285 | #ifdef _SC_2_PBS_ACCOUNTING 286 | case 0x0066: return _SC_2_PBS_ACCOUNTING; 287 | #endif 288 | #ifdef _SC_2_PBS_CHECKPOINT 289 | case 0x0067: return _SC_2_PBS_CHECKPOINT; 290 | #endif 291 | #ifdef _SC_2_PBS_LOCATE 292 | case 0x0068: return _SC_2_PBS_LOCATE; 293 | #endif 294 | #ifdef _SC_2_PBS_MESSAGE 295 | case 0x0069: return _SC_2_PBS_MESSAGE; 296 | #endif 297 | #ifdef _SC_2_PBS_TRACK 298 | case 0x006a: return _SC_2_PBS_TRACK; 299 | #endif 300 | #ifdef _SC_ADVISORY_INFO 301 | case 0x006b: return _SC_ADVISORY_INFO; 302 | #endif 303 | #ifdef _SC_BARRIERS 304 | case 0x006c: return _SC_BARRIERS; 305 | #endif 306 | #ifdef _SC_CLOCK_SELECTION 307 | case 0x006d: return _SC_CLOCK_SELECTION; 308 | #endif 309 | #ifdef _SC_CPUTIME 310 | case 0x006e: return _SC_CPUTIME; 311 | #endif 312 | #ifdef _SC_HOST_NAME_MAX 313 | case 0x006f: return _SC_HOST_NAME_MAX; 314 | #endif 315 | #ifdef _SC_IPV6 316 | case 0x0070: return _SC_IPV6; 317 | #endif 318 | #ifdef _SC_RAW_SOCKETS 319 | case 0x0071: return _SC_RAW_SOCKETS; 320 | #endif 321 | #ifdef _SC_READER_WRITER_LOCKS 322 | case 0x0072: return _SC_READER_WRITER_LOCKS; 323 | #endif 324 | #ifdef _SC_REGEXP 325 | case 0x0073: return _SC_REGEXP; 326 | #endif 327 | #ifdef _SC_SHELL 328 | case 0x0074: return _SC_SHELL; 329 | #endif 330 | #ifdef _SC_SPAWN 331 | case 0x0075: return _SC_SPAWN; 332 | #endif 333 | #ifdef _SC_SPIN_LOCKS 334 | case 0x0076: return _SC_SPIN_LOCKS; 335 | #endif 336 | #ifdef _SC_SPORADIC_SERVER 337 | case 0x0077: return _SC_SPORADIC_SERVER; 338 | #endif 339 | #ifdef _SC_SS_REPL_MAX 340 | case 0x0078: return _SC_SS_REPL_MAX; 341 | #endif 342 | #ifdef _SC_SYMLOOP_MAX 343 | case 0x0079: return _SC_SYMLOOP_MAX; 344 | #endif 345 | #ifdef _SC_THREAD_CPUTIME 346 | case 0x007a: return _SC_THREAD_CPUTIME; 347 | #endif 348 | #ifdef _SC_THREAD_PROCESS_SHARED 349 | case 0x007b: return _SC_THREAD_PROCESS_SHARED; 350 | #endif 351 | #ifdef _SC_THREAD_ROBUST_PRIO_INHERIT 352 | case 0x007c: return _SC_THREAD_ROBUST_PRIO_INHERIT; 353 | #endif 354 | #ifdef _SC_THREAD_ROBUST_PRIO_PROTECT 355 | case 0x007d: return _SC_THREAD_ROBUST_PRIO_PROTECT; 356 | #endif 357 | #ifdef _SC_THREAD_SPORADIC_SERVER 358 | case 0x007e: return _SC_THREAD_SPORADIC_SERVER; 359 | #endif 360 | #ifdef _SC_TIMEOUTS 361 | case 0x007f: return _SC_TIMEOUTS; 362 | #endif 363 | #ifdef _SC_TRACE 364 | case 0x0080: return _SC_TRACE; 365 | #endif 366 | #ifdef _SC_TRACE_EVENT_FILTER 367 | case 0x0081: return _SC_TRACE_EVENT_FILTER; 368 | #endif 369 | #ifdef _SC_TRACE_EVENT_NAME_MAX 370 | case 0x0082: return _SC_TRACE_EVENT_NAME_MAX; 371 | #endif 372 | #ifdef _SC_TRACE_INHERIT 373 | case 0x0083: return _SC_TRACE_INHERIT; 374 | #endif 375 | #ifdef _SC_TRACE_LOG 376 | case 0x0084: return _SC_TRACE_LOG; 377 | #endif 378 | #ifdef _SC_TRACE_NAME_MAX 379 | case 0x0085: return _SC_TRACE_NAME_MAX; 380 | #endif 381 | #ifdef _SC_TRACE_SYS_MAX 382 | case 0x0086: return _SC_TRACE_SYS_MAX; 383 | #endif 384 | #ifdef _SC_TRACE_USER_EVENT_MAX 385 | case 0x0087: return _SC_TRACE_USER_EVENT_MAX; 386 | #endif 387 | #ifdef _SC_TYPED_MEMORY_OBJECTS 388 | case 0x0088: return _SC_TYPED_MEMORY_OBJECTS; 389 | #endif 390 | #ifdef _SC_V7_ILP32_OFF32 391 | case 0x0089: return _SC_V7_ILP32_OFF32; 392 | #endif 393 | #ifdef _SC_V7_ILP32_OFFBIG 394 | case 0x008a: return _SC_V7_ILP32_OFFBIG; 395 | #endif 396 | #ifdef _SC_V7_LP64_OFF64 397 | case 0x008b: return _SC_V7_LP64_OFF64; 398 | #endif 399 | #ifdef _SC_V7_LPBIG_OFFBIG 400 | case 0x008c: return _SC_V7_LPBIG_OFFBIG; 401 | #endif 402 | #ifdef _SC_XOPEN_STREAMS 403 | case 0x008d: return _SC_XOPEN_STREAMS; 404 | #endif 405 | #ifdef _SC_XOPEN_UUCP 406 | case 0x008e: return _SC_XOPEN_UUCP; 407 | #endif 408 | #ifdef _SC_LEVEL1_ICACHE_SIZE 409 | case 0x008f: return _SC_LEVEL1_ICACHE_SIZE; 410 | #endif 411 | #ifdef _SC_LEVEL1_ICACHE_ASSOC 412 | case 0x0090: return _SC_LEVEL1_ICACHE_ASSOC; 413 | #endif 414 | #ifdef _SC_LEVEL1_ICACHE_LINESIZE 415 | case 0x0091: return _SC_LEVEL1_ICACHE_LINESIZE; 416 | #endif 417 | #ifdef _SC_LEVEL1_DCACHE_SIZE 418 | case 0x0092: return _SC_LEVEL1_DCACHE_SIZE; 419 | #endif 420 | #ifdef _SC_LEVEL1_DCACHE_ASSOC 421 | case 0x0093: return _SC_LEVEL1_DCACHE_ASSOC; 422 | #endif 423 | #ifdef _SC_LEVEL1_DCACHE_LINESIZE 424 | case 0x0094: return _SC_LEVEL1_DCACHE_LINESIZE; 425 | #endif 426 | #ifdef _SC_LEVEL2_CACHE_SIZE 427 | case 0x0095: return _SC_LEVEL2_CACHE_SIZE; 428 | #endif 429 | #ifdef _SC_LEVEL2_CACHE_ASSOC 430 | case 0x0096: return _SC_LEVEL2_CACHE_ASSOC; 431 | #endif 432 | #ifdef _SC_LEVEL2_CACHE_LINESIZE 433 | case 0x0097: return _SC_LEVEL2_CACHE_LINESIZE; 434 | #endif 435 | #ifdef _SC_LEVEL3_CACHE_SIZE 436 | case 0x0098: return _SC_LEVEL3_CACHE_SIZE; 437 | #endif 438 | #ifdef _SC_LEVEL3_CACHE_ASSOC 439 | case 0x0099: return _SC_LEVEL3_CACHE_ASSOC; 440 | #endif 441 | #ifdef _SC_LEVEL3_CACHE_LINESIZE 442 | case 0x009a: return _SC_LEVEL3_CACHE_LINESIZE; 443 | #endif 444 | #ifdef _SC_LEVEL4_CACHE_SIZE 445 | case 0x009b: return _SC_LEVEL4_CACHE_SIZE; 446 | #endif 447 | #ifdef _SC_LEVEL4_CACHE_ASSOC 448 | case 0x009c: return _SC_LEVEL4_CACHE_ASSOC; 449 | #endif 450 | #ifdef _SC_LEVEL4_CACHE_LINESIZE 451 | case 0x009d: return _SC_LEVEL4_CACHE_LINESIZE; 452 | #endif 453 | default: 454 | fprintf(stderr, "sysconf constant (%d) is not mapped\n", name); 455 | abort(); 456 | } 457 | return 0xFFFF; 458 | } 459 | -------------------------------------------------------------------------------- /src/libc-verbose.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | /** 7 | * This file implements functions only for verbose output, which is useful for debugging. 8 | * These functions can be enabled with -DVERBOSE_FUNCTIONS 9 | */ 10 | 11 | char* 12 | bionic_realpath(const char *path, char *resolved_path) 13 | { 14 | verbose("%s", path); 15 | return realpath(path, resolved_path); 16 | } 17 | 18 | int 19 | bionic_chdir(const char *path) 20 | { 21 | verbose("%s", path); 22 | return chdir(path); 23 | } 24 | 25 | int 26 | bionic_rename(const char *old, const char *fresh) 27 | { 28 | verbose("%s -> %s", old, fresh); 29 | return rename(old, fresh); 30 | } 31 | 32 | int 33 | bionic_access(const char *path, int amode) 34 | { 35 | verbose("%s (%d)", path, amode); 36 | return access(path, amode); 37 | } 38 | 39 | FILE* 40 | bionic_fopen(const char *path, const char *mode) 41 | { 42 | verbose("%s %s", path, mode); 43 | return fopen(path, mode); 44 | } 45 | 46 | int 47 | bionic_mkdir(const char *path, mode_t mode) 48 | { 49 | verbose("%s -> %u", path, mode); 50 | return mkdir(path, mode); 51 | } 52 | 53 | DIR* 54 | bionic_opendir(const char *path) 55 | { 56 | verbose("%s", path); 57 | return opendir(path); 58 | } 59 | 60 | int 61 | bionic_sprintf(char *str, const char *fmt, ...) 62 | { 63 | va_list ap; 64 | va_start(ap, fmt); 65 | int r = vsprintf(str, fmt, ap); 66 | va_end(ap); 67 | verbose("%s == %s", fmt, str); 68 | return r; 69 | } 70 | 71 | int 72 | bionic_snprintf(char *str, size_t size, const char *fmt, ...) 73 | { 74 | va_list ap; 75 | va_start(ap, fmt); 76 | int r = vsnprintf(str, size, fmt, ap); 77 | va_end(ap); 78 | verbose("%s (%zu) == %s", fmt, size, str); 79 | return r; 80 | } 81 | 82 | size_t 83 | bionic_strlen(const char *str) 84 | { 85 | verbose("%s (%zu)", str, strlen(str)); 86 | return strlen(str); 87 | } 88 | 89 | char* 90 | bionic_strchr(const char *str, int c) 91 | { 92 | verbose("%s %c", str, c); 93 | return strchr(str, c); 94 | } 95 | 96 | char* 97 | bionic_strcpy(char *dest, const char *src) 98 | { 99 | verbose("%s", src); 100 | return strcpy(dest, src); 101 | } 102 | 103 | char* 104 | bionic_strncpy(char *dest, const char *src, size_t n) 105 | { 106 | verbose("%s (%zu)", src, n); 107 | return strncpy(dest, src, n); 108 | } 109 | 110 | extern char* strdup(const char*); 111 | 112 | char* 113 | bionic_strdup(const char *str) 114 | { 115 | verbose("%s", str); 116 | return strdup(str); 117 | } 118 | 119 | char* 120 | bionic_strstr(const char *haystack, const char *needle) 121 | { 122 | verbose("%s, %s", haystack, needle); 123 | return strstr(haystack, needle); 124 | } 125 | 126 | int 127 | bionic_strcmp(const char *s1, const char *s2) 128 | { 129 | verbose("%s == %s", s1, s2); 130 | return strcmp(s1, s2); 131 | } 132 | 133 | int 134 | bionic_strncmp(const char *s1, const char *s2, size_t n) 135 | { 136 | verbose("%s == %s (%zu)", s1, s2, n); 137 | return strncmp(s1, s2, n); 138 | } 139 | 140 | ssize_t 141 | bionic_readlink(const char *path, char *buf, size_t bufsize) 142 | { 143 | verbose("%s", path); 144 | return readlink(path, buf, bufsize); 145 | } 146 | 147 | int 148 | bionic_unlink(const char *path) 149 | { 150 | verbose("%s", path); 151 | return unlink(path); 152 | } 153 | 154 | char* 155 | bionic_getenv(const char *name) 156 | { 157 | verbose("%s", name); 158 | return getenv(name); 159 | } 160 | -------------------------------------------------------------------------------- /src/libc.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 | #include 15 | #include // PAGE_SIZE, PAGE_SHIFT 16 | #include // h_errno 17 | #include "wrapper/verbose.h" 18 | 19 | struct bionic_dirent { 20 | uint64_t d_ino; 21 | int64_t d_off; 22 | unsigned short d_reclen; 23 | unsigned char d_type; 24 | char d_name[256]; 25 | }; 26 | 27 | #ifdef ANDROID_X86_LINKER 28 | typedef unsigned long bionic_sigset_t; 29 | struct bionic_sigaction { 30 | union { 31 | void (*bsa_handler)(int); 32 | void (*bsa_sigaction)(int, void*, void*); 33 | }; 34 | bionic_sigset_t sa_mask; 35 | int sa_flags; 36 | void (*sa_restorer)(void); 37 | }; 38 | #else 39 | # error "not implemented for this platform" 40 | #endif 41 | 42 | // Stuff that doesn't exist in glibc 43 | 44 | #define PROP_NAME_MAX 32 45 | #define PROP_VALUE_MAX 92 46 | 47 | int 48 | __system_property_get(const char *name, char *value) 49 | { 50 | verbose("%s", name); 51 | 52 | if (!strcmp(name, "ro.build.version.sdk")) 53 | return snprintf(value, PROP_VALUE_MAX, "%d", 15); 54 | 55 | *value = 0; 56 | return 0; 57 | } 58 | 59 | pid_t 60 | gettid(void) 61 | { 62 | return syscall(SYS_gettid); 63 | } 64 | 65 | int 66 | tgkill(int tgid, int tid, int sig) 67 | { 68 | verbose("%d, %d, %d", tgid, tid, sig); 69 | return syscall(SYS_tgkill, tgid, tid, sig); 70 | } 71 | 72 | int 73 | tkill(int tid, int sig) 74 | { 75 | verbose("%d, %d", tid, sig); 76 | return syscall(SYS_tkill, tid, sig); 77 | } 78 | 79 | // Stuff needed for runtime compatibility, but not neccessary for linking 80 | // Also stuff that exists in glibc, but needs to be wrapped for runtime compatibility 81 | 82 | // Some defines from app-stdio.c as per GNU linker's manual for --wrap: 83 | // You may wish to provide a __real_malloc function as well, so that links without the 84 | // --wrap option will succeed. If you do this, you should not put the definition of 85 | // __real_malloc in the same file as __wrap_malloc; if you do, the assembler may resolve 86 | // the call before the linker has a chance to wrap it to malloc. 87 | 88 | size_t __real_IO_file_xsputn(FILE *f, const void *buf, size_t n) { return 0; } 89 | 90 | #include "libc-ctype.h" 91 | 92 | const unsigned int bionic___page_size = PAGE_SIZE; 93 | 94 | __attribute_const__ int* 95 | bionic___errno(void) 96 | { 97 | return __errno_location(); 98 | } 99 | 100 | __attribute_const__ int* 101 | bionic___get_h_errno(void) 102 | { 103 | return &h_errno; 104 | } 105 | 106 | int 107 | bionic_execv(const char *pathname, char *const argv[]) 108 | { 109 | verbose("%s", pathname); 110 | char const* args[255]; 111 | size_t i = 0; 112 | args[i++] = "/proc/self/exe"; 113 | args[i++] = pathname; 114 | for (const size_t x = i; i < sizeof(args) - 1 && argv[i - x]; ++i) args[i] = argv[i - x]; 115 | assert(argv[i] == NULL); 116 | args[i] = NULL; 117 | return execv("/proc/self/exe", (char*const*)args); 118 | } 119 | 120 | int 121 | bionic_stat(const char *restrict path, struct stat *restrict buf) 122 | { 123 | verbose("%s", path); 124 | return stat(path, buf); 125 | } 126 | 127 | int 128 | bionic_lstat(const char *restrict path, struct stat *restrict buf) 129 | { 130 | verbose("%s", path); 131 | return lstat(path, buf); 132 | } 133 | 134 | int 135 | bionic_fstat(int fd, struct stat *buf) 136 | { 137 | verbose("%d", fd); 138 | return fstat(fd, buf); 139 | } 140 | 141 | int 142 | bionic_fstatat(int dirfd, const char *pathname, void *buf, int flags) 143 | { 144 | verbose("%d, %s", dirfd, pathname); 145 | return fstatat(dirfd, pathname, buf, flags); 146 | } 147 | 148 | static void 149 | glibc_dirent_to_bionic_dirent(const struct dirent *de, struct bionic_dirent *bde) 150 | { 151 | assert(bde && de); 152 | *bde = (struct bionic_dirent){ 153 | .d_ino = de->d_ino, 154 | .d_off = de->d_off, 155 | .d_reclen = de->d_reclen, 156 | .d_type = de->d_type, 157 | }; 158 | _Static_assert(sizeof(bde->d_name) >= sizeof(de->d_name), "bionic_dirent can't hold dirent's d_name"); 159 | memcpy(bde->d_name, de->d_name, sizeof(bde->d_name)); 160 | } 161 | 162 | struct bionic_dirent* 163 | bionic_readdir(DIR *dirp) 164 | { 165 | assert(dirp); 166 | static struct bionic_dirent bde; 167 | struct dirent *de; 168 | if (!(de = readdir(dirp))) 169 | return NULL; 170 | glibc_dirent_to_bionic_dirent(de, &bde); 171 | return &bde; 172 | } 173 | 174 | int 175 | bionic_readdir_r(DIR *dirp, struct bionic_dirent *entry, struct bionic_dirent **result) 176 | { 177 | assert(dirp && entry && result); 178 | struct dirent de, *der = NULL; 179 | 180 | int ret; 181 | if ((ret = readdir_r(dirp, &de, &der)) != 0 || !der) { 182 | *result = NULL; 183 | return ret; 184 | } 185 | 186 | glibc_dirent_to_bionic_dirent(der, entry); 187 | *result = entry; 188 | return 0; 189 | } 190 | 191 | // Need to wrap bunch of signal crap 192 | // https://android.googlesource.com/platform/bionic/+/master/docs/32-bit-abi.md 193 | 194 | int 195 | bionic_sigaddset(const bionic_sigset_t *set, int sig) 196 | { 197 | int bit = sig - 1; // Signal numbers start at 1, but bit positions start at 0. 198 | unsigned long *local_set = (unsigned long*)set; 199 | if (!set || bit < 0 || bit >= (int)(8 * sizeof(*set))) { 200 | errno = EINVAL; 201 | return -1; 202 | } 203 | local_set[bit / LONG_BIT] |= 1UL << (bit % LONG_BIT); 204 | return 0; 205 | } 206 | 207 | int 208 | bionic_sigismember(const bionic_sigset_t *set, int sig) 209 | { 210 | int bit = sig - 1; // Signal numbers start at 1, but bit positions start at 0. 211 | const unsigned long *local_set = (const unsigned long*)set; 212 | if (!set || bit < 0 || bit >= (int)(8 * sizeof(*set))) { 213 | errno = EINVAL; 214 | return -1; 215 | } 216 | return (int)((local_set[bit / LONG_BIT] >> (bit % LONG_BIT)) & 1); 217 | } 218 | 219 | int 220 | bionic_sigaction(int sig, const struct bionic_sigaction *restrict act, struct bionic_sigaction *restrict oact) 221 | { 222 | verbose("%d, %p, %p", sig, (void*)act, (void*)oact); 223 | 224 | // THREAD_SIGNAL on android used by libbacktrace 225 | if (sig == 33) 226 | sig = SIGRTMIN; 227 | 228 | struct sigaction goact = {0}, gact = {0}; 229 | if (act) { 230 | gact.sa_handler = act->bsa_handler; 231 | gact.sa_flags = act->sa_flags; 232 | gact.sa_restorer = act->sa_restorer; 233 | 234 | // delete reserved signals 235 | // 32 (__SIGRTMIN + 0) POSIX timers 236 | // 33 (__SIGRTMIN + 1) libbacktrace 237 | // 34 (__SIGRTMIN + 2) libcore 238 | // 35 (__SIGRTMIN + 3) debuggerd -b 239 | assert(35 < SIGRTMAX); 240 | for (int signo = 35; signo < SIGRTMAX; ++signo) { 241 | if (bionic_sigismember(&act->sa_mask, signo)) 242 | sigaddset(&gact.sa_mask, signo); 243 | } 244 | } 245 | 246 | const int ret = sigaction(sig, (act ? &gact : NULL), (oact ? &goact : NULL)); 247 | 248 | if (oact) { 249 | *oact = (struct bionic_sigaction){0}; 250 | oact->bsa_handler = goact.sa_handler; 251 | oact->sa_flags = goact.sa_flags; 252 | oact->sa_restorer = goact.sa_restorer; 253 | 254 | for (int signo = SIGRTMIN + 3; signo < SIGRTMAX; ++signo) { 255 | if (sigismember(&goact.sa_mask, signo)) 256 | bionic_sigaddset(&oact->sa_mask, signo); 257 | } 258 | } 259 | 260 | return ret; 261 | } 262 | 263 | int 264 | bionic___isfinitef(float f) 265 | { 266 | return isfinite(f); 267 | } 268 | 269 | int 270 | bionic___isfinite(float f) 271 | { 272 | return isfinite(f); 273 | } 274 | 275 | void 276 | bionic___assert2(const char* file, int line, const char* function, const char* failed_expression) 277 | { 278 | fprintf(stderr, "%s:%d: %s: assertion \"%s\" failed\n", file, line, function, failed_expression); 279 | abort(); 280 | } 281 | 282 | uintptr_t bionic___stack_chk_guard = 4; 283 | 284 | __attribute__((noreturn)) void 285 | bionic___stack_chk_fail(void) 286 | { 287 | abort(); 288 | } 289 | 290 | size_t 291 | bionic___strlen_chk(const char *s, size_t s_len) 292 | { 293 | const size_t ret = strlen(s); 294 | if (__builtin_expect(ret >= s_len, 0)) { 295 | fprintf(stderr, "*** strlen read overflow detected ***\n"); 296 | abort(); 297 | } 298 | return ret; 299 | } 300 | 301 | size_t 302 | bionic___fwrite_chk(const void * __restrict buf, size_t size, size_t count, FILE * __restrict stream, size_t buf_size) 303 | { 304 | size_t total; 305 | if (__builtin_expect(__builtin_mul_overflow(size, count, &total), 0)) { 306 | // overflow: trigger the error path in fwrite 307 | return fwrite(buf, size, count, stream); 308 | } 309 | 310 | if (__builtin_expect(total > buf_size, 0)) { 311 | fprintf(stderr, "*** fwrite read overflow detected ***\n"); 312 | abort(); 313 | } 314 | 315 | return fwrite(buf, size, count, stream); 316 | } 317 | 318 | char* 319 | bionic___strchr_chk(const char* p, int ch, size_t s_len) 320 | { 321 | for (;; ++p, s_len--) { 322 | if (__builtin_expect(s_len == 0, 0)) { 323 | fprintf(stderr, "*** strchr buffer overrun detected ***\n"); 324 | abort(); 325 | } 326 | 327 | if (*p == ch) 328 | return (char*)p; 329 | else if (!*p) 330 | return NULL; 331 | } 332 | assert(0 && "should not happen"); 333 | } 334 | 335 | char* 336 | bionic___strrchr_chk(const char* p, int ch, size_t s_len) 337 | { 338 | const char *save; 339 | for (save = NULL;; ++p, s_len--) { 340 | if (__builtin_expect(s_len == 0, 0)) { 341 | fprintf(stderr, "*** strchr buffer overrun detected ***\n"); 342 | abort(); 343 | } 344 | 345 | if (*p == ch) 346 | save = p; 347 | else if (!*p) 348 | return (char*)save; 349 | } 350 | assert(0 && "should not happen"); 351 | } 352 | 353 | #include "libc-sysconf.h" 354 | 355 | long 356 | bionic_sysconf(int name) 357 | { 358 | verbose("0x%x", name); 359 | return sysconf(bionic_sysconf_to_glibc_sysconf(name)); 360 | } 361 | 362 | static void 363 | __libc_fini(int signal, void *array) 364 | { 365 | void** fini_array = (void**)array; 366 | 367 | if (!array || (size_t)fini_array[0] != (size_t)~0) 368 | return; 369 | 370 | fini_array += 1; 371 | 372 | int count; 373 | for (count = 0; fini_array[count]; ++count); 374 | 375 | for (; count > 0; --count) { 376 | const union { 377 | void *ptr; 378 | void (*fun)(void); 379 | } fini = { .ptr = fini_array[count] }; 380 | 381 | if ((size_t)fini.ptr != (size_t)~0) 382 | fini.fun(); 383 | } 384 | } 385 | 386 | struct bionic_structors { 387 | void (**preinit_array)(void); 388 | void (**init_array)(void); 389 | void (**fini_array)(void); 390 | }; 391 | 392 | __attribute__((noreturn)) void 393 | bionic___libc_init(void *raw_args, void (*onexit)(void), int (*slingshot)(int, char**, char**), struct bionic_structors const *const structors) 394 | { 395 | // linker has already called the constructors 396 | 397 | union { 398 | struct s { 399 | uintptr_t argc; 400 | char **argv; 401 | } s; 402 | char bytes[sizeof(struct s)]; 403 | } arg; 404 | 405 | memcpy(arg.bytes, raw_args, sizeof(arg.bytes)); 406 | 407 | if (structors->fini_array && on_exit(__libc_fini, structors->fini_array)) { 408 | fprintf(stderr, "__cxa_atexit failed\n"); 409 | abort(); 410 | } 411 | 412 | exit(slingshot(arg.s.argc, arg.s.argv, arg.s.argv + arg.s.argc + 1)); 413 | } 414 | 415 | #ifdef VERBOSE_FUNCTIONS 416 | # include "libc-verbose.h" 417 | #endif 418 | -------------------------------------------------------------------------------- /src/libjvm-android.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "jvm/jni.h" 7 | 8 | jstring 9 | android_os_Build_MANUFACTURER(JNIEnv *env, jobject object) 10 | { 11 | assert(env && object); 12 | return (*env)->NewStringUTF(env, "android2gnulinux"); 13 | } 14 | 15 | jstring 16 | android_os_Build_MODEL(JNIEnv *env, jobject object) 17 | { 18 | return android_os_Build_MANUFACTURER(env, object); 19 | } 20 | 21 | jstring 22 | android_os_Build_PRODUCT(JNIEnv *env, jobject object) 23 | { 24 | return android_os_Build_MANUFACTURER(env, object); 25 | } 26 | 27 | jstring 28 | android_os_Build_ID(JNIEnv *env, jobject object) 29 | { 30 | return android_os_Build_MANUFACTURER(env, object); 31 | } 32 | 33 | jstring 34 | android_os_Build_BRAND(JNIEnv *env, jobject object) 35 | { 36 | return android_os_Build_MANUFACTURER(env, object); 37 | } 38 | 39 | jstring 40 | android_os_Build_VERSION_RELEASE(JNIEnv *env, jobject object) 41 | { 42 | assert(env && object); 43 | // XXX: android2gnulinux version, but we may need to fake this if apps rely on this 44 | return (*env)->NewStringUTF(env, "1.0"); 45 | } 46 | 47 | jint 48 | android_os_Build_VERSION_SDK_INT(JNIEnv *env, jobject object) 49 | { 50 | assert(env && object); 51 | return 15; // >15 needs android.view.Choreographer to work correctly, XXX: maybe tunable, as can change app behaviour 52 | } 53 | 54 | jstring 55 | android_os_Build_VERSION_INCREMENTAL(JNIEnv *env, jobject object) 56 | { 57 | assert(env && object); 58 | return (*env)->NewStringUTF(env, "0"); // XXX: maybe git sha of this repo 59 | } 60 | 61 | jstring 62 | android_content_Context_getPackageName(JNIEnv *env, jobject object, va_list args) 63 | { 64 | assert(env && object); 65 | return (*env)->NewStringUTF(env, getenv("ANDROID_PACKAGE_NAME")); 66 | } 67 | 68 | jstring 69 | android_content_Context_getPackageCodePath(JNIEnv *env, jobject object, va_list args) 70 | { 71 | assert(env && object); 72 | return (*env)->NewStringUTF(env, getenv("ANDROID_PACKAGE_CODE_PATH")); 73 | } 74 | 75 | jstring 76 | android_content_pm_PackageInfo_versionName(JNIEnv *env, jobject object) 77 | { 78 | assert(env && object); 79 | return (*env)->NewStringUTF(env, "1.1"); 80 | } 81 | 82 | jobject 83 | android_content_Context_getExternalFilesDir(JNIEnv *env, jobject object, va_list args) 84 | { 85 | assert(env && object); 86 | // FIXME: add mechanism that allows us to implement these objects and then 87 | // use `$XDG_DATA_HOME/android2gnulinux/appid` for the path 88 | jstring str = va_arg(args, jstring); 89 | (*env)->GetStringUTFChars(env, str, NULL); 90 | static jobject sv; 91 | return (sv ? sv : (sv = (*env)->AllocObject(env, (*env)->FindClass(env, "java/io/File")))); 92 | } 93 | 94 | jobject 95 | android_content_Context_getFilesDir(JNIEnv *env, jobject object, va_list args) 96 | { 97 | assert(env && object); 98 | static jobject sv; 99 | return (sv ? sv : (sv = (*env)->AllocObject(env, (*env)->FindClass(env, "java/io/File")))); 100 | } 101 | 102 | jobject 103 | android_content_Context_getCacheDir(JNIEnv *env, jobject object, va_list args) 104 | { 105 | assert(env && object); 106 | static jobject sv; 107 | return (sv ? sv : (sv = (*env)->AllocObject(env, (*env)->FindClass(env, "java/io/File")))); 108 | } 109 | 110 | jobject 111 | android_content_Context_getExternalCacheDir(JNIEnv *env, jobject object, va_list args) 112 | { 113 | assert(env && object); 114 | static jobject sv; 115 | return (sv ? sv : (sv = (*env)->AllocObject(env, (*env)->FindClass(env, "java/io/File")))); 116 | } 117 | 118 | jstring 119 | android_net_Uri_decode(JNIEnv *env, jobject object, va_list args) 120 | { 121 | assert(env && object); 122 | jstring str = va_arg(args, jstring); 123 | (*env)->GetStringUTFChars(env, str, NULL); 124 | return str; 125 | } 126 | 127 | jstring 128 | android_net_Uri_encode(JNIEnv *env, jobject object, va_list args) 129 | { 130 | assert(env && object); 131 | jstring str = va_arg(args, jstring); 132 | (*env)->GetStringUTFChars(env, str, NULL); 133 | return str; 134 | } 135 | 136 | jstring 137 | android_content_SharedPreferences_getString(JNIEnv *env, jobject object, va_list args) 138 | { 139 | assert(env && object); 140 | jstring str1 = va_arg(args, jstring); 141 | jstring str2 = va_arg(args, jstring); 142 | (*env)->GetStringUTFChars(env, str1, NULL); 143 | (*env)->GetStringUTFChars(env, str2, NULL); 144 | return str2; 145 | } 146 | 147 | jstring 148 | android_os_Bundle_getString(JNIEnv *env, jobject object, va_list args) 149 | { 150 | assert(env && object); 151 | jstring str1 = va_arg(args, jstring); 152 | (*env)->GetStringUTFChars(env, str1, NULL); 153 | return NULL; 154 | } 155 | 156 | jintArray 157 | android_view_InputDevice_getDeviceIds(JNIEnv *env, jobject object, va_list args) 158 | { 159 | assert(env && object); 160 | return (*env)->NewIntArray(env, 1); 161 | } 162 | 163 | jint 164 | android_view_InputEvent_getSource(JNIEnv *env, jobject object, va_list args) 165 | { 166 | assert(env && object); 167 | return 0x00001002; // SOURCE_TOUCHSCREEN 168 | } 169 | 170 | jint 171 | android_view_MotionEvent_getAction(JNIEnv *env, jobject object, va_list args) 172 | { 173 | assert(env && object); 174 | static int action; 175 | return (action = !action); 176 | } 177 | 178 | jfloat 179 | android_view_MotionEvent_getX(JNIEnv *env, jobject object, va_list args) 180 | { 181 | assert(env && object); 182 | return 1024/2; 183 | } 184 | 185 | jfloat 186 | android_view_MotionEvent_getY(JNIEnv *env, jobject object, va_list args) 187 | { 188 | assert(env && object); 189 | static int y; 190 | return y = (y + 8) % 768; 191 | } 192 | 193 | jint 194 | android_view_MotionEvent_getPointerCount(JNIEnv *env, jobject object, va_list args) 195 | { 196 | assert(env && object); 197 | return 1; 198 | } 199 | -------------------------------------------------------------------------------- /src/libjvm-java.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "jvm/jni.h" 12 | 13 | jstring 14 | java_lang_System_getProperty(JNIEnv *env, jobject object, va_list args) 15 | { 16 | assert(env && object); 17 | const char *key = (*env)->GetStringUTFChars(env, va_arg(args, jstring), NULL); 18 | 19 | if (!strcmp(key, "java.vm.version")) 20 | return (*env)->NewStringUTF(env, "1.6"); 21 | 22 | union { 23 | void *ptr; 24 | int (*fun)(const char*, char*); 25 | } __system_property_get; 26 | 27 | if (!(__system_property_get.ptr = dlsym(RTLD_DEFAULT, "__system_property_get"))) 28 | return NULL; 29 | 30 | char value[92]; // PROP_VALUE_MAX 92 31 | __system_property_get.fun(key, value); 32 | return (*env)->NewStringUTF(env, value); 33 | } 34 | 35 | void 36 | java_lang_System_load(JNIEnv *env, jobject object, va_list args) 37 | { 38 | assert(env && object); 39 | const char *lib = (*env)->GetStringUTFChars(env, va_arg(args, jstring), NULL); 40 | 41 | struct { 42 | union { 43 | void *ptr; 44 | void* (*fun)(const char*, int); 45 | } open; 46 | 47 | union { 48 | void *ptr; 49 | void* (*fun)(void*, const char*); 50 | } sym; 51 | } dl; 52 | 53 | if (!(dl.open.ptr = dlsym(RTLD_DEFAULT, "bionic_dlopen")) || !(dl.sym.ptr = dlsym(RTLD_DEFAULT, "bionic_dlsym"))) { 54 | dl.open.fun = dlopen; 55 | dl.sym.fun = dlsym; 56 | } 57 | 58 | void *handle; 59 | if (!(handle = dl.open.fun(lib, RTLD_NOW | RTLD_GLOBAL))) { 60 | warnx("java/lang/System/load: failed to dlopen `%s`", lib); 61 | return; 62 | } 63 | 64 | union { 65 | void *ptr; 66 | void* (*fun)(void*, void*); 67 | } JNI_OnLoad; 68 | 69 | if ((JNI_OnLoad.ptr = dl.sym.fun(handle, "JNI_OnLoad"))) { 70 | JavaVM *vm; 71 | (*env)->GetJavaVM(env, &vm); 72 | JNI_OnLoad.fun(vm, NULL); 73 | } 74 | } 75 | 76 | jobject 77 | java_lang_ClassLoader_findLibrary(JNIEnv *env, jobject object, va_list args) 78 | { 79 | assert(env && object); 80 | // XXX: according to docs should return absolute path, but relative is more convenient for us. 81 | // fix if breaks anything because of this. 82 | char lib[255]; 83 | snprintf(lib, sizeof(lib), "lib%s.so", (*env)->GetStringUTFChars(env, va_arg(args, jstring), NULL)); 84 | return (*env)->NewStringUTF(env, lib); 85 | } 86 | 87 | jobject 88 | java_lang_ClassLoader_findClass(JNIEnv *env, jobject object, va_list args) 89 | { 90 | assert(env && object); 91 | jstring str = va_arg(args, jstring); 92 | const char *utf = (*env)->GetStringUTFChars(env, str, NULL); 93 | return (*env)->FindClass(env, utf); 94 | } 95 | 96 | jobject 97 | java_lang_Class_getClassLoader(JNIEnv *env, jobject object) 98 | { 99 | assert(env && object); 100 | static jobject sv; 101 | return (sv ? sv : (sv = (*env)->AllocObject(env, (*env)->FindClass(env, "java/lang/ClassLoader")))); 102 | } 103 | 104 | jclass 105 | java_lang_Class_forName(JNIEnv *env, jobject object, va_list args) 106 | { 107 | assert(env && object); 108 | jstring str = va_arg(args, jstring); 109 | const char *utf = (*env)->GetStringUTFChars(env, str, NULL); 110 | return (*env)->FindClass(env, utf); 111 | } 112 | 113 | jstring 114 | java_lang_Class_getName(JNIEnv *env, jobject object) 115 | { 116 | assert(env && object); 117 | 118 | { 119 | struct { 120 | union { 121 | void *ptr; 122 | struct jvm* (*fun)(JNIEnv*); 123 | } jnienv_get_jvm; 124 | 125 | union { 126 | void *ptr; 127 | const char* (*fun)(const struct jvm*, jobject); 128 | } jvm_get_class_name; 129 | } jvm; 130 | 131 | if ((jvm.jnienv_get_jvm.ptr = dlsym(RTLD_DEFAULT, "jnienv_get_jvm")) && (jvm.jvm_get_class_name.ptr = dlsym(RTLD_DEFAULT, "jvm_get_class_name"))) { 132 | struct jvm *jvm_ = jvm.jnienv_get_jvm.fun(env); 133 | return (*env)->NewStringUTF(env, jvm.jvm_get_class_name.fun(jvm_, object)); 134 | } 135 | } 136 | 137 | warnx("%s: returning NULL, as running in unknown JVM and don't know how to get class name", __func__); 138 | return NULL; 139 | } 140 | 141 | jclass 142 | java_lang_Object_getClass(JNIEnv *env, jobject object) 143 | { 144 | assert(env && object); 145 | return (*env)->GetObjectClass(env, object); 146 | } 147 | 148 | jstring 149 | java_io_File_getPath(JNIEnv *env, jobject object, va_list args) 150 | { 151 | assert(env && object); 152 | // FIXME: see comment on `android_content_Context_getExternalFilesDir` 153 | return (*env)->NewStringUTF(env, getenv("ANDROID_EXTERNAL_FILES_DIR")); 154 | } 155 | 156 | jstring 157 | java_io_File_getParent(JNIEnv *env, jobject object, va_list args) 158 | { 159 | // FIXME: see comment on `android_content_Context_getExternalFilesDir` 160 | char path[4096]; 161 | snprintf(path, sizeof(path), "%s", getenv("ANDROID_EXTERNAL_FILES_DIR")); 162 | return (*env)->NewStringUTF(env, dirname(path)); 163 | } 164 | 165 | jboolean 166 | java_lang_String_equals(JNIEnv *env, jobject object, va_list args) 167 | { 168 | assert(env && object); 169 | jstring str = va_arg(args, jstring); 170 | const char *utf1 = (*env)->GetStringUTFChars(env, object, NULL); 171 | const char *utf2 = (*env)->GetStringUTFChars(env, str, NULL); 172 | const jboolean equal = (utf1 == utf2 || (utf1 && utf2 && !strcmp(utf1, utf2))); 173 | (*env)->ReleaseStringUTFChars(env, object, utf1); 174 | (*env)->ReleaseStringUTFChars(env, str, utf2); 175 | return equal; 176 | } 177 | 178 | jbyteArray 179 | java_lang_String_getBytes(JNIEnv *env, jobject object, va_list args) 180 | { 181 | assert(env && object); 182 | const char *utf = (*env)->GetStringUTFChars(env, object, NULL); 183 | const size_t len = (utf ? strlen(utf) : 0); 184 | jbyteArray bytes = (*env)->NewByteArray(env, len); 185 | (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)utf); 186 | return bytes; 187 | } 188 | 189 | jstring 190 | java_util_Locale_getLanguage(JNIEnv *env, jobject object) 191 | { 192 | assert(env && object); 193 | return (*env)->NewStringUTF(env, "en"); 194 | } 195 | 196 | jstring 197 | java_util_Locale_getCountry(JNIEnv *env, jobject object) 198 | { 199 | assert(env && object); 200 | return (*env)->NewStringUTF(env, "US"); 201 | } 202 | -------------------------------------------------------------------------------- /src/libjvm-misc.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "jvm/jni.h" 4 | 5 | jstring 6 | com_blizzard_wtcg_hearthstone_DeviceSettings_GetModelNumber(JNIEnv *env, jobject object) 7 | { 8 | return (*env)->NewStringUTF(env, "0"); 9 | } 10 | 11 | -------------------------------------------------------------------------------- /src/libjvm-unity.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "jvm/jni.h" 4 | 5 | jmethodID 6 | com_unity3d_player_ReflectionHelper_getMethodID(JNIEnv *env, jobject object, jvalue *values) 7 | { 8 | assert(env && object); 9 | const char *utf1 = (*env)->GetStringUTFChars(env, values[1].l, NULL); 10 | const char *utf2 = (*env)->GetStringUTFChars(env, values[2].l, NULL); 11 | return (*env)->GetMethodID(env, values[0].l, utf1, utf2); 12 | } 13 | 14 | jfieldID 15 | com_unity3d_player_ReflectionHelper_getFieldID(JNIEnv *env, jobject object, jvalue *values) 16 | { 17 | assert(env && object); 18 | const char *utf1 = (*env)->GetStringUTFChars(env, values[1].l, NULL); 19 | const char *utf2 = (*env)->GetStringUTFChars(env, values[2].l, NULL); 20 | return (*env)->GetFieldID(env, values[0].l, utf1, utf2); 21 | } 22 | -------------------------------------------------------------------------------- /src/liblog.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int 5 | __android_log_vprint(int prio, const char *tag, const char *fmt, va_list ap) 6 | { 7 | int ret = printf("(%d) %s :: ", prio, tag); 8 | ret += vprintf(fmt, ap); 9 | ret += (puts("") != EOF); 10 | return ret; 11 | } 12 | 13 | int 14 | __android_log_print(int prio, const char *tag, const char *fmt, ...) 15 | { 16 | va_list ap; 17 | va_start(ap, fmt); 18 | int ret = __android_log_vprint(prio, tag, fmt, ap); 19 | va_end(ap); 20 | return ret; 21 | } 22 | 23 | int 24 | __android_log_write(int prio, const char *tag, const char *text) 25 | { 26 | return __android_log_print(prio, tag, "%s", text); 27 | } 28 | -------------------------------------------------------------------------------- /src/libpthread.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | typedef struct { 11 | union { 12 | struct { 13 | unsigned int count; 14 | #ifdef __LP64__ 15 | int __reserved[3]; 16 | #endif 17 | } bionic; 18 | sem_t *glibc; 19 | }; 20 | } bionic_sem_t; 21 | 22 | typedef struct { 23 | union { 24 | struct { 25 | uint32_t flags; 26 | void* stack_base; 27 | size_t stack_size; 28 | size_t guard_size; 29 | int32_t sched_policy; 30 | int32_t sched_priority; 31 | #ifdef __LP64__ 32 | char __reserved[16]; 33 | #endif 34 | } bionic; 35 | pthread_attr_t *glibc; 36 | }; 37 | } bionic_attr_t; 38 | 39 | typedef struct { 40 | union { 41 | #if defined(__LP64__) 42 | int32_t __private[10]; 43 | #else 44 | int32_t __private[1]; 45 | #endif 46 | pthread_mutex_t *glibc; 47 | }; 48 | } bionic_mutex_t; 49 | 50 | typedef struct { 51 | union { 52 | long __private; 53 | pthread_mutexattr_t *glibc; 54 | }; 55 | } bionic_mutexattr_t; 56 | 57 | static const struct { 58 | bionic_mutex_t bionic; 59 | pthread_mutex_t glibc; 60 | } bionic_mutex_init_map[] = { 61 | { .bionic = {{{ ((PTHREAD_MUTEX_NORMAL & 3) << 14) }}}, .glibc = PTHREAD_MUTEX_INITIALIZER }, 62 | { .bionic = {{{ ((PTHREAD_MUTEX_RECURSIVE & 3) << 14) }}}, .glibc = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP }, 63 | { .bionic = {{{ ((PTHREAD_MUTEX_ERRORCHECK & 3) << 14) }}}, .glibc = PTHREAD_ERRORCHECK_MUTEX_INITIALIZER_NP }, 64 | }; 65 | 66 | typedef struct { 67 | union { 68 | #if defined(__LP64__) 69 | int32_t __private[12]; 70 | #else 71 | int32_t __private[1]; 72 | #endif 73 | pthread_cond_t *glibc; 74 | }; 75 | } bionic_cond_t; 76 | 77 | typedef struct { 78 | union { 79 | long __private; 80 | pthread_condattr_t *glibc; 81 | }; 82 | } bionic_condattr_t; 83 | 84 | typedef int bionic_key_t; 85 | _Static_assert(sizeof(bionic_key_t) == sizeof(pthread_key_t), "bionic_key_t and pthread_key_t size mismatch"); 86 | 87 | typedef int bionic_once_t; 88 | _Static_assert(sizeof(bionic_once_t) == sizeof(pthread_once_t), "bionic_once_t and pthread_once_t size mismatch"); 89 | 90 | typedef long bionic_pthread_t; 91 | _Static_assert(sizeof(bionic_pthread_t) == sizeof(pthread_t), "bionic_pthread_t and pthread_t size mismatch"); 92 | 93 | struct bionic_pthread_cleanup_t { 94 | union { 95 | struct bionic_pthread_cleanup_t *prev; 96 | __pthread_unwind_buf_t *glibc; 97 | }; 98 | void (*routine)(void*); 99 | void *arg; 100 | }; 101 | 102 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) 103 | 104 | // For checking, if our glibc version is mapped to memory. 105 | // Used for sanity checking and static initialization below. 106 | #define IS_MAPPED(x) is_mapped(x->glibc, sizeof(x)) 107 | 108 | // For handling static initialization. 109 | #define INIT_IF_NOT_MAPPED(x, init) do { if (!IS_MAPPED(x)) init(x); } while(0) 110 | 111 | static bool 112 | is_mapped(void *mem, const size_t sz) 113 | { 114 | const size_t ps = sysconf(_SC_PAGESIZE); 115 | assert(ps > 0); 116 | unsigned char vec[(sz + ps - 1) / ps]; 117 | return !mincore(mem, sz, vec); 118 | } 119 | 120 | void 121 | bionic___pthread_cleanup_push(struct bionic_pthread_cleanup_t *c, void (*routine)(void*), void *arg) 122 | { 123 | assert(c && routine); 124 | c->glibc = mmap(NULL, sizeof(*c->glibc), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 125 | c->routine = routine; 126 | c->arg = arg; 127 | 128 | int not_first_call; 129 | if ((not_first_call = __sigsetjmp((struct __jmp_buf_tag*)(void*)c->glibc->__cancel_jmp_buf, 0))) { 130 | routine(arg); 131 | __pthread_unwind_next(c->glibc); 132 | } 133 | 134 | __pthread_register_cancel(c->glibc); 135 | } 136 | 137 | void 138 | bionic___pthread_cleanup_pop(struct bionic_pthread_cleanup_t *c, int execute) 139 | { 140 | assert(c && IS_MAPPED(c)); 141 | __pthread_unregister_cancel(c->glibc); 142 | 143 | if (execute) 144 | c->routine(c->arg); 145 | 146 | munmap(c->glibc, sizeof(*c->glibc)); 147 | } 148 | 149 | int 150 | bionic_sem_destroy(bionic_sem_t *sem) 151 | { 152 | assert(sem); 153 | int ret = 0; 154 | if (IS_MAPPED(sem)) { 155 | ret = sem_destroy(sem->glibc); 156 | munmap(sem->glibc, sizeof(*sem->glibc)); 157 | } 158 | return ret; 159 | } 160 | 161 | static void 162 | default_sem_init(bionic_sem_t *sem) 163 | { 164 | // Apparently some android apps (hearthstone) do not call sem_init() 165 | assert(sem); 166 | sem->glibc = mmap(NULL, sizeof(*sem->glibc), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 167 | memset(sem->glibc, 0, sizeof(*sem->glibc)); 168 | } 169 | 170 | int 171 | bionic_sem_init(bionic_sem_t *sem, int pshared, unsigned int value) 172 | { 173 | assert(sem); 174 | // From SEM_INIT(3) 175 | // Initializing a semaphore that has already been initialized results in underined behavior. 176 | *sem = (bionic_sem_t){0}; 177 | sem->glibc = mmap(NULL, sizeof(*sem->glibc), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 178 | return sem_init(sem->glibc, pshared, value); 179 | } 180 | 181 | int 182 | bionic_sem_post(bionic_sem_t *sem) 183 | { 184 | assert(sem); 185 | INIT_IF_NOT_MAPPED(sem, default_sem_init); 186 | return sem_post(sem->glibc); 187 | } 188 | 189 | int 190 | bionic_sem_wait(bionic_sem_t *sem) 191 | { 192 | assert(sem); 193 | INIT_IF_NOT_MAPPED(sem, default_sem_init); 194 | return sem_wait(sem->glibc); 195 | } 196 | 197 | int 198 | bionic_sem_trywait(bionic_sem_t *sem) 199 | { 200 | assert(sem); 201 | INIT_IF_NOT_MAPPED(sem, default_sem_init); 202 | return sem_trywait(sem->glibc); 203 | } 204 | 205 | int 206 | bionic_sem_timedwait(bionic_sem_t *sem, const struct timespec *abs_timeout) 207 | { 208 | assert(sem && abs_timeout); 209 | INIT_IF_NOT_MAPPED(sem, default_sem_init); 210 | return sem_timedwait(sem->glibc, abs_timeout); 211 | } 212 | 213 | int 214 | bionic_pthread_attr_destroy(bionic_attr_t *attr) 215 | { 216 | assert(attr); 217 | int ret = 0; 218 | if (IS_MAPPED(attr)) { 219 | ret = pthread_attr_destroy(attr->glibc); 220 | munmap(attr->glibc, sizeof(*attr->glibc)); 221 | } 222 | return ret; 223 | } 224 | 225 | int 226 | bionic_pthread_attr_init(bionic_attr_t *attr) 227 | { 228 | assert(attr); 229 | // From PTHREAD_ATTR_INIT(3) 230 | // Calling `pthread_attr_init` on a thread attributes object that has already been initialized results in ud. 231 | *attr = (bionic_attr_t){0}; 232 | attr->glibc = mmap(NULL, sizeof(*attr->glibc), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 233 | return pthread_attr_init(attr->glibc); 234 | } 235 | 236 | int 237 | bionic_pthread_getattr_np(bionic_pthread_t thread, bionic_attr_t *attr) 238 | { 239 | assert(thread && attr); 240 | *attr = (bionic_attr_t){0}; 241 | attr->glibc = mmap(NULL, sizeof(*attr->glibc), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 242 | return pthread_getattr_np((pthread_t)thread, attr->glibc); 243 | } 244 | 245 | int 246 | bionic_pthread_attr_settstack(bionic_attr_t *attr, void *stackaddr, size_t stacksize) 247 | { 248 | assert(attr && IS_MAPPED(attr)); 249 | return pthread_attr_setstack(attr->glibc, stackaddr, stacksize); 250 | } 251 | 252 | int 253 | bionic_pthread_attr_getstack(const bionic_attr_t *attr, void *stackaddr, size_t *stacksize) 254 | { 255 | assert(attr && IS_MAPPED(attr)); 256 | return pthread_attr_getstack(attr->glibc, stackaddr, stacksize); 257 | } 258 | 259 | int 260 | bionic_pthread_attr_setstacksize(bionic_attr_t *attr, size_t stacksize) 261 | { 262 | assert(attr && IS_MAPPED(attr)); 263 | return pthread_attr_setstacksize(attr->glibc, stacksize); 264 | } 265 | 266 | int 267 | bionic_pthread_attr_getstacksize(const bionic_attr_t *attr, size_t *stacksize) 268 | { 269 | assert(attr && IS_MAPPED(attr)); 270 | return pthread_attr_getstacksize(attr->glibc, stacksize); 271 | } 272 | 273 | int 274 | bionic_pthread_attr_setschedpolicy(bionic_attr_t *attr, int policy) 275 | { 276 | assert(attr && IS_MAPPED(attr)); 277 | return pthread_attr_setschedpolicy(attr->glibc, policy); 278 | } 279 | 280 | int 281 | bionic_pthread_attr_getschedpolicy(bionic_attr_t *attr, int *policy) 282 | { 283 | assert(attr && IS_MAPPED(attr)); 284 | return pthread_attr_getschedpolicy(attr->glibc, policy); 285 | } 286 | 287 | int 288 | bionic_pthread_attr_setschedparam(bionic_attr_t *attr, const struct sched_param *param) 289 | { 290 | assert(attr && IS_MAPPED(attr)); 291 | return pthread_attr_setschedparam(attr->glibc, param); 292 | } 293 | 294 | int 295 | bionic_pthread_attr_getschedparam(bionic_attr_t *attr, struct sched_param *param) 296 | { 297 | assert(attr && IS_MAPPED(attr)); 298 | return pthread_attr_getschedparam(attr->glibc, param); 299 | } 300 | 301 | int 302 | bionic_pthread_attr_setdetachstate(bionic_attr_t *attr, int detachstate) 303 | { 304 | assert(attr && IS_MAPPED(attr)); 305 | return pthread_attr_setdetachstate(attr->glibc, detachstate); 306 | } 307 | 308 | int 309 | bionic_pthread_attr_getdetachstate(bionic_attr_t *attr, int *detachstate) 310 | { 311 | assert(attr && IS_MAPPED(attr)); 312 | return pthread_attr_getdetachstate(attr->glibc, detachstate); 313 | } 314 | 315 | int 316 | bionic_pthread_create(bionic_pthread_t *thread, const bionic_attr_t *attr, void* (*start)(void*), void *arg) 317 | { 318 | assert(thread && (!attr || IS_MAPPED(attr))); 319 | return pthread_create((pthread_t*)thread, (attr ? attr->glibc : NULL), start, arg); 320 | } 321 | 322 | int 323 | bionic_pthread_mutexattr_settype(bionic_mutexattr_t *attr, int type) 324 | { 325 | assert(attr && IS_MAPPED(attr)); 326 | return pthread_mutexattr_settype(attr->glibc, type); 327 | } 328 | 329 | int 330 | bionic_pthread_mutexattr_destroy(bionic_mutexattr_t *attr) 331 | { 332 | assert(attr); 333 | int ret = 0; 334 | if (IS_MAPPED(attr)) { 335 | ret = pthread_mutexattr_destroy(attr->glibc); 336 | munmap(attr->glibc, sizeof(*attr->glibc)); 337 | } 338 | return ret; 339 | } 340 | 341 | int 342 | bionic_pthread_mutexattr_init(bionic_mutexattr_t *attr) 343 | { 344 | assert(attr); 345 | // From PTHREAD_MUTEXATTR_INIT(3) 346 | // The results of initializing an already initialized mutex attributes object are undefined. 347 | *attr = (bionic_mutexattr_t){0}; 348 | attr->glibc = mmap(NULL, sizeof(*attr->glibc), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 349 | return pthread_mutexattr_init(attr->glibc); 350 | } 351 | 352 | static void 353 | default_pthread_mutex_init(bionic_mutex_t *mutex) 354 | { 355 | assert(mutex); 356 | mutex->glibc = mmap(NULL, sizeof(*mutex->glibc), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 357 | 358 | for (size_t i = 0; i < ARRAY_SIZE(bionic_mutex_init_map); ++i) { 359 | if (!memcmp(&bionic_mutex_init_map[i].bionic, mutex, sizeof(*mutex))) 360 | continue; 361 | 362 | memcpy(mutex->glibc, &bionic_mutex_init_map[i].glibc, sizeof(bionic_mutex_init_map[i].glibc)); 363 | return; 364 | } 365 | 366 | assert(0 && "no such default initializer???"); 367 | } 368 | 369 | int 370 | bionic_pthread_mutex_destroy(bionic_mutex_t *mutex) 371 | { 372 | assert(mutex); 373 | int ret = 0; 374 | if (IS_MAPPED(mutex)) { 375 | ret = pthread_mutex_destroy(mutex->glibc); 376 | munmap(mutex->glibc, sizeof(*mutex->glibc)); 377 | } 378 | return ret; 379 | } 380 | 381 | int 382 | bionic_pthread_mutex_init(bionic_mutex_t *mutex, const bionic_mutexattr_t *attr) 383 | { 384 | assert(mutex && (!attr || IS_MAPPED(attr))); 385 | // From PTHREAD_MUTEX_INIT(3) 386 | // Attempting to initialize an already initialized mutex result in undefined behavior. 387 | *mutex = (bionic_mutex_t){0}; 388 | mutex->glibc = mmap(NULL, sizeof(*mutex->glibc), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 389 | return pthread_mutex_init(mutex->glibc, (attr ? attr->glibc : NULL)); 390 | } 391 | 392 | int 393 | bionic_pthread_mutex_lock(bionic_mutex_t *mutex) 394 | { 395 | assert(mutex); 396 | INIT_IF_NOT_MAPPED(mutex, default_pthread_mutex_init); 397 | return pthread_mutex_lock(mutex->glibc); 398 | } 399 | 400 | int 401 | bionic_pthread_mutex_trylock(bionic_mutex_t *mutex) 402 | { 403 | assert(mutex); 404 | INIT_IF_NOT_MAPPED(mutex, default_pthread_mutex_init); 405 | return pthread_mutex_trylock(mutex->glibc); 406 | } 407 | 408 | int 409 | bionic_pthread_mutex_unlock(bionic_mutex_t *mutex) 410 | { 411 | assert(mutex); 412 | INIT_IF_NOT_MAPPED(mutex, default_pthread_mutex_init); 413 | return pthread_mutex_unlock(mutex->glibc); 414 | } 415 | 416 | static void 417 | default_pthread_cond_init(bionic_cond_t *cond) 418 | { 419 | assert(cond); 420 | cond->glibc = mmap(NULL, sizeof(*cond->glibc), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 421 | memset(cond->glibc, 0, sizeof(*cond->glibc)); 422 | } 423 | 424 | int 425 | bionic_pthread_cond_destroy(bionic_cond_t *cond) 426 | { 427 | assert(cond); 428 | int ret = 0; 429 | if (IS_MAPPED(cond)) { 430 | ret = pthread_cond_destroy(cond->glibc); 431 | munmap(cond->glibc, sizeof(*cond->glibc)); 432 | } 433 | return ret; 434 | } 435 | 436 | int 437 | bionic_pthread_cond_init(bionic_cond_t *cond, const bionic_condattr_t *attr) 438 | { 439 | assert(cond && (!attr || IS_MAPPED(attr))); 440 | // From PTHREAD_COND_INIT(3) 441 | // Attempting to initialize an already initialized mutex result in undefined behavior. 442 | *cond = (bionic_cond_t){0}; 443 | cond->glibc = mmap(NULL, sizeof(*cond->glibc), PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 444 | return pthread_cond_init(cond->glibc, (attr ? attr->glibc : NULL)); 445 | } 446 | 447 | int 448 | bionic_pthread_cond_broadcast(bionic_cond_t *cond) 449 | { 450 | assert(cond); 451 | INIT_IF_NOT_MAPPED(cond, default_pthread_cond_init); 452 | return pthread_cond_broadcast(cond->glibc); 453 | } 454 | 455 | int 456 | bionic_pthread_cond_signal(bionic_cond_t *cond) 457 | { 458 | assert(cond); 459 | INIT_IF_NOT_MAPPED(cond, default_pthread_cond_init); 460 | return pthread_cond_signal(cond->glibc); 461 | } 462 | 463 | int 464 | bionic_pthread_cond_wait(bionic_cond_t *cond, bionic_mutex_t *mutex) 465 | { 466 | assert(cond && mutex); 467 | INIT_IF_NOT_MAPPED(cond, default_pthread_cond_init); 468 | INIT_IF_NOT_MAPPED(mutex, default_pthread_mutex_init); 469 | return pthread_cond_wait(cond->glibc, mutex->glibc); 470 | } 471 | 472 | int 473 | bionic_pthread_cond_timedwait(bionic_cond_t *cond, bionic_mutex_t *mutex, const struct timespec *abs_timeout) 474 | { 475 | assert(cond && mutex); 476 | INIT_IF_NOT_MAPPED(cond, default_pthread_cond_init); 477 | INIT_IF_NOT_MAPPED(mutex, default_pthread_mutex_init); 478 | return pthread_cond_timedwait(cond->glibc, mutex->glibc, abs_timeout); 479 | } 480 | 481 | int 482 | bionic_pthread_cond_timedwait_relative_np(bionic_cond_t *cond, bionic_mutex_t *mutex, const struct timespec *reltime) 483 | { 484 | assert(cond && mutex && reltime); 485 | struct timespec tv; 486 | clock_gettime(CLOCK_REALTIME, &tv); 487 | tv.tv_sec += reltime->tv_sec; 488 | tv.tv_nsec += reltime->tv_nsec; 489 | if (tv.tv_nsec >= 1000000000) { 490 | ++tv.tv_sec; 491 | tv.tv_nsec -= 1000000000; 492 | } 493 | return bionic_pthread_cond_timedwait(cond, mutex, &tv); 494 | } 495 | 496 | int 497 | bionic_pthread_cond_timedwait_monotonic_np(bionic_cond_t *cond, bionic_mutex_t *mutex, const struct timespec *abstime) 498 | { 499 | assert(cond && mutex && abstime); 500 | struct timespec tv; 501 | clock_gettime(CLOCK_MONOTONIC, &tv); 502 | tv.tv_sec += abstime->tv_sec; 503 | tv.tv_nsec += abstime->tv_nsec; 504 | if (tv.tv_nsec >= 1000000000) { 505 | ++tv.tv_sec; 506 | tv.tv_nsec -= 1000000000; 507 | } 508 | return bionic_pthread_cond_timedwait(cond, mutex, &tv); 509 | } 510 | -------------------------------------------------------------------------------- /src/linker/NOTICE: -------------------------------------------------------------------------------- 1 | 2 | Copyright (c) 2005-2008, The Android Open Source Project 3 | 4 | Licensed under the Apache License, Version 2.0 (the "License"); 5 | you may not use this file except in compliance with the License. 6 | 7 | Unless required by applicable law or agreed to in writing, software 8 | distributed under the License is distributed on an "AS IS" BASIS, 9 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 10 | See the License for the specific language governing permissions and 11 | limitations under the License. 12 | 13 | 14 | Apache License 15 | Version 2.0, January 2004 16 | http://www.apache.org/licenses/ 17 | 18 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 19 | 20 | 1. Definitions. 21 | 22 | "License" shall mean the terms and conditions for use, reproduction, 23 | and distribution as defined by Sections 1 through 9 of this document. 24 | 25 | "Licensor" shall mean the copyright owner or entity authorized by 26 | the copyright owner that is granting the License. 27 | 28 | "Legal Entity" shall mean the union of the acting entity and all 29 | other entities that control, are controlled by, or are under common 30 | control with that entity. For the purposes of this definition, 31 | "control" means (i) the power, direct or indirect, to cause the 32 | direction or management of such entity, whether by contract or 33 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 34 | outstanding shares, or (iii) beneficial ownership of such entity. 35 | 36 | "You" (or "Your") shall mean an individual or Legal Entity 37 | exercising permissions granted by this License. 38 | 39 | "Source" form shall mean the preferred form for making modifications, 40 | including but not limited to software source code, documentation 41 | source, and configuration files. 42 | 43 | "Object" form shall mean any form resulting from mechanical 44 | transformation or translation of a Source form, including but 45 | not limited to compiled object code, generated documentation, 46 | and conversions to other media types. 47 | 48 | "Work" shall mean the work of authorship, whether in Source or 49 | Object form, made available under the License, as indicated by a 50 | copyright notice that is included in or attached to the work 51 | (an example is provided in the Appendix below). 52 | 53 | "Derivative Works" shall mean any work, whether in Source or Object 54 | form, that is based on (or derived from) the Work and for which the 55 | editorial revisions, annotations, elaborations, or other modifications 56 | represent, as a whole, an original work of authorship. For the purposes 57 | of this License, Derivative Works shall not include works that remain 58 | separable from, or merely link (or bind by name) to the interfaces of, 59 | the Work and Derivative Works thereof. 60 | 61 | "Contribution" shall mean any work of authorship, including 62 | the original version of the Work and any modifications or additions 63 | to that Work or Derivative Works thereof, that is intentionally 64 | submitted to Licensor for inclusion in the Work by the copyright owner 65 | or by an individual or Legal Entity authorized to submit on behalf of 66 | the copyright owner. For the purposes of this definition, "submitted" 67 | means any form of electronic, verbal, or written communication sent 68 | to the Licensor or its representatives, including but not limited to 69 | communication on electronic mailing lists, source code control systems, 70 | and issue tracking systems that are managed by, or on behalf of, the 71 | Licensor for the purpose of discussing and improving the Work, but 72 | excluding communication that is conspicuously marked or otherwise 73 | designated in writing by the copyright owner as "Not a Contribution." 74 | 75 | "Contributor" shall mean Licensor and any individual or Legal Entity 76 | on behalf of whom a Contribution has been received by Licensor and 77 | subsequently incorporated within the Work. 78 | 79 | 2. Grant of Copyright License. Subject to the terms and conditions of 80 | this License, each Contributor hereby grants to You a perpetual, 81 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 82 | copyright license to reproduce, prepare Derivative Works of, 83 | publicly display, publicly perform, sublicense, and distribute the 84 | Work and such Derivative Works in Source or Object form. 85 | 86 | 3. Grant of Patent License. Subject to the terms and conditions of 87 | this License, each Contributor hereby grants to You a perpetual, 88 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 89 | (except as stated in this section) patent license to make, have made, 90 | use, offer to sell, sell, import, and otherwise transfer the Work, 91 | where such license applies only to those patent claims licensable 92 | by such Contributor that are necessarily infringed by their 93 | Contribution(s) alone or by combination of their Contribution(s) 94 | with the Work to which such Contribution(s) was submitted. If You 95 | institute patent litigation against any entity (including a 96 | cross-claim or counterclaim in a lawsuit) alleging that the Work 97 | or a Contribution incorporated within the Work constitutes direct 98 | or contributory patent infringement, then any patent licenses 99 | granted to You under this License for that Work shall terminate 100 | as of the date such litigation is filed. 101 | 102 | 4. Redistribution. You may reproduce and distribute copies of the 103 | Work or Derivative Works thereof in any medium, with or without 104 | modifications, and in Source or Object form, provided that You 105 | meet the following conditions: 106 | 107 | (a) You must give any other recipients of the Work or 108 | Derivative Works a copy of this License; and 109 | 110 | (b) You must cause any modified files to carry prominent notices 111 | stating that You changed the files; and 112 | 113 | (c) You must retain, in the Source form of any Derivative Works 114 | that You distribute, all copyright, patent, trademark, and 115 | attribution notices from the Source form of the Work, 116 | excluding those notices that do not pertain to any part of 117 | the Derivative Works; and 118 | 119 | (d) If the Work includes a "NOTICE" text file as part of its 120 | distribution, then any Derivative Works that You distribute must 121 | include a readable copy of the attribution notices contained 122 | within such NOTICE file, excluding those notices that do not 123 | pertain to any part of the Derivative Works, in at least one 124 | of the following places: within a NOTICE text file distributed 125 | as part of the Derivative Works; within the Source form or 126 | documentation, if provided along with the Derivative Works; or, 127 | within a display generated by the Derivative Works, if and 128 | wherever such third-party notices normally appear. The contents 129 | of the NOTICE file are for informational purposes only and 130 | do not modify the License. You may add Your own attribution 131 | notices within Derivative Works that You distribute, alongside 132 | or as an addendum to the NOTICE text from the Work, provided 133 | that such additional attribution notices cannot be construed 134 | as modifying the License. 135 | 136 | You may add Your own copyright statement to Your modifications and 137 | may provide additional or different license terms and conditions 138 | for use, reproduction, or distribution of Your modifications, or 139 | for any such Derivative Works as a whole, provided Your use, 140 | reproduction, and distribution of the Work otherwise complies with 141 | the conditions stated in this License. 142 | 143 | 5. Submission of Contributions. Unless You explicitly state otherwise, 144 | any Contribution intentionally submitted for inclusion in the Work 145 | by You to the Licensor shall be under the terms and conditions of 146 | this License, without any additional terms or conditions. 147 | Notwithstanding the above, nothing herein shall supersede or modify 148 | the terms of any separate license agreement you may have executed 149 | with Licensor regarding such Contributions. 150 | 151 | 6. Trademarks. This License does not grant permission to use the trade 152 | names, trademarks, service marks, or product names of the Licensor, 153 | except as required for reasonable and customary use in describing the 154 | origin of the Work and reproducing the content of the NOTICE file. 155 | 156 | 7. Disclaimer of Warranty. Unless required by applicable law or 157 | agreed to in writing, Licensor provides the Work (and each 158 | Contributor provides its Contributions) on an "AS IS" BASIS, 159 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 160 | implied, including, without limitation, any warranties or conditions 161 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 162 | PARTICULAR PURPOSE. You are solely responsible for determining the 163 | appropriateness of using or redistributing the Work and assume any 164 | risks associated with Your exercise of permissions under this License. 165 | 166 | 8. Limitation of Liability. In no event and under no legal theory, 167 | whether in tort (including negligence), contract, or otherwise, 168 | unless required by applicable law (such as deliberate and grossly 169 | negligent acts) or agreed to in writing, shall any Contributor be 170 | liable to You for damages, including any direct, indirect, special, 171 | incidental, or consequential damages of any character arising as a 172 | result of this License or out of the use or inability to use the 173 | Work (including but not limited to damages for loss of goodwill, 174 | work stoppage, computer failure or malfunction, or any and all 175 | other commercial damages or losses), even if such Contributor 176 | has been advised of the possibility of such damages. 177 | 178 | 9. Accepting Warranty or Additional Liability. While redistributing 179 | the Work or Derivative Works thereof, You may choose to offer, 180 | and charge a fee for, acceptance of support, warranty, indemnity, 181 | or other liability obligations and/or rights consistent with this 182 | License. However, in accepting such obligations, You may act only 183 | on Your own behalf and on Your sole responsibility, not on behalf 184 | of any other Contributor, and only if You agree to indemnify, 185 | defend, and hold each Contributor harmless for any liability 186 | incurred by, or claims asserted against, such Contributor by reason 187 | of your accepting any such warranty or additional liability. 188 | 189 | END OF TERMS AND CONDITIONS 190 | 191 | -------------------------------------------------------------------------------- /src/linker/README.TXT: -------------------------------------------------------------------------------- 1 | Android Dynamic Linker Design Notes 2 | =================================== 3 | 4 | Introduction: 5 | ------------- 6 | 7 | This document provides several notes related to the design of the Android 8 | dynamic linker. 9 | 10 | 11 | Prelinking: 12 | ----------- 13 | 14 | System libraries in Android are internally prelinked, which means that 15 | any internal relocations within them are stripped from the corresponding 16 | shared object, in order to reduce size and speed up loading. 17 | 18 | Such libraries can only be loaded at the very specific virtual memory address 19 | they have been prelinked to (during the build process). The list of prelinked 20 | system libraries and their corresponding virtual memory address is found in 21 | the file: 22 | 23 | build/core/prelink-linux-.map 24 | 25 | It should be updated each time a new system library is added to the 26 | system. 27 | 28 | The prelink step happens at build time, and uses the 'soslim' and 'apriori' 29 | tools: 30 | 31 | - 'apriori' is the real prelink tool which removes relocations from the 32 | shared object, however, it must be given a list of symbols to remove 33 | from the file. 34 | 35 | - 'soslim' is used to find symbols in an executable ELF file 36 | and generate a list that can be passed to 'apriori'. 37 | 38 | By default, these tools are only used to remove internal symbols from 39 | libraries, though they have been designed to allow more aggressive 40 | optimizations (e.g. 'global' prelinking and symbol stripping, which 41 | prevent replacing individual system libraries though). 42 | 43 | You can disable prelinking at build time by modifying your Android.mk with 44 | a line like: 45 | 46 | LOCAL_PRELINK_MODULE := false 47 | 48 | 49 | Initialization and Termination functions: 50 | ----------------------------------------- 51 | 52 | The Unix Sys V Binary Interface standard states that an 53 | executable can have the following entries in its .dynamic 54 | section: 55 | 56 | DT_INIT 57 | Points to the address of an initialization function 58 | that must be called when the file is loaded. 59 | 60 | DT_INIT_ARRAY 61 | Points to an array of function addresses that must be 62 | called, in-order, to perform initialization. Some of 63 | the entries in the array can be 0 or -1, and should 64 | be ignored. 65 | 66 | Note: this is generally stored in a .init_array section 67 | 68 | DT_INIT_ARRAYSZ 69 | The size of the DT_INITARRAY, if any 70 | 71 | DT_FINI 72 | Points to the address of a finalization function which 73 | must be called when the file is unloaded or the process 74 | terminated. 75 | 76 | DT_FINI_ARRAY 77 | Same as DT_INITARRAY but for finalizers. Note that the 78 | functions must be called in reverse-order though 79 | 80 | Note: this is generally stored in a .fini_array section 81 | 82 | DT_FINI_ARRAYSZ 83 | Size of FT_FINIARRAY 84 | 85 | DT_PREINIT_ARRAY 86 | An array similar to DT_INIT_ARRAY which must *only* be 87 | present in executables, not shared libraries, which contains 88 | a list of functions that need to be called before any other 89 | initialization function (i.e. DT_INIT and/or DT_INIT_ARRAY) 90 | in the executable or any of its libraries. 91 | 92 | Note: this is generally stored in a .preinit_array section 93 | 94 | DT_PREINIT_ARRAYSZ 95 | The size of DT_PREINIT_ARRAY 96 | 97 | If both a DT_INIT and DT_INITARRAY entry are present, the DT_INIT 98 | function must be called before the DT_INITARRAY functions. 99 | 100 | Consequently, the DT_FINIARRAY must be parsed in reverse order before 101 | the DT_FINI function, if both are available. 102 | 103 | Note that the implementation of static C++ constructors is very 104 | much processor dependent, and may use different ELF sections. 105 | 106 | On the ARM (see "C++ ABI for ARM" document), the static constructors 107 | must be called explicitly from the DT_INIT_ARRAY, and each one of them 108 | shall register a destructor by calling the special __eabi_atexit() 109 | function (provided by the C library). The DT_FINI_ARRAY is not used 110 | by static C++ destructors. 111 | 112 | On x86, the lists of constructors and destructors are placed in special 113 | sections named ".ctors" and ".dtors", and the DT_INIT / DT_FINI functions 114 | are in charge of calling them explicitly. 115 | 116 | 117 | Debugging: 118 | ---------- 119 | 120 | It is possible to enable debug output in the dynamic linker. To do so, 121 | follow these steps: 122 | 123 | 1/ Modify the line in Android.mk that says: 124 | 125 | LOCAL_CFLAGS += -DLINKER_DEBUG=0 126 | 127 | Into the following: 128 | 129 | LOCAL_CFLAGS += -DLINKER_DEBUG=1 130 | 131 | 2/ Force-rebuild the dynamic linker: 132 | 133 | cd bionic/linker 134 | mm -B 135 | 136 | 3/ Rebuild a new system image. 137 | 138 | You can increase the verbosity of debug traces by defining the DEBUG 139 | environment variable to a numeric value from 0 to 2. This will only 140 | affect new processes being launched. 141 | 142 | By default, traces are sent to logcat, with the "linker" tag. You can 143 | change this to go to stdout instead by setting the definition of 144 | LINKER_DEBUG_TO_LOG to 0 in "linker_debug.h". 145 | -------------------------------------------------------------------------------- /src/linker/bionic_tls.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008 The Android Open Source Project 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in 12 | * the documentation and/or other materials provided with the 13 | * distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 | * SUCH DAMAGE. 27 | */ 28 | #ifndef _SYS_TLS_H 29 | #define _SYS_TLS_H 30 | 31 | #define HAVE_ARM_TLS_REGISTER 32 | 33 | #include 34 | 35 | __BEGIN_DECLS 36 | 37 | /** WARNING WARNING WARNING 38 | ** 39 | ** This header file is *NOT* part of the public Bionic ABI/API 40 | ** and should not be used/included by user-serviceable parts of 41 | ** the system (e.g. applications). 42 | ** 43 | ** It is only provided here for the benefit of the system dynamic 44 | ** linker and the OpenGL sub-system (which needs to access the 45 | ** pre-allocated slot directly for performance reason). 46 | **/ 47 | 48 | /* maximum number of elements in the TLS array */ 49 | #define BIONIC_TLS_SLOTS 64 50 | 51 | /* note that slot 0, called TLS_SLOT_SELF must point to itself. 52 | * this is required to implement thread-local storage with the x86 53 | * Linux kernel, that reads the TLS from fs:[0], where 'fs' is a 54 | * thread-specific segment descriptor... 55 | */ 56 | 57 | /* Well known TLS slots */ 58 | #define TLS_SLOT_SELF 0 59 | #define TLS_SLOT_THREAD_ID 1 60 | #define TLS_SLOT_ERRNO 2 61 | 62 | #define TLS_SLOT_OPENGL_API 3 63 | #define TLS_SLOT_OPENGL 4 64 | 65 | /* this slot is only used to pass information from the dynamic linker to 66 | * libc.so when the C library is loaded in to memory. The C runtime init 67 | * function will then clear it. Since its use is extremely temporary, 68 | * we reuse an existing location. 69 | */ 70 | #define TLS_SLOT_BIONIC_PREINIT (TLS_SLOT_ERRNO+1) 71 | 72 | /* small technical note: it is not possible to call pthread_setspecific 73 | * on keys that are <= TLS_SLOT_MAX_WELL_KNOWN, which is why it is set to 74 | * TLS_SLOT_ERRNO. 75 | * 76 | * later slots like TLS_SLOT_OPENGL are pre-allocated through the use of 77 | * TLS_DEFAULT_ALLOC_MAP. this means that there is no need to use 78 | * pthread_key_create() to initialize them. on the other hand, there is 79 | * no destructor associated to them (we might need to implement this later) 80 | */ 81 | #define TLS_SLOT_MAX_WELL_KNOWN TLS_SLOT_ERRNO 82 | 83 | #define TLS_DEFAULT_ALLOC_MAP 0x0000001F 84 | 85 | /* set the Thread Local Storage, must contain at least BIONIC_TLS_SLOTS pointers */ 86 | extern void __init_tls(void** tls, void* thread_info); 87 | 88 | /* syscall only, do not call directly */ 89 | extern int __set_tls(void *ptr); 90 | 91 | /* get the TLS */ 92 | #ifdef __arm__ 93 | /* The standard way to get the TLS is to call a kernel helper 94 | * function (i.e. a function provided at a fixed address in a 95 | * "magic page" mapped in all user-space address spaces ), which 96 | * contains the most appropriate code path for the target device. 97 | * 98 | * However, for performance reasons, we're going to use our own 99 | * machine code for the system's C shared library. 100 | * 101 | * We cannot use this optimization in the static version of the 102 | * C library, because we don't know where the corresponding code 103 | * is going to run. 104 | */ 105 | # ifdef LIBC_STATIC 106 | 107 | /* Use the kernel helper in static C library. */ 108 | typedef volatile void* (__kernel_get_tls_t)(void); 109 | # define __get_tls() (*(__kernel_get_tls_t *)0xffff0fe0)() 110 | 111 | # else /* !LIBC_STATIC */ 112 | /* Use optimized code path. 113 | * Note that HAVE_ARM_TLS_REGISTER is build-specific 114 | * (it must match your kernel configuration) 115 | */ 116 | # ifdef HAVE_ARM_TLS_REGISTER 117 | /* We can read the address directly from a coprocessor 118 | * register, which avoids touching the data cache 119 | * completely. 120 | */ 121 | # define __get_tls() \ 122 | ({ register unsigned int __val asm("r0"); \ 123 | asm ("mrc p15, 0, r0, c13, c0, 3" : "=r"(__val) ); \ 124 | (volatile void*)__val; }) 125 | # else /* !HAVE_ARM_TLS_REGISTER */ 126 | /* The kernel provides the address of the TLS at a fixed 127 | * address of the magic page too. 128 | */ 129 | # define __get_tls() ( *((volatile void **) 0xffff0ff0) ) 130 | # endif 131 | # endif /* !LIBC_STATIC */ 132 | #else /* !ARM */ 133 | extern void* __get_tls( void ); 134 | #endif /* !ARM */ 135 | 136 | /* return the stack base and size, used by our malloc debugger */ 137 | extern void* __get_stack_base(int *p_stack_size); 138 | 139 | __END_DECLS 140 | 141 | #endif /* _SYS_TLS_H */ 142 | -------------------------------------------------------------------------------- /src/linker/dlfcn.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2007 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include "linker.h" 22 | #include "linker_format.h" 23 | 24 | #include "wrapper/wrapper.h" 25 | #include "wrapper/verbose.h" 26 | #include "linker_debug.h" 27 | 28 | #ifdef APKENV_DEBUG 29 | # define LINKER_DEBUG_PRINTF(...) PRINT(__VA_ARGS__) 30 | #else 31 | # define LINKER_DEBUG_PRINTF(...) 32 | #endif 33 | /* This file hijacks the symbols stubbed out in libdl.so. */ 34 | 35 | #define DL_SUCCESS 0 36 | #define DL_ERR_CANNOT_LOAD_LIBRARY 1 37 | #define DL_ERR_INVALID_LIBRARY_HANDLE 2 38 | #define DL_ERR_BAD_SYMBOL_NAME 3 39 | #define DL_ERR_SYMBOL_NOT_FOUND 4 40 | #define DL_ERR_SYMBOL_NOT_GLOBAL 5 41 | 42 | static char dl_err_buf[1024]; 43 | static const char *dl_err_str; 44 | 45 | static const char *dl_errors[] = { 46 | [DL_ERR_CANNOT_LOAD_LIBRARY] = "Cannot load library", 47 | [DL_ERR_INVALID_LIBRARY_HANDLE] = "Invalid library handle", 48 | [DL_ERR_BAD_SYMBOL_NAME] = "Invalid symbol name", 49 | [DL_ERR_SYMBOL_NOT_FOUND] = "Symbol not found", 50 | [DL_ERR_SYMBOL_NOT_GLOBAL] = "Symbol is not global", 51 | }; 52 | 53 | #define likely(expr) __builtin_expect (expr, 1) 54 | #define unlikely(expr) __builtin_expect (expr, 0) 55 | 56 | static pthread_mutex_t apkenv_dl_lock = PTHREAD_MUTEX_INITIALIZER; 57 | 58 | static void set_dlerror(int err) 59 | { 60 | format_buffer(dl_err_buf, sizeof(dl_err_buf), "%s: %s", dl_errors[err], 61 | apkenv_linker_get_error()); 62 | dl_err_str = (const char *)&dl_err_buf[0]; 63 | } 64 | 65 | void *bionic_dlopen(const char *filename, int flag) 66 | { 67 | verbose("%s (%d)", filename, flag); 68 | soinfo *ret; 69 | pthread_mutex_lock(&apkenv_dl_lock); 70 | ret = apkenv_find_library(filename, false); 71 | 72 | if (unlikely(ret == NULL)) { 73 | if (!(flag & (RTLD_LAZY | RTLD_NOW))) 74 | flag |= RTLD_NOW; 75 | 76 | char path[4096]; 77 | snprintf(path, sizeof(path), RUNTIMEPATH "/%s", filename); 78 | if (!(ret = dlopen(filename, flag) && !(ret = dlopen(path, flag)))) 79 | set_dlerror(DL_ERR_CANNOT_LOAD_LIBRARY); 80 | } else { 81 | apkenv_call_constructors_recursive(ret); 82 | ret->refcount++; 83 | } 84 | pthread_mutex_unlock(&apkenv_dl_lock); 85 | return ret; 86 | } 87 | 88 | const char *bionic_dlerror(void) 89 | { 90 | const char *tmp = dl_err_str; 91 | dl_err_str = NULL; 92 | return (const char *)tmp; 93 | } 94 | 95 | enum { 96 | WRAPPER_DYNHOOK, 97 | }; 98 | 99 | #define MIN(a,b) (((a)<(b))?(a):(b)) 100 | 101 | void *bionic_dlsym(void *handle, const char *symbol) 102 | { 103 | verbose("%p, %s", handle, symbol); 104 | 105 | soinfo *found; 106 | Elf32_Sym *sym; 107 | unsigned bind; 108 | 109 | pthread_mutex_lock(&apkenv_dl_lock); 110 | 111 | if(unlikely(symbol == 0)) { 112 | set_dlerror(DL_ERR_BAD_SYMBOL_NAME); 113 | goto err; 114 | } 115 | 116 | { 117 | char wrap_sym_name[1024] = { 'b', 'i', 'o', 'n', 'i', 'c', '_' }; 118 | memcpy(wrap_sym_name + 7, symbol, MIN(sizeof(wrap_sym_name) - 7, strlen(symbol))); 119 | if ((sym = dlsym(RTLD_DEFAULT, wrap_sym_name))) { 120 | pthread_mutex_unlock(&apkenv_dl_lock); 121 | verbose("found bionic_ version"); 122 | return wrapper_create(symbol, sym); 123 | } else if ((sym = dlsym(RTLD_DEFAULT, symbol))) { 124 | pthread_mutex_unlock(&apkenv_dl_lock); 125 | verbose("found system version"); 126 | return wrapper_create(symbol, sym); 127 | } 128 | } 129 | 130 | if(unlikely(handle == 0)) { 131 | set_dlerror(DL_ERR_INVALID_LIBRARY_HANDLE); 132 | goto err; 133 | } 134 | 135 | if(handle == RTLD_DEFAULT) { 136 | sym = apkenv_lookup(symbol, &found, NULL); 137 | } else if(handle == RTLD_NEXT) { 138 | void *ret_addr = __builtin_return_address(0); 139 | soinfo *si = apkenv_find_containing_library(ret_addr); 140 | 141 | sym = NULL; 142 | if(si && si->next) { 143 | sym = apkenv_lookup(symbol, &found, si->next); 144 | } 145 | } else { 146 | found = (soinfo*)handle; 147 | sym = apkenv_lookup_in_library(found, symbol); 148 | } 149 | 150 | if(likely(sym != 0)) { 151 | bind = ELF32_ST_BIND(sym->st_info); 152 | 153 | if(likely((bind == STB_GLOBAL) && (sym->st_shndx != 0))) { 154 | unsigned ret = sym->st_value + found->base; 155 | pthread_mutex_unlock(&apkenv_dl_lock); 156 | return wrapper_create((char*)symbol, (void*)ret); 157 | } 158 | 159 | set_dlerror(DL_ERR_SYMBOL_NOT_GLOBAL); 160 | } 161 | else 162 | set_dlerror(DL_ERR_SYMBOL_NOT_FOUND); 163 | 164 | err: 165 | LINKER_DEBUG_PRINTF("symbol %s has not been hooked\n",symbol); 166 | pthread_mutex_unlock(&apkenv_dl_lock); 167 | return 0; 168 | } 169 | 170 | int bionic_dladdr(const void *addr, Dl_info *info) 171 | { 172 | int ret = 0; 173 | 174 | pthread_mutex_lock(&apkenv_dl_lock); 175 | 176 | /* Determine if this address can be found in any library currently mapped */ 177 | soinfo *si = apkenv_find_containing_library(addr); 178 | 179 | if(si) { 180 | memset(info, 0, sizeof(*info)); 181 | 182 | info->dli_fname = si->name; 183 | info->dli_fbase = (void*)(uintptr_t)si->base; 184 | 185 | /* Determine if any symbol in the library contains the specified address */ 186 | Elf32_Sym *sym = apkenv_find_containing_symbol(addr, si); 187 | 188 | if(sym != NULL) { 189 | info->dli_sname = si->strtab + sym->st_name; 190 | info->dli_saddr = (void*)(uintptr_t)(si->base + sym->st_value); 191 | } 192 | 193 | ret = 1; 194 | } 195 | 196 | pthread_mutex_unlock(&apkenv_dl_lock); 197 | 198 | return ret; 199 | } 200 | 201 | int bionic_dlclose(void *handle) 202 | { 203 | #if 0 204 | if (is_builtin_lib_handle(handle)) 205 | return 0; 206 | #endif 207 | 208 | pthread_mutex_lock(&apkenv_dl_lock); 209 | (void)apkenv_unload_library((soinfo*)handle); 210 | pthread_mutex_unlock(&apkenv_dl_lock); 211 | return 0; 212 | } 213 | 214 | 215 | #if defined(ANDROID_ARM_LINKER) 216 | // 0000000 00011111 111112 22222222 2333333 333344444444445555555 217 | // 0123456 78901234 567890 12345678 9012345 678901234567890123456 218 | #define ANDROID_LIBDL_STRTAB \ 219 | "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_unwind_find_exidx\0" 220 | 221 | _Unwind_Ptr bionic_dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount); 222 | 223 | #elif defined(ANDROID_X86_LINKER) 224 | // 0000000 00011111 111112 22222222 2333333 3333444444444455 225 | // 0123456 78901234 567890 12345678 9012345 6789012345678901 226 | #define ANDROID_LIBDL_STRTAB \ 227 | "dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_iterate_phdr\0" 228 | int 229 | bionic_dl_iterate_phdr(int (*cb)(struct dl_phdr_info *info, size_t size, void *data), void *data); 230 | 231 | #else 232 | #error Unsupported architecture. Only ARM and x86 are presently supported. 233 | #endif 234 | 235 | static Elf32_Sym apkenv_libdl_symtab[7]; 236 | 237 | /* Fake out a hash table with a single bucket. 238 | * A search of the hash table will look through 239 | * apkenv_libdl_symtab starting with index [1], then 240 | * use apkenv_libdl_chains to find the next index to 241 | * look at. apkenv_libdl_chains should be set up to 242 | * walk through every element in apkenv_libdl_symtab, 243 | * and then end with 0 (sentinel value). 244 | * 245 | * I.e., apkenv_libdl_chains should look like 246 | * { 0, 2, 3, ... N, 0 } where N is the number 247 | * of actual symbols, or nelems(apkenv_libdl_symtab)-1 248 | * (since the first element of apkenv_libdl_symtab is not 249 | * a real symbol). 250 | * 251 | * (see _elf_lookup()) 252 | * 253 | * Note that adding any new symbols here requires 254 | * stubbing them out in libdl. 255 | */ 256 | static unsigned apkenv_libdl_buckets[1] = { 1 }; 257 | static unsigned apkenv_libdl_chains[7] = { 0, 2, 3, 4, 5, 6, 0 }; 258 | 259 | soinfo apkenv_libdl_info = { 260 | .name = "libdl.so", 261 | .flags = FLAG_LINKED, 262 | 263 | .strtab = ANDROID_LIBDL_STRTAB, 264 | .symtab = apkenv_libdl_symtab, 265 | 266 | .nbucket = 1, 267 | .nchain = 7, 268 | .bucket = apkenv_libdl_buckets, 269 | .chain = apkenv_libdl_chains, 270 | }; 271 | 272 | __attribute__((constructor)) 273 | void 274 | construct(void) 275 | { 276 | const Elf32_Sym symtab[sizeof(apkenv_libdl_symtab) / sizeof(apkenv_libdl_symtab[0])] = { 277 | // total length of apkenv_libdl_info.strtab, including trailing 0 278 | // This is actually the the STH_UNDEF entry. Technically, it's 279 | // supposed to have st_name == 0, but instead, it points to an index 280 | // in the strtab with a \0 to make iterating through the symtab easier. 281 | { 282 | .st_name = sizeof(ANDROID_LIBDL_STRTAB) - 1, 283 | }, { 284 | .st_name = 0, // starting index of the name in apkenv_libdl_info.strtab 285 | .st_value = (Elf32_Addr)(uintptr_t)bionic_dlopen, 286 | .st_info = STB_GLOBAL << 4, 287 | .st_shndx = 1, 288 | }, { 289 | .st_name = 7, 290 | .st_value = (Elf32_Addr)(uintptr_t)bionic_dlclose, 291 | .st_info = STB_GLOBAL << 4, 292 | .st_shndx = 1, 293 | }, { 294 | .st_name = 15, 295 | .st_value = (Elf32_Addr)(uintptr_t)bionic_dlsym, 296 | .st_info = STB_GLOBAL << 4, 297 | .st_shndx = 1, 298 | }, { 299 | .st_name = 21, 300 | .st_value = (Elf32_Addr)(uintptr_t)bionic_dlerror, 301 | .st_info = STB_GLOBAL << 4, 302 | .st_shndx = 1, 303 | }, { 304 | .st_name = 29, 305 | .st_value = (Elf32_Addr)(uintptr_t)bionic_dladdr, 306 | .st_info = STB_GLOBAL << 4, 307 | .st_shndx = 1, 308 | }, 309 | #ifdef ANDROID_ARM_LINKER 310 | { 311 | .st_name = 36, 312 | .st_value = (Elf32_Addr)(uintptr_t)bionic_dl_unwind_find_exidx, 313 | .st_info = STB_GLOBAL << 4, 314 | .st_shndx = 1, 315 | }, 316 | #elif defined(ANDROID_X86_LINKER) 317 | { 318 | .st_name = 36, 319 | .st_value = (Elf32_Addr)(uintptr_t)bionic_dl_iterate_phdr, 320 | .st_info = STB_GLOBAL << 4, 321 | .st_shndx = 1, 322 | }, 323 | #endif 324 | }; 325 | memcpy(apkenv_libdl_symtab, symtab, sizeof(symtab)); 326 | } 327 | -------------------------------------------------------------------------------- /src/linker/dlfcn.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void dl_parse_library_path(const char *path, char *delim); 4 | void *bionic_dlopen(const char *filename, int flag); 5 | const char *bionic_dlerror(void); 6 | void *bionic_dlsym(void *handle, const char *symbol); 7 | int bionic_dlclose(void *handle); 8 | -------------------------------------------------------------------------------- /src/linker/linker.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008 The Android Open Source Project 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in 12 | * the documentation and/or other materials provided with the 13 | * distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 | * SUCH DAMAGE. 27 | */ 28 | 29 | #ifndef _LINKER_H_ 30 | #define _LINKER_H_ 31 | 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | #undef PAGE_MASK 39 | #undef PAGE_SIZE 40 | #define PAGE_SIZE 4096 41 | #define PAGE_MASK 4095 42 | 43 | void apkenv_debugger_init(); 44 | 45 | /* magic shared structures that GDB knows about */ 46 | 47 | #if 0 48 | struct link_map 49 | { 50 | uintptr_t l_addr; 51 | char * l_name; 52 | uintptr_t l_ld; 53 | struct link_map * l_next; 54 | struct link_map * l_prev; 55 | }; 56 | 57 | /* needed for dl_iterate_phdr to be passed to the callbacks provided */ 58 | struct dl_phdr_info 59 | { 60 | Elf32_Addr dlpi_addr; 61 | const char *dlpi_name; 62 | const Elf32_Phdr *dlpi_phdr; 63 | Elf32_Half dlpi_phnum; 64 | }; 65 | 66 | 67 | // Values for r_debug->state 68 | enum { 69 | RT_CONSISTENT, 70 | RT_ADD, 71 | RT_DELETE 72 | }; 73 | 74 | struct r_debug 75 | { 76 | int32_t r_version; 77 | struct link_map * r_map; 78 | void (*r_brk)(void); 79 | int32_t r_state; 80 | uintptr_t r_ldbase; 81 | }; 82 | #endif 83 | 84 | typedef struct soinfo soinfo; 85 | 86 | #define FLAG_LINKED 0x00000001 87 | #define FLAG_ERROR 0x00000002 88 | #define FLAG_EXE 0x00000004 // The main executable 89 | #define FLAG_LINKER 0x00000010 // The linker itself 90 | 91 | #define SOINFO_NAME_LEN 128 92 | 93 | struct soinfo 94 | { 95 | const char name[SOINFO_NAME_LEN]; 96 | Elf32_Phdr *phdr; 97 | int phnum; 98 | unsigned entry; 99 | unsigned base; 100 | unsigned size; 101 | 102 | int unused; // DO NOT USE, maintained for compatibility. 103 | 104 | unsigned *dynamic; 105 | 106 | unsigned wrprotect_start; 107 | unsigned wrprotect_end; 108 | 109 | soinfo *next; 110 | unsigned flags; 111 | 112 | const char *strtab; 113 | Elf32_Sym *symtab; 114 | 115 | unsigned nbucket; 116 | unsigned nchain; 117 | unsigned *bucket; 118 | unsigned *chain; 119 | 120 | unsigned *plt_got; 121 | 122 | Elf32_Rel *plt_rel; 123 | unsigned plt_rel_count; 124 | 125 | Elf32_Rel *rel; 126 | unsigned rel_count; 127 | 128 | unsigned *preinit_array; 129 | unsigned preinit_array_count; 130 | 131 | unsigned *init_array; 132 | unsigned init_array_count; 133 | unsigned *fini_array; 134 | unsigned fini_array_count; 135 | 136 | void (*init_func)(void); 137 | void (*fini_func)(void); 138 | 139 | #ifdef ANDROID_ARM_LINKER 140 | /* ARM EABI section used for stack unwinding. */ 141 | unsigned *ARM_exidx; 142 | unsigned ARM_exidx_count; 143 | #endif 144 | 145 | unsigned refcount; 146 | struct link_map linkmap; 147 | 148 | int constructors_called; 149 | 150 | Elf32_Addr gnu_relro_start; 151 | unsigned gnu_relro_len; 152 | 153 | /* apkenv stuff */ 154 | char fullpath[SOINFO_NAME_LEN]; 155 | }; 156 | 157 | 158 | extern soinfo apkenv_libdl_info; 159 | 160 | #ifdef ANDROID_ARM_LINKER 161 | 162 | #define R_ARM_COPY 20 163 | #define R_ARM_GLOB_DAT 21 164 | #define R_ARM_JUMP_SLOT 22 165 | #define R_ARM_RELATIVE 23 166 | 167 | /* According to the AAPCS specification, we only 168 | * need the above relocations. However, in practice, 169 | * the following ones turn up from time to time. 170 | */ 171 | #define R_ARM_ABS32 2 172 | #define R_ARM_REL32 3 173 | 174 | #elif defined(ANDROID_X86_LINKER) 175 | 176 | #define R_386_32 1 177 | #define R_386_PC32 2 178 | #define R_386_GLOB_DAT 6 179 | #define R_386_JUMP_SLOT 7 180 | #define R_386_RELATIVE 8 181 | 182 | #endif 183 | 184 | #ifndef DT_INIT_ARRAY 185 | #define DT_INIT_ARRAY 25 186 | #endif 187 | 188 | #ifndef DT_FINI_ARRAY 189 | #define DT_FINI_ARRAY 26 190 | #endif 191 | 192 | #ifndef DT_INIT_ARRAYSZ 193 | #define DT_INIT_ARRAYSZ 27 194 | #endif 195 | 196 | #ifndef DT_FINI_ARRAYSZ 197 | #define DT_FINI_ARRAYSZ 28 198 | #endif 199 | 200 | #ifndef DT_PREINIT_ARRAY 201 | #define DT_PREINIT_ARRAY 32 202 | #endif 203 | 204 | #ifndef DT_PREINIT_ARRAYSZ 205 | #define DT_PREINIT_ARRAYSZ 33 206 | #endif 207 | 208 | soinfo *apkenv_find_library(const char *name, const bool try_glibc); 209 | unsigned apkenv_unload_library(soinfo *si); 210 | Elf32_Sym *apkenv_lookup_in_library(soinfo *si, const char *name); 211 | Elf32_Sym *apkenv_lookup(const char *name, soinfo **found, soinfo *start); 212 | soinfo *apkenv_find_containing_library(const void *addr); 213 | Elf32_Sym *apkenv_find_containing_symbol(const void *addr, soinfo *si); 214 | const char *apkenv_linker_get_error(void); 215 | void apkenv_call_constructors_recursive(soinfo *si); 216 | 217 | #ifdef ANDROID_ARM_LINKER 218 | typedef long unsigned int *_Unwind_Ptr; 219 | _Unwind_Ptr apkenv_dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount); 220 | #elif defined(ANDROID_X86_LINKER) 221 | int apkenv_dl_iterate_phdr(int (*cb)(struct dl_phdr_info *, size_t, void *), void *); 222 | #endif 223 | 224 | void apkenv_notify_gdb_of_libraries(void); 225 | int apkenv_add_sopath(const char *path); 226 | 227 | #endif 228 | -------------------------------------------------------------------------------- /src/linker/linker_debug.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008-2010 The Android Open Source Project 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in 12 | * the documentation and/or other materials provided with the 13 | * distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 | * SUCH DAMAGE. 27 | */ 28 | 29 | #ifndef _LINKER_DEBUG_H_ 30 | #define _LINKER_DEBUG_H_ 31 | 32 | #include 33 | 34 | #ifndef LINKER_DEBUG 35 | #error LINKER_DEBUG should be defined to either 1 or 0 in Android.mk 36 | #endif 37 | 38 | /* set LINKER_DEBUG_TO_LOG to 1 to send the logs to logcat, 39 | * or 0 to use stdout instead. 40 | */ 41 | #define LINKER_DEBUG_TO_LOG 0 42 | #define TRACE_DEBUG 1 43 | #define DO_TRACE_LOOKUP 1 44 | #define DO_TRACE_RELO 1 45 | #define TIMING 0 46 | #define STATS 0 47 | #define COUNT_PAGES 0 48 | 49 | /********************************************************************* 50 | * You shouldn't need to modify anything below unless you are adding 51 | * more debugging information. 52 | * 53 | * To enable/disable specific debug options, change the defines above 54 | *********************************************************************/ 55 | 56 | 57 | /*********************************************************************/ 58 | #undef TRUE 59 | #undef FALSE 60 | #define TRUE 1 61 | #define FALSE 0 62 | 63 | /* Only use printf() during debugging. We have seen occasional memory 64 | * corruption when the linker uses printf(). 65 | */ 66 | #if LINKER_DEBUG 67 | #include "linker_format.h" 68 | extern int apkenv_debug_verbosity; 69 | #if LINKER_DEBUG_TO_LOG 70 | extern int apkenv_format_log(int, const char *, const char *, ...); 71 | #define _PRINTVF(v,f,x...) \ 72 | do { \ 73 | if (apkenv_debug_verbosity > (v)) apkenv_format_log(5-(v),"linker",x); \ 74 | } while (0) 75 | #else /* !LINKER_DEBUG_TO_LOG */ 76 | #define _PRINTVF(v,f,x...) \ 77 | do { \ 78 | if (apkenv_debug_verbosity > (v)) fprintf(stderr, x); \ 79 | } while (0) 80 | #endif /* !LINKER_DEBUG_TO_LOG */ 81 | #else /* !LINKER_DEBUG */ 82 | #define _PRINTVF(v,f,x...) do {} while(0) 83 | #endif /* LINKER_DEBUG */ 84 | 85 | #define PRINT(x...) _PRINTVF(-1, FALSE, x) 86 | #define INFO(x...) _PRINTVF(1, TRUE, x) 87 | #define TRACE(x...) _PRINTVF(1, TRUE, x) 88 | #define WARN(fmt,args...) \ 89 | _PRINTVF(-1, TRUE, "%s:%d| WARNING: " fmt, __FILE__, __LINE__, ## args) 90 | #define ERROR(fmt,args...) \ 91 | printf("%s:%d| ERROR: " fmt, __FILE__, __LINE__, ## args) 92 | 93 | 94 | #if TRACE_DEBUG 95 | #define DEBUG(x...) _PRINTVF(2, TRUE, "DEBUG: " x) 96 | #else /* !TRACE_DEBUG */ 97 | #define DEBUG(x...) do {} while (0) 98 | #endif /* TRACE_DEBUG */ 99 | 100 | #if LINKER_DEBUG 101 | #define TRACE_TYPE(t,x...) do { if (DO_TRACE_##t) { TRACE(x); } } while (0) 102 | #else /* !LINKER_DEBUG */ 103 | #define TRACE_TYPE(t,x...) do {} while (0) 104 | #endif /* LINKER_DEBUG */ 105 | 106 | #if STATS 107 | #define RELOC_ABSOLUTE 0 108 | #define RELOC_RELATIVE 1 109 | #define RELOC_COPY 2 110 | #define RELOC_SYMBOL 3 111 | #define NUM_RELOC_STATS 4 112 | 113 | struct _link_stats { 114 | int reloc[NUM_RELOC_STATS]; 115 | }; 116 | extern struct _link_stats apkenv_linker_stats; 117 | 118 | #define COUNT_RELOC(type) \ 119 | do { if (type >= 0 && type < NUM_RELOC_STATS) { \ 120 | apkenv_linker_stats.reloc[type] += 1; \ 121 | } else { \ 122 | PRINT("Unknown reloc stat requested\n"); \ 123 | } \ 124 | } while(0) 125 | #else /* !STATS */ 126 | #define COUNT_RELOC(type) do {} while(0) 127 | #endif /* STATS */ 128 | 129 | #if TIMING 130 | #undef WARN 131 | #define WARN(x...) do {} while (0) 132 | #endif /* TIMING */ 133 | 134 | #if COUNT_PAGES 135 | extern unsigned apkenv_bitmask[]; 136 | #define MARK(offset) do { \ 137 | apkenv_bitmask[((offset) >> 12) >> 3] |= (1 << (((offset) >> 12) & 7)); \ 138 | } while(0) 139 | #else 140 | #define MARK(x) do {} while (0) 141 | #endif 142 | 143 | #define DEBUG_DUMP_PHDR(phdr, name, pid) do { \ 144 | DEBUG("%5d %s (phdr = 0x%08x)\n", (pid), (name), (unsigned)(phdr)); \ 145 | DEBUG("\t\tphdr->offset = 0x%08x\n", (unsigned)((phdr)->p_offset)); \ 146 | DEBUG("\t\tphdr->p_vaddr = 0x%08x\n", (unsigned)((phdr)->p_vaddr)); \ 147 | DEBUG("\t\tphdr->p_paddr = 0x%08x\n", (unsigned)((phdr)->p_paddr)); \ 148 | DEBUG("\t\tphdr->p_filesz = 0x%08x\n", (unsigned)((phdr)->p_filesz)); \ 149 | DEBUG("\t\tphdr->p_memsz = 0x%08x\n", (unsigned)((phdr)->p_memsz)); \ 150 | DEBUG("\t\tphdr->p_flags = 0x%08x\n", (unsigned)((phdr)->p_flags)); \ 151 | DEBUG("\t\tphdr->p_align = 0x%08x\n", (unsigned)((phdr)->p_align)); \ 152 | } while (0) 153 | 154 | #endif /* _LINKER_DEBUG_H_ */ 155 | -------------------------------------------------------------------------------- /src/linker/linker_environ.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 The Android Open Source Project 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in 12 | * the documentation and/or other materials provided with the 13 | * distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 | * SUCH DAMAGE. 27 | */ 28 | #include "linker_environ.h" 29 | #include 30 | 31 | static char** apkenv__envp; 32 | 33 | /* Returns 1 if 'str' points to a valid environment variable definition. 34 | * For now, we check that: 35 | * - It is smaller than MAX_ENV_LEN (to detect non-zero terminated strings) 36 | * - It contains at least one equal sign that is not the first character 37 | */ 38 | static int 39 | apkenv__is_valid_definition(const char* str) 40 | { 41 | int pos = 0; 42 | int first_equal_pos = -1; 43 | 44 | /* According to its sources, the kernel uses 32*PAGE_SIZE by default 45 | * as the maximum size for an env. variable definition. 46 | */ 47 | const int MAX_ENV_LEN = 32*4096; 48 | 49 | if (str == NULL) 50 | return 0; 51 | 52 | /* Parse the string, looking for the first '=' there, and its size */ 53 | do { 54 | if (str[pos] == '\0') 55 | break; 56 | if (str[pos] == '=' && first_equal_pos < 0) 57 | first_equal_pos = pos; 58 | pos++; 59 | } while (pos < MAX_ENV_LEN); 60 | 61 | if (pos >= MAX_ENV_LEN) /* Too large */ 62 | return 0; 63 | 64 | if (first_equal_pos < 1) /* No equal sign, or it is the first character */ 65 | return 0; 66 | 67 | return 1; 68 | } 69 | 70 | unsigned* 71 | apkenv_linker_env_init(unsigned* vecs) 72 | { 73 | /* Store environment pointer - can't be NULL */ 74 | apkenv__envp = (char**) vecs; 75 | 76 | /* Skip over all definitions */ 77 | while (vecs[0] != 0) 78 | vecs++; 79 | /* The end of the environment block is marked by two NULL pointers */ 80 | vecs++; 81 | 82 | /* As a sanity check, we're going to remove all invalid variable 83 | * definitions from the environment array. 84 | */ 85 | { 86 | char** readp = apkenv__envp; 87 | char** writep = apkenv__envp; 88 | for ( ; readp[0] != NULL; readp++ ) { 89 | if (!apkenv__is_valid_definition(readp[0])) 90 | continue; 91 | writep[0] = readp[0]; 92 | writep++; 93 | } 94 | writep[0] = NULL; 95 | } 96 | 97 | /* Return the address of the aux vectors table */ 98 | return vecs; 99 | } 100 | 101 | /* Check if the environment variable definition at 'envstr' 102 | * starts with '=', and if so return the address of the 103 | * first character after the equal sign. Otherwise return NULL. 104 | */ 105 | static char* 106 | apkenv_env_match(char* envstr, const char* name) 107 | { 108 | size_t cnt = 0; 109 | 110 | while (envstr[cnt] == name[cnt] && name[cnt] != '\0') 111 | cnt++; 112 | 113 | if (name[cnt] == '\0' && envstr[cnt] == '=') 114 | return envstr + cnt + 1; 115 | 116 | return NULL; 117 | } 118 | 119 | #define MAX_ENV_LEN (16*4096) 120 | 121 | const char* 122 | apkenv_linker_env_get(const char* name) 123 | { 124 | char** readp = apkenv__envp; 125 | 126 | if (name == NULL || name[0] == '\0') 127 | return NULL; 128 | 129 | for ( ; readp[0] != NULL; readp++ ) { 130 | char* val = apkenv_env_match(readp[0], name); 131 | if (val != NULL) { 132 | /* Return NULL for empty strings, or if it is too large */ 133 | if (val[0] == '\0') 134 | val = NULL; 135 | return val; 136 | } 137 | } 138 | return NULL; 139 | } 140 | 141 | 142 | void 143 | apkenv_linker_env_unset(const char* name) 144 | { 145 | char** readp = apkenv__envp; 146 | char** writep = readp; 147 | 148 | if (name == NULL || name[0] == '\0') 149 | return; 150 | 151 | for ( ; readp[0] != NULL; readp++ ) { 152 | if (apkenv_env_match(readp[0], name)) 153 | continue; 154 | writep[0] = readp[0]; 155 | writep++; 156 | } 157 | /* end list with a NULL */ 158 | writep[0] = NULL; 159 | } 160 | 161 | 162 | 163 | /* Remove unsafe environment variables. This should be used when 164 | * running setuid programs. */ 165 | void 166 | apkenv_linker_env_secure(void) 167 | { 168 | /* The same list than GLibc at this point */ 169 | static const char* const unsec_vars[] = { 170 | "GCONV_PATH", 171 | "GETCONF_DIR", 172 | "HOSTALIASES", 173 | "LD_AUDIT", 174 | "LD_DEBUG", 175 | "LD_DEBUG_OUTPUT", 176 | "LD_DYNAMIC_WEAK", 177 | "LD_LIBRARY_PATH", 178 | "LD_ORIGIN_PATH", 179 | "LD_PRELOAD", 180 | "LD_PROFILE", 181 | "LD_SHOW_AUXV", 182 | "LD_USE_LOAD_BIAS", 183 | "LOCALDOMAIN", 184 | "LOCPATH", 185 | "MALLOC_TRACE", 186 | "MALLOC_CHECK_", 187 | "NIS_PATH", 188 | "NLSPATH", 189 | "RESOLV_HOST_CONF", 190 | "RES_OPTIONS", 191 | "TMPDIR", 192 | "TZDIR", 193 | "LD_AOUT_LIBRARY_PATH", 194 | "LD_AOUT_PRELOAD", 195 | }; 196 | 197 | const char* const* cp = unsec_vars; 198 | const char* const* endp = cp + sizeof(unsec_vars)/sizeof(unsec_vars[0]); 199 | 200 | while (cp < endp) { 201 | apkenv_linker_env_unset(*cp); 202 | cp++; 203 | } 204 | } 205 | -------------------------------------------------------------------------------- /src/linker/linker_environ.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 The Android Open Source Project 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in 12 | * the documentation and/or other materials provided with the 13 | * distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 | * SUCH DAMAGE. 27 | */ 28 | #ifndef LINKER_ENVIRON_H 29 | #define LINKER_ENVIRON_H 30 | 31 | /* Call this function before anything else. 'vecs' must be the pointer 32 | * to the environment block in the ELF data block. The function returns 33 | * the start of the aux vectors after the env block. 34 | */ 35 | extern unsigned* apkenv_linker_env_init(unsigned* vecs); 36 | 37 | /* Unset a given environment variable. In case the variable is defined 38 | * multiple times, unset all instances. This modifies the environment 39 | * block, so any pointer returned by linker_env_get() after this call 40 | * might become invalid */ 41 | extern void apkenv_linker_env_unset(const char* name); 42 | 43 | 44 | /* Returns the value of environment variable 'name' if defined and not 45 | * empty, or NULL otherwise. Note that the returned pointer may become 46 | * invalid if linker_env_unset() or linker_env_secure() are called 47 | * after this function. */ 48 | extern const char* apkenv_linker_env_get(const char* name); 49 | 50 | /* Remove unsecure environment variables. This should be used when 51 | * running setuid programs. */ 52 | extern void apkenv_linker_env_secure(void); 53 | 54 | #endif /* LINKER_ENVIRON_H */ 55 | -------------------------------------------------------------------------------- /src/linker/linker_format.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2010 The Android Open Source Project 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in 12 | * the documentation and/or other materials provided with the 13 | * distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 | * SUCH DAMAGE. 27 | */ 28 | #ifndef _LINKER_FORMAT_H 29 | #define _LINKER_FORMAT_H 30 | 31 | #include 32 | #include 33 | 34 | /* Formatting routines for the dynamic linker's debug traces */ 35 | /* We want to avoid dragging the whole C library fprintf() */ 36 | /* implementation into the dynamic linker since this creates */ 37 | /* issues (it uses malloc()/free()) and increases code size */ 38 | 39 | // apkenv: we can just use snprintf 40 | //int format_buffer(char *buffer, size_t bufsize, const char *format, ...); 41 | #define format_buffer snprintf 42 | 43 | #endif /* _LINKER_FORMAT_H */ 44 | -------------------------------------------------------------------------------- /src/linker/rt.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2008 The Android Open Source Project 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions 7 | * are met: 8 | * * Redistributions of source code must retain the above copyright 9 | * notice, this list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright 11 | * notice, this list of conditions and the following disclaimer in 12 | * the documentation and/or other materials provided with the 13 | * distribution. 14 | * 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 18 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 19 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 22 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 25 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 | * SUCH DAMAGE. 27 | */ 28 | 29 | /* 30 | * This function is an empty stub where GDB locates a breakpoint to get notified 31 | * about linker activity. 32 | */ 33 | void __attribute__((noinline)) apkenv_rtld_db_dlactivity(void) 34 | { 35 | } 36 | 37 | -------------------------------------------------------------------------------- /src/linker/strlcpy.c: -------------------------------------------------------------------------------- 1 | /* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */ 2 | 3 | /* 4 | * Copyright (c) 1998 Todd C. Miller 5 | * 6 | * Permission to use, copy, modify, and distribute this software for any 7 | * purpose with or without fee is hereby granted, provided that the above 8 | * copyright notice and this permission notice appear in all copies. 9 | * 10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 | */ 18 | 19 | #include "strlcpy.h" 20 | 21 | /* 22 | * Copy src to string dst of size siz. At most siz-1 characters 23 | * will be copied. Always NUL terminates (unless siz == 0). 24 | * Returns strlen(src); if retval >= siz, truncation occurred. 25 | */ 26 | size_t 27 | apkenv_strlcpy(char *dst, const char *src, size_t siz) 28 | { 29 | char *d = dst; 30 | const char *s = src; 31 | size_t n = siz; 32 | 33 | /* Copy as many bytes as will fit */ 34 | if (n != 0) { 35 | while (--n != 0) { 36 | if ((*d++ = *s++) == '\0') 37 | break; 38 | } 39 | } 40 | 41 | /* Not enough room in dst, add NUL and traverse rest of src */ 42 | if (n == 0) { 43 | if (siz != 0) 44 | *d = '\0'; /* NUL-terminate dst */ 45 | while (*s++) 46 | ; 47 | } 48 | 49 | return(s - src - 1); /* count does not include NUL */ 50 | } 51 | -------------------------------------------------------------------------------- /src/linker/strlcpy.h: -------------------------------------------------------------------------------- 1 | #ifndef STRLCPY_H 2 | #define STRLCPY_H 3 | 4 | #include 5 | #include 6 | 7 | size_t 8 | apkenv_strlcpy(char *dst, const char *src, size_t siz); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /src/loader.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "linker/dlfcn.h" 12 | #include "linker/linker.h" 13 | #include "jvm/jvm.h" 14 | #include 15 | 16 | static int 17 | run_jni_game(struct jvm *jvm) 18 | { 19 | // Works only with unity libs for now 20 | // XXX: What this basically is that, we port the Java bits to C 21 | // XXX: This will become unneccessary as we make dalvik interpreter 22 | 23 | struct { 24 | union { 25 | void *ptr; 26 | void (*fun)(JNIEnv*, jobject, jobject); 27 | } native_init_jni; 28 | 29 | union { 30 | void *ptr; 31 | void (*fun)(JNIEnv*, jobject); 32 | } native_done; 33 | 34 | union { 35 | void *ptr; 36 | void (*fun)(JNIEnv*, jobject, jstring); 37 | } native_file; 38 | 39 | union { 40 | void *ptr; 41 | jboolean (*fun)(JNIEnv*, jobject); 42 | } native_pause; 43 | 44 | union { 45 | void *ptr; 46 | void (*fun)(JNIEnv*, jobject, jint, jobject); 47 | } native_recreate_gfx_state; 48 | 49 | union { 50 | void *ptr; 51 | jboolean (*fun)(JNIEnv*, jobject); 52 | } native_render; 53 | 54 | union { 55 | void *ptr; 56 | void (*fun)(JNIEnv*, jobject); 57 | } native_resume; 58 | 59 | union { 60 | void *ptr; 61 | void (*fun)(JNIEnv*, jobject, jboolean); 62 | } native_focus_changed; 63 | 64 | union { 65 | void *ptr; 66 | void (*fun)(JNIEnv*, jobject, jstring); 67 | } native_set_input_string; 68 | 69 | union { 70 | void *ptr; 71 | void (*fun)(JNIEnv*, jobject); 72 | } native_soft_input_closed; 73 | 74 | union { 75 | void *ptr; 76 | void (*fun)(JNIEnv*, jobject, jboolean); 77 | } native_set_input_canceled; 78 | 79 | union { 80 | void *ptr; 81 | void (*fun)(JNIEnv*, jobject, jobject); 82 | } native_init_www; 83 | 84 | union { 85 | void *ptr; 86 | void (*fun)(JNIEnv*, jobject, jobject); 87 | } native_init_web_request; 88 | 89 | union { 90 | void *ptr; 91 | void (*fun)(JNIEnv*, jobject, jlong); 92 | } native_add_vsync_time; 93 | 94 | union { 95 | void *ptr; 96 | void (*fun)(JNIEnv*, jobject, jboolean); 97 | } native_forward_events_to_dalvik; 98 | 99 | union { 100 | void *ptr; 101 | void (*fun)(JNIEnv*, jobject, jobject); 102 | } native_inject_event; 103 | } unity; 104 | 105 | static const char *unity_player_class = "com.unity3d.player.UnityPlayer"; 106 | unity.native_init_jni.ptr = jvm_get_native_method(jvm, unity_player_class, "initJni"); 107 | unity.native_done.ptr = jvm_get_native_method(jvm, unity_player_class, "nativeDone"); 108 | unity.native_file.ptr = jvm_get_native_method(jvm, unity_player_class, "nativeFile"); 109 | unity.native_pause.ptr = jvm_get_native_method(jvm, unity_player_class, "nativePause"); 110 | unity.native_recreate_gfx_state.ptr = jvm_get_native_method(jvm, unity_player_class, "nativeRecreateGfxState"); 111 | unity.native_render.ptr = jvm_get_native_method(jvm, unity_player_class, "nativeRender"); 112 | unity.native_resume.ptr = jvm_get_native_method(jvm, unity_player_class, "nativeResume"); 113 | unity.native_focus_changed.ptr = jvm_get_native_method(jvm, unity_player_class, "nativeFocusChanged"); 114 | unity.native_set_input_string.ptr = jvm_get_native_method(jvm, unity_player_class, "nativeSetInputString"); 115 | unity.native_soft_input_closed.ptr = jvm_get_native_method(jvm, unity_player_class, "nativeSoftInputClosed"); 116 | unity.native_set_input_canceled.ptr = jvm_get_native_method(jvm, unity_player_class, "nativeSetInputCanceled"); 117 | unity.native_init_www.ptr = jvm_get_native_method(jvm, unity_player_class, "nativeInitWWW"); 118 | unity.native_init_web_request.ptr = jvm_get_native_method(jvm, unity_player_class, "nativeInitWebRequest"); 119 | unity.native_add_vsync_time.ptr = jvm_get_native_method(jvm, unity_player_class, "nativeAddVSyncTime"); 120 | unity.native_forward_events_to_dalvik.ptr = jvm_get_native_method(jvm, unity_player_class, "nativeForwardEventsToDalvik"); 121 | unity.native_inject_event.ptr = jvm_get_native_method(jvm, unity_player_class, "nativeInjectEvent"); 122 | 123 | if (!unity.native_init_jni.ptr || !unity.native_file.ptr) 124 | errx(EXIT_FAILURE, "not a unity jni lib"); 125 | 126 | const jobject context = jvm->native.AllocObject(&jvm->env, jvm->native.FindClass(&jvm->env, "android/app/Activity")); 127 | unity.native_init_jni.fun(&jvm->env, context, context); 128 | 129 | unity.native_file.fun(&jvm->env, context, jvm->env->NewStringUTF(&jvm->env, getenv("ANDROID_PACKAGE_CODE_PATH"))); 130 | 131 | { 132 | DIR *dir; 133 | const char *obb_dir = getenv("ANDROID_EXTERNAL_OBB_DIR"); 134 | if (obb_dir && (dir = opendir(obb_dir))) { 135 | for (struct dirent *d; (d = readdir(dir));) { 136 | if (!strcmp(d->d_name, ".") || !strcmp(d->d_name, "..")) 137 | continue; 138 | 139 | char path[4096]; 140 | snprintf(path, sizeof(path), "%s/%s", obb_dir, d->d_name); 141 | unity.native_file.fun(&jvm->env, context, jvm->env->NewStringUTF(&jvm->env, path)); 142 | } 143 | } 144 | } 145 | 146 | // unity.native_forward_events_to_dalvik.fun(&jvm->env, context, true); 147 | unity.native_init_www.fun(&jvm->env, context, jvm->env->FindClass(&jvm->env, "com/unity3d/player/WWW")); 148 | unity.native_init_web_request.fun(&jvm->env, context, jvm->env->FindClass(&jvm->env, "com/unity3d/player/UnityWebRequest")); 149 | unity.native_recreate_gfx_state.fun(&jvm->env, context, 0, context); 150 | unity.native_focus_changed.fun(&jvm->env, context, true); 151 | unity.native_resume.fun(&jvm->env, context); 152 | unity.native_done.fun(&jvm->env, context); 153 | // unity.native_add_vsync_time.fun(&jvm->env, context, 0); 154 | 155 | while (unity.native_render.fun(&jvm->env, context)) { 156 | static int i = 0; 157 | if (++i >= 10) { 158 | unity.native_inject_event.fun(&jvm->env, context, jvm->native.AllocObject(&jvm->env, jvm->native.FindClass(&jvm->env, "android/view/MotionEvent"))); 159 | i = 0; 160 | } 161 | } 162 | 163 | return EXIT_SUCCESS; 164 | } 165 | 166 | __attribute__((optimize(0))) static void 167 | raw_start(void *entry, int argc, const char *argv[]) 168 | { 169 | // XXX: make this part of the linker when it's rewritten 170 | #if ANDROID_X86_LINKER 171 | __asm__("mov 2*4(%ebp),%eax"); /* entry */ 172 | __asm__("mov 3*4(%ebp),%ecx"); /* argc */ 173 | __asm__("mov 4*4(%ebp),%edx"); /* argv */ 174 | __asm__("mov %edx,%esp"); /* trim stack. */ 175 | __asm__("push %edx"); /* push argv */ 176 | __asm__("push %ecx"); /* push argc */ 177 | __asm__("sub %edx,%edx"); /* no rtld_fini function */ 178 | __asm__("jmp *%eax"); /* goto entry */ 179 | #else 180 | warnx("raw_start not implemented for this asm platform, can't execute binaries."); 181 | #endif 182 | } 183 | 184 | int 185 | main(int argc, const char *argv[]) 186 | { 187 | if (argc < 2) 188 | errx(EXIT_FAILURE, "usage: "); 189 | 190 | printf("loading module: %s\n", argv[1]); 191 | 192 | { 193 | // FIXME: should point to apk's libdir 194 | char abs[PATH_MAX], paths[4096]; 195 | realpath(argv[1], abs); 196 | snprintf(paths, sizeof(paths), "%s", dirname(abs)); 197 | dl_parse_library_path(paths, ":"); 198 | } 199 | 200 | void *handle; 201 | if (!(handle = bionic_dlopen(argv[1], RTLD_LOCAL | RTLD_NOW))) 202 | errx(EXIT_FAILURE, "dlopen failed: %s", bionic_dlerror()); 203 | 204 | struct { 205 | union { 206 | void *ptr; 207 | jint (*fun)(void*, void*); 208 | } JNI_OnLoad; 209 | 210 | union { 211 | void *ptr; 212 | } start; 213 | } entry = {0}; 214 | 215 | { 216 | union { 217 | char bytes[sizeof(Elf32_Ehdr)]; 218 | Elf32_Ehdr hdr; 219 | } elf; 220 | 221 | FILE *f; 222 | if (!(f = fopen(argv[1], "rb"))) 223 | err(EXIT_FAILURE, "fopen(%s)", argv[1]); 224 | 225 | fread(elf.bytes, 1, sizeof(elf.bytes), f); 226 | fclose(f); 227 | 228 | struct soinfo *si = handle; 229 | if (elf.hdr.e_entry) 230 | entry.start.ptr = (void*)(intptr_t)(si->base + elf.hdr.e_entry); 231 | } 232 | 233 | int ret = EXIT_FAILURE; 234 | if (entry.start.ptr) { 235 | printf("jumping to %p\n", entry.start.ptr); 236 | raw_start(entry.start.ptr, argc - 1, &argv[1]); 237 | } else if ((entry.JNI_OnLoad.ptr = bionic_dlsym(handle, "JNI_OnLoad"))) { 238 | struct jvm jvm; 239 | jvm_init(&jvm); 240 | entry.JNI_OnLoad.fun(&jvm.vm, NULL); 241 | ret = run_jni_game(&jvm); 242 | jvm_release(&jvm); 243 | } else { 244 | warnx("no entrypoint found in %s", argv[1]); 245 | } 246 | 247 | printf("unloading module: %s\n", argv[1]); 248 | bionic_dlclose(handle); 249 | printf("exiting\n"); 250 | return ret; 251 | } 252 | -------------------------------------------------------------------------------- /src/wrapper/verbose.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void 4 | __attribute__((format(printf, 1, 2))) 5 | verbose_log(const char *fmt, ...); 6 | 7 | #ifdef VERBOSE_FUNCTIONS 8 | # define verbose verbose_log 9 | #else 10 | # define verbose(...) 11 | #endif 12 | -------------------------------------------------------------------------------- /src/wrapper/wrapper.c: -------------------------------------------------------------------------------- 1 | #include "wrapper.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "verbose.h" 12 | #include 13 | 14 | static __thread bool skip_trace; 15 | 16 | void 17 | verbose_log(const char *fmt, ...) 18 | { 19 | if (skip_trace) 20 | return; 21 | 22 | static pthread_mutex_t mutex = PTHREAD_MUTEX_INITIALIZER; 23 | pthread_mutex_lock(&mutex); 24 | va_list ap; 25 | va_start(ap, fmt); 26 | static char buf[1024]; 27 | vsnprintf(buf, sizeof(buf), fmt, ap); 28 | va_end(ap); 29 | fprintf(stderr, "%lu: %s\n", pthread_self(), buf); 30 | pthread_mutex_unlock(&mutex); 31 | } 32 | 33 | #ifdef VERBOSE_FUNCTIONS 34 | # ifdef ANDROID_X86_LINKER 35 | __asm__( 36 | "wrapper_start: nop\n" 37 | "wrapper_store: push %edi\npush %esp\npush %ebp\npush %ebx\npush %eax\npush %ecx\npush %edx\n" 38 | "wrapper_symbol: pushl $0xFAFBFCFD\n" // arg1 for trace 39 | "wrapper_trace: .byte 0xE8, 0xFA, 0xFB, 0xFC, 0xFD\n" // CALL (trace) 40 | "wrapper_restore: pop %eax\npop %edx\npop %ecx\npop %eax\npop %ebx\npop %ebp\npop %esp\npop %edi\n" 41 | "wrapper_jmp: .byte 0xE9, 0xFA, 0xFB, 0xFC, 0xFD\n" // JMP 42 | "wrapper_ud: .byte 0x0F, 0xFF\n" // UD 43 | "wrapper_end: nop\n" 44 | ); 45 | # define WRAPPER_TRACE 46 | # else 47 | # warning "no wrapper asm for this platform, function tracing is not available" 48 | # endif 49 | #endif 50 | 51 | #ifdef WRAPPER_TRACE 52 | extern unsigned char wrapper_start, wrapper_symbol, wrapper_trace, wrapper_restore, wrapper_jmp, wrapper_ud, wrapper_end; 53 | 54 | static union { 55 | void *ptr; 56 | char* (*fun)(const char *mangled_name, char *output_buffer, size_t *length, int *status); 57 | } __cxa_demangle; 58 | 59 | static void 60 | trace(const char *const symbol) 61 | { 62 | assert(symbol); 63 | 64 | if (__cxa_demangle.ptr) { 65 | // >If output_buffer is not long enough, it is expanded using realloc 66 | // Holy fuck gcc what the fuck? Guess we don't use stack then, thanks 67 | int status; 68 | char *demangled; 69 | static __thread char *data; 70 | static __thread size_t size; 71 | 72 | // Avoid infinite recursion and tracing calls made by __cxa_demangle.fun 73 | if (skip_trace) 74 | return; 75 | 76 | skip_trace = true; 77 | demangled = __cxa_demangle.fun(symbol, data, &size, &status); 78 | skip_trace = false; 79 | 80 | if (demangled) { 81 | data = (data != demangled ? demangled : data); 82 | verbose("trace: %s", demangled); 83 | return; 84 | } 85 | } 86 | 87 | verbose("trace: %s", symbol); 88 | } 89 | #endif 90 | 91 | void 92 | wrapper_set_cpp_demangler(void *function) 93 | { 94 | #ifdef WRAPPER_TRACE 95 | __cxa_demangle.ptr = function; 96 | verbose_log("wrapper: set cpp_demangler to %p", function); 97 | #endif 98 | } 99 | 100 | void* 101 | wrapper_create(const char *const symbol, void *function) 102 | { 103 | assert(symbol); 104 | 105 | if (!function) { 106 | verbose_log("FIXME: unimplemented symbol: %s", symbol); 107 | return NULL; 108 | } 109 | 110 | #ifdef WRAPPER_TRACE 111 | static const union { 112 | void *ptr; 113 | void (*fun)(const char*); 114 | } tracefun = { .fun = trace }; 115 | 116 | const size_t len = strlen(symbol) + 1; 117 | char *copy = malloc(len); 118 | assert(copy && "welp, malloc failed"); 119 | memcpy(copy, symbol, len); 120 | const size_t sz = &wrapper_end - &wrapper_start; 121 | unsigned char *fun = mmap(NULL, sz, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0); 122 | assert(fun != MAP_FAILED); 123 | memcpy(fun, &wrapper_start, sz); 124 | #ifdef ANDROID_X86_LINKER 125 | memcpy(fun + (&wrapper_symbol - &wrapper_start) + 1, ©, sizeof(copy)); 126 | { 127 | const unsigned char *from = fun + (&wrapper_restore - &wrapper_start); 128 | const intptr_t to = (unsigned char*)tracefun.ptr - from; 129 | memcpy(fun + (&wrapper_trace - &wrapper_start) + 1, &to, sizeof(to)); 130 | }{ 131 | const unsigned char *from = fun + (&wrapper_ud - &wrapper_start); 132 | const intptr_t to = (unsigned char*)function - from; 133 | memcpy(fun + (&wrapper_jmp - &wrapper_start) + 1, &to, sizeof(to)); 134 | } 135 | #else 136 | # error "you forgot to implement the pointer setups for your asm platform" 137 | #endif 138 | mprotect(fun, sz, PROT_READ | PROT_EXEC); 139 | return fun; 140 | #else 141 | return function; 142 | #endif 143 | } 144 | -------------------------------------------------------------------------------- /src/wrapper/wrapper.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | void* 4 | wrapper_create(const char *const symbol, void *function); 5 | 6 | void 7 | wrapper_set_cpp_demangler(void *function); 8 | --------------------------------------------------------------------------------