remove byopen
This commit is contained in:
parent
1f40a9d0ab
commit
9a371b5ed1
|
@ -27,17 +27,9 @@ LOCAL_CONLYFLAGS := -std=c11
|
|||
LOCAL_LDLIBS := -llog
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := byopen
|
||||
LOCAL_SRC_FILES := byopen/byopen_android.c
|
||||
LOCAL_C_INCLUDES := $(LOCAL_PATH)/byopen
|
||||
LOCAL_CFLAGS := -Wall
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := fcl
|
||||
LOCAL_SHARED_LIBRARIES := xhook \
|
||||
byopen
|
||||
LOCAL_SHARED_LIBRARIES := xhook
|
||||
LOCAL_SRC_FILES := fcl/fcl_bridge.c \
|
||||
fcl/fcl_event.c \
|
||||
fcl/fcl_loader.c
|
||||
|
@ -48,8 +40,7 @@ include $(BUILD_SHARED_LIBRARY)
|
|||
|
||||
include $(CLEAR_VARS)
|
||||
LOCAL_MODULE := glfw
|
||||
LOCAL_SHARED_LIBRARIES := fcl \
|
||||
byopen
|
||||
LOCAL_SHARED_LIBRARIES := fcl
|
||||
LOCAL_SRC_FILES := glfw/context.c \
|
||||
glfw/init.c \
|
||||
glfw/input.c \
|
||||
|
@ -332,8 +323,7 @@ LOCAL_MODULE := lwjgl
|
|||
LOCAL_STATIC_LIBRARIES := dyncall \
|
||||
dyncallback \
|
||||
dynload
|
||||
LOCAL_SHARED_LIBRARIES := byopen \
|
||||
fcl
|
||||
LOCAL_SHARED_LIBRARIES := fcl
|
||||
LOCAL_SRC_FILES := lwjgl3/fcl_hook.c \
|
||||
lwjgl3/common_tools.c \
|
||||
lwjgl3/org_lwjgl_opengl_AMDDebugOutput.c \
|
||||
|
|
|
@ -1,78 +0,0 @@
|
|||
/*!A dlopen library that bypasses mobile system limitation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (C) 2020-present, TBOOX Open Source Group.
|
||||
*
|
||||
* @author ruki
|
||||
* @file byopen.h
|
||||
*
|
||||
*/
|
||||
#ifndef BY_BYOPEN_H
|
||||
#define BY_BYOPEN_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////////////////////
|
||||
* includes
|
||||
*/
|
||||
#include "prefix.h"
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////////////////////
|
||||
* types
|
||||
*/
|
||||
|
||||
/// the dlopen flag enum
|
||||
typedef enum __by_dlopen_flag_e
|
||||
{
|
||||
BY_RTLD_LAZY = 1
|
||||
, BY_RTLD_NOW = 2
|
||||
|
||||
}by_dlopen_flag_e;
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////////////////////
|
||||
* interfaces
|
||||
*/
|
||||
|
||||
/*! The function dlopen() loads the dynamic library and returns an opaque "handle".
|
||||
*
|
||||
* @param filename the dynamic library file named by the null-terminated string filename
|
||||
* @param flag the load flag
|
||||
*
|
||||
* @return the dynamic library handle
|
||||
*/
|
||||
by_pointer_t by_dlopen(by_char_t const* filename, by_int_t flag);
|
||||
|
||||
/*! get the address where that symbol is loaded into memory
|
||||
*
|
||||
* @param handle the dynamic library handle
|
||||
*
|
||||
* @return the symbol address
|
||||
*/
|
||||
by_pointer_t by_dlsym(by_pointer_t handle, by_char_t const* symbol);
|
||||
|
||||
/*! It decrements the reference count on the dynamic library handle handle.
|
||||
* If the reference count drops to zero and no other loaded libraries use symbols in it, then the dynamic library is unloaded.
|
||||
*
|
||||
* @param handle the dynamic library handle
|
||||
*
|
||||
* @return 0 on success, and nonzero on error
|
||||
*/
|
||||
by_int_t by_dlclose(by_pointer_t handle);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -1,935 +0,0 @@
|
|||
/*!A dlopen library that bypasses mobile system limitation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (C) 2020-present, TBOOX Open Source Group.
|
||||
*
|
||||
* @author ruki
|
||||
* @file byopen_android.c
|
||||
*
|
||||
*/
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////////////////////
|
||||
* includes
|
||||
*/
|
||||
#include "byopen.h"
|
||||
#include <dlfcn.h>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <inttypes.h>
|
||||
#include <elf.h>
|
||||
#include <link.h>
|
||||
#include <pthread.h>
|
||||
#include <sys/system_properties.h>
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////////////////////
|
||||
* macros
|
||||
*/
|
||||
|
||||
// the fake dlopen magic
|
||||
#define BY_FAKE_DLCTX_MAGIC (0xfaddfadd)
|
||||
|
||||
/* g_dl_mutex in linker
|
||||
*
|
||||
* @see http://androidxref.com/5.0.0_r2/xref/bionic/linker/dlfcn.cpp#32
|
||||
*/
|
||||
#define BY_LINKER_MUTEX "__dl__ZL10g_dl_mutex"
|
||||
|
||||
// the linker name
|
||||
#ifndef __LP64__
|
||||
# define BY_LINKER_NAME "linker"
|
||||
#else
|
||||
# define BY_LINKER_NAME "linker64"
|
||||
#endif
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////////////////////
|
||||
* types
|
||||
*/
|
||||
|
||||
// the dynamic library context type for fake dlopen
|
||||
typedef struct _by_fake_dlctx_t
|
||||
{
|
||||
// magic, mark handle for fake dlopen
|
||||
by_uint32_t magic;
|
||||
|
||||
// the load bias address of the dynamic library
|
||||
by_pointer_t biasaddr;
|
||||
|
||||
// the .dynsym and .dynstr sections
|
||||
by_pointer_t dynstr;
|
||||
by_pointer_t dynsym;
|
||||
by_int_t dynsym_num;
|
||||
|
||||
// the .symtab and .strtab sections
|
||||
by_pointer_t strtab;
|
||||
by_pointer_t symtab;
|
||||
by_int_t symtab_num;
|
||||
|
||||
// the file data and size
|
||||
by_pointer_t filedata;
|
||||
by_size_t filesize;
|
||||
|
||||
}by_fake_dlctx_t, *by_fake_dlctx_ref_t;
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////////////////////
|
||||
* globals
|
||||
*/
|
||||
|
||||
// the jni environment on tls
|
||||
__thread JNIEnv* g_tls_jnienv = by_null;
|
||||
static JavaVM* g_jvm = by_null;
|
||||
static by_int_t g_jversion = JNI_VERSION_1_4;
|
||||
static pthread_mutex_t* g_linker_mutex = by_null;
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////////////////////
|
||||
* declaration
|
||||
*/
|
||||
extern __attribute((weak)) by_int_t dl_iterate_phdr(by_int_t (*)(struct dl_phdr_info*, size_t, by_pointer_t), by_pointer_t);
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////////////////////
|
||||
* declaration
|
||||
*/
|
||||
|
||||
// weak symbol import
|
||||
by_void_t __system_property_read_callback(
|
||||
prop_info const* info,
|
||||
by_void_t (*callback)(by_pointer_t cookie, by_char_t const* name, by_char_t const* value, uint32_t serial),
|
||||
by_void_t* cookie) __attribute__((weak));
|
||||
|
||||
by_int_t __system_property_get(by_char_t const* name, by_char_t* value) __attribute__((weak));
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////////////////////
|
||||
* private implementation
|
||||
*/
|
||||
|
||||
/* Technical note regarding reading system properties.
|
||||
*
|
||||
* Try to use the new __system_property_read_callback API that appeared in
|
||||
* Android O / API level 26 when available. Otherwise use the deprecated
|
||||
* __system_property_get function.
|
||||
*
|
||||
* For more technical details from an NDK maintainer, see:
|
||||
* https://bugs.chromium.org/p/chromium/issues/detail?id=392191#c17
|
||||
*/
|
||||
|
||||
// callback used with __system_property_read_callback.
|
||||
static by_void_t by_rt_prop_read_int(by_pointer_t cookie, by_char_t const* name, by_char_t const* value, uint32_t serial)
|
||||
{
|
||||
*(by_int_t *)cookie = atoi(value);
|
||||
(by_void_t)name;
|
||||
(by_void_t)serial;
|
||||
}
|
||||
|
||||
// read process output
|
||||
static by_int_t by_rt_process_read(by_char_t const* cmd, by_char_t* data, by_size_t maxn)
|
||||
{
|
||||
by_int_t n = 0;
|
||||
FILE* p = popen(cmd, "r");
|
||||
if (p)
|
||||
{
|
||||
by_char_t buf[256] = {0};
|
||||
by_char_t* pos = data;
|
||||
by_char_t* end = data + maxn;
|
||||
while (!feof(p))
|
||||
{
|
||||
if (fgets(buf, sizeof(buf), p))
|
||||
{
|
||||
by_int_t len = strlen(buf);
|
||||
if (pos + len < end)
|
||||
{
|
||||
memcpy(pos, buf, len);
|
||||
pos += len;
|
||||
n += len;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*pos = '\0';
|
||||
pclose(p);
|
||||
}
|
||||
return n;
|
||||
}
|
||||
|
||||
// get system property integer
|
||||
static by_int_t by_rt_system_property_get_int(by_char_t const* name)
|
||||
{
|
||||
// check
|
||||
by_assert_and_check_return_val(name, -1);
|
||||
|
||||
by_int_t result = 0;
|
||||
if (__system_property_read_callback)
|
||||
{
|
||||
struct prop_info const* info = __system_property_find(name);
|
||||
if (info) __system_property_read_callback(info, &by_rt_prop_read_int, &result);
|
||||
}
|
||||
else if (__system_property_get)
|
||||
{
|
||||
by_char_t value[PROP_VALUE_MAX] = {0};
|
||||
if (__system_property_get(name, value) >= 1)
|
||||
result = atoi(value);
|
||||
}
|
||||
else
|
||||
{
|
||||
by_char_t cmd[256];
|
||||
by_char_t value[PROP_VALUE_MAX];
|
||||
snprintf(cmd, sizeof(cmd), "getprop %s", name);
|
||||
if (by_rt_process_read(cmd, value, sizeof(value)) > 1)
|
||||
result = atoi(value);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static by_int_t by_rt_api_level()
|
||||
{
|
||||
static by_int_t s_api_level = -1;
|
||||
if (s_api_level < 0)
|
||||
s_api_level = by_rt_system_property_get_int("ro.build.version.sdk");
|
||||
return s_api_level;
|
||||
}
|
||||
|
||||
// find the load bias address from the base address
|
||||
static by_pointer_t by_fake_find_biasaddr_from_baseaddr(by_pointer_t baseaddr)
|
||||
{
|
||||
// check
|
||||
by_assert_and_check_return_val(baseaddr, by_null);
|
||||
|
||||
// find load bias from program header
|
||||
ElfW(Ehdr)* ehdr = (ElfW(Ehdr)*)baseaddr;
|
||||
ElfW(Phdr) const* dlpi_phdr = (ElfW(Phdr) const*)(baseaddr + ehdr->e_phoff);
|
||||
by_int_t dlpi_phnum = ehdr->e_phnum;
|
||||
uintptr_t min_vaddr = UINTPTR_MAX;
|
||||
for (by_int_t i = 0; i < dlpi_phnum; i++)
|
||||
{
|
||||
ElfW(Phdr) const* phdr = &(dlpi_phdr[i]);
|
||||
if (PT_LOAD == phdr->p_type)
|
||||
{
|
||||
if (min_vaddr > phdr->p_vaddr)
|
||||
min_vaddr = phdr->p_vaddr;
|
||||
}
|
||||
}
|
||||
return min_vaddr != UINTPTR_MAX? baseaddr - min_vaddr : by_null;
|
||||
}
|
||||
|
||||
// find the load bias address and real path from the maps
|
||||
static by_pointer_t by_fake_find_biasaddr_from_maps(by_char_t const* filename, by_char_t* realpath, by_size_t realmaxn)
|
||||
{
|
||||
// check
|
||||
by_assert_and_check_return_val(filename && realpath && realmaxn, by_null);
|
||||
|
||||
// trace
|
||||
by_trace("find biasaddr of %s from maps", filename);
|
||||
|
||||
// find it
|
||||
by_char_t line[512];
|
||||
by_char_t page_attr[10];
|
||||
by_pointer_t biasaddr = by_null;
|
||||
FILE* fp = fopen("/proc/self/maps", "r");
|
||||
if (fp)
|
||||
{
|
||||
while (fgets(line, sizeof(line), fp))
|
||||
{
|
||||
if (strstr(line, filename))
|
||||
{
|
||||
int pos = 0;
|
||||
uintptr_t start = 0;
|
||||
uintptr_t offset = 0;
|
||||
// 7372a68000-7372bc1000 --xp 000fe000 fd:06 39690571 /system/lib64/libandroid_runtime.so
|
||||
if (3 == sscanf(line, "%"SCNxPTR"-%*"SCNxPTR" %4s %"SCNxPTR" %*x:%*x %*d%n", &start, page_attr, &offset, &pos))
|
||||
{
|
||||
// check permission and offset
|
||||
if (page_attr[0] != 'r') continue;
|
||||
if (page_attr[3] != 'p') continue;
|
||||
if (0 != offset) continue;
|
||||
|
||||
// get load bias address
|
||||
biasaddr = by_fake_find_biasaddr_from_baseaddr((by_pointer_t)start);
|
||||
|
||||
// get real path
|
||||
if (filename[0] == '/')
|
||||
strlcpy(realpath, filename, realmaxn);
|
||||
else if (pos < sizeof(line))
|
||||
{
|
||||
by_char_t* p = line + pos;
|
||||
by_char_t* e = p + strlen(p);
|
||||
while (p < e && isspace((by_int_t)*p)) p++;
|
||||
while (p < e && isspace((by_int_t)(*(e - 1)))) e--;
|
||||
*e = '\0';
|
||||
if (p < e) strlcpy(realpath, p, realmaxn);
|
||||
else realpath[0] = '\0';
|
||||
}
|
||||
else realpath[0] = '\0';
|
||||
|
||||
// trace
|
||||
by_trace("realpath: %s, biasaddr: %p found!", realpath, biasaddr);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
fclose(fp);
|
||||
}
|
||||
return biasaddr;
|
||||
}
|
||||
|
||||
// the callback of dl_iterate_phdr()
|
||||
static by_int_t by_fake_find_biasaddr_from_linker_cb(struct dl_phdr_info* info, size_t size, by_pointer_t udata)
|
||||
{
|
||||
// check
|
||||
by_cpointer_t* args = (by_cpointer_t*)udata;
|
||||
by_check_return_val(args, 1);
|
||||
by_check_return_val(info && info->dlpi_addr && info->dlpi_name && info->dlpi_name[0] != '\0', 0);
|
||||
|
||||
// get filename
|
||||
by_char_t const* filename = by_null;
|
||||
by_char_t const* filepath = (by_char_t const*)args[0];
|
||||
by_assert_and_check_return_val(filepath, 1);
|
||||
if (filepath[0] == '/')
|
||||
{
|
||||
by_char_t const* p = filepath + strlen(filepath);
|
||||
while (p >= filepath && *p != '/')
|
||||
p--;
|
||||
if (p >= filepath && *p == '/') filename = p + 1;
|
||||
}
|
||||
|
||||
// find library, we can also get full path of dlpi_name from maps
|
||||
by_pointer_t* pbiasaddr = (by_pointer_t*)&args[3];
|
||||
by_char_t* realpath = (by_char_t*)args[1];
|
||||
by_size_t realmaxn = (by_size_t)args[2];
|
||||
if ((filepath && strstr(info->dlpi_name, filepath)) ||
|
||||
(filename && !strcmp(info->dlpi_name, filename))) // dlpi_name ma ybe not full path, e.g. libart.so
|
||||
{
|
||||
// save load bias address
|
||||
*pbiasaddr = (by_pointer_t)info->dlpi_addr;
|
||||
|
||||
// get real path
|
||||
if (filepath[0] == '/')
|
||||
strlcpy(realpath, filepath, realmaxn);
|
||||
else if (info->dlpi_name[0] == '/')
|
||||
strlcpy(realpath, info->dlpi_name, realmaxn);
|
||||
else
|
||||
{
|
||||
// we only find real path
|
||||
if (!by_fake_find_biasaddr_from_maps(filepath, realpath, realmaxn))
|
||||
realpath[0] = '\0';
|
||||
}
|
||||
|
||||
// trace
|
||||
by_trace("realpath: %s, biasaddr: %p found!", realpath, (by_pointer_t)info->dlpi_addr);
|
||||
|
||||
// found, stop it
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
// find the load bias address and real path from the maps
|
||||
static by_pointer_t by_fake_find_biasaddr_from_linker(by_char_t const* filepath, by_char_t* realpath, by_size_t realmaxn)
|
||||
{
|
||||
// check
|
||||
by_assert_and_check_return_val(dl_iterate_phdr && filepath && realpath && realmaxn, by_null);
|
||||
|
||||
// trace
|
||||
by_trace("find biasaddr of %s from linker", filepath);
|
||||
|
||||
// find biasaddr
|
||||
by_cpointer_t args[4];
|
||||
args[0] = (by_cpointer_t)filepath;
|
||||
args[1] = (by_cpointer_t)realpath;
|
||||
args[2] = (by_cpointer_t)realmaxn;
|
||||
args[3] = by_null;
|
||||
if (g_linker_mutex) pthread_mutex_lock(g_linker_mutex);
|
||||
dl_iterate_phdr(by_fake_find_biasaddr_from_linker_cb, args);
|
||||
if (g_linker_mutex) pthread_mutex_unlock(g_linker_mutex);
|
||||
return (by_pointer_t)args[3];
|
||||
}
|
||||
|
||||
// find the load bias address and real path
|
||||
static by_pointer_t by_fake_find_biasaddr(by_char_t const* filename, by_char_t* realpath, by_size_t realmaxn)
|
||||
{
|
||||
by_assert_and_check_return_val(filename && realpath, by_null);
|
||||
by_pointer_t biasaddr = by_null;
|
||||
if (dl_iterate_phdr && 0 != strcmp(filename, BY_LINKER_NAME))
|
||||
biasaddr = by_fake_find_biasaddr_from_linker(filename, realpath, realmaxn);
|
||||
if (!biasaddr)
|
||||
biasaddr = by_fake_find_biasaddr_from_maps(filename, realpath, realmaxn);
|
||||
return biasaddr;
|
||||
}
|
||||
|
||||
// open map file
|
||||
static by_pointer_t by_fake_open_file(by_char_t const* filepath, by_size_t* pfilesize)
|
||||
{
|
||||
// check
|
||||
by_assert_and_check_return_val(filepath && pfilesize, by_null);
|
||||
|
||||
// open it
|
||||
by_int_t fd = -1;
|
||||
by_pointer_t filedata = by_null;
|
||||
do
|
||||
{
|
||||
// open file
|
||||
fd = open(filepath, O_RDONLY | O_CLOEXEC);
|
||||
if (fd < 0 && errno == EINTR)
|
||||
fd = open(filepath, O_RDONLY | O_CLOEXEC);
|
||||
by_check_break(fd > 0);
|
||||
|
||||
// get file size
|
||||
struct stat st;
|
||||
if (0 != fstat(fd, &st) || 0 == st.st_size) break;
|
||||
|
||||
// mmap the file data
|
||||
filedata = mmap(by_null, st.st_size, PROT_READ, MAP_PRIVATE, fd, 0);
|
||||
by_assert_and_check_break(filedata && filedata != MAP_FAILED);
|
||||
|
||||
// save the file size
|
||||
if (pfilesize) *pfilesize = (by_size_t)st.st_size;
|
||||
|
||||
} while (0);
|
||||
|
||||
// close the fd first
|
||||
if (fd > 0) close(fd);
|
||||
fd = -1;
|
||||
|
||||
// ok?
|
||||
return filedata;
|
||||
}
|
||||
|
||||
// get symbol address from the fake dlopen context
|
||||
static by_pointer_t by_fake_dlsym(by_fake_dlctx_ref_t dlctx, by_char_t const* symbol)
|
||||
{
|
||||
// check
|
||||
by_assert_and_check_return_val(dlctx && dlctx->filedata && dlctx->filesize && symbol, by_null);
|
||||
|
||||
// find the symbol address from the .dynsym first
|
||||
by_int_t i = 0;
|
||||
by_pointer_t end = dlctx->filedata + dlctx->filesize;
|
||||
by_char_t const* dynstr = (by_char_t const*)dlctx->dynstr;
|
||||
ElfW(Sym)* dynsym = (ElfW(Sym)*)dlctx->dynsym;
|
||||
by_int_t dynsym_num = dlctx->dynsym_num;
|
||||
if (dynsym && dynstr)
|
||||
{
|
||||
for (i = 0; i < dynsym_num; i++, dynsym++)
|
||||
{
|
||||
by_char_t const* name = dynstr + dynsym->st_name;
|
||||
if ((by_pointer_t)name < end && strcmp(name, symbol) == 0)
|
||||
{
|
||||
/* NB: sym->st_value is an offset into the section for relocatables,
|
||||
* but a VMA for shared libs or exe files, so we have to subtract the bias
|
||||
*/
|
||||
by_pointer_t symboladdr = (by_pointer_t)(dlctx->biasaddr + dynsym->st_value);
|
||||
by_trace("dlsym(%s): found at .dynsym/%p = %p + %x", symbol, symboladdr, dlctx->biasaddr, (by_int_t)dynsym->st_value);
|
||||
return symboladdr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// find the symbol address from the .symtab
|
||||
by_char_t const* strtab = (by_char_t const*)dlctx->strtab;
|
||||
ElfW(Sym)* symtab = (ElfW(Sym)*)dlctx->symtab;
|
||||
by_int_t symtab_num = dlctx->symtab_num;
|
||||
if (symtab && strtab)
|
||||
{
|
||||
for (i = 0; i < symtab_num; i++, symtab++)
|
||||
{
|
||||
by_char_t const* name = strtab + symtab->st_name;
|
||||
if ((by_pointer_t)name < end && strcmp(name, symbol) == 0)
|
||||
{
|
||||
by_pointer_t symboladdr = (by_pointer_t)(dlctx->biasaddr + symtab->st_value);
|
||||
by_trace("dlsym(%s): found at .symtab/%p = %p + %x", symbol, symboladdr, dlctx->biasaddr, (by_int_t)symtab->st_value);
|
||||
return symboladdr;
|
||||
}
|
||||
}
|
||||
}
|
||||
return by_null;
|
||||
}
|
||||
|
||||
// close the fake dlopen context
|
||||
static by_int_t by_fake_dlclose(by_fake_dlctx_ref_t dlctx)
|
||||
{
|
||||
// check
|
||||
by_assert_and_check_return_val(dlctx, -1);
|
||||
|
||||
// clear data
|
||||
dlctx->biasaddr = by_null;
|
||||
dlctx->dynsym = by_null;
|
||||
dlctx->dynstr = by_null;
|
||||
dlctx->dynsym_num = 0;
|
||||
dlctx->strtab = by_null;
|
||||
dlctx->symtab = by_null;
|
||||
dlctx->symtab_num = 0;
|
||||
|
||||
// unmap file data
|
||||
if (dlctx->filedata) munmap(dlctx->filedata, dlctx->filesize);
|
||||
dlctx->filedata = by_null;
|
||||
dlctx->filesize = 0;
|
||||
|
||||
// free context
|
||||
free(dlctx);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* @see https://www.sunmoonblog.com/2019/06/04/fake-dlopen/
|
||||
* https://github.com/avs333/Nougat_dlfunctions
|
||||
*/
|
||||
static by_fake_dlctx_ref_t by_fake_dlopen_impl(by_char_t const* filename, by_int_t flag)
|
||||
{
|
||||
// check
|
||||
by_assert_and_check_return_val(filename, by_null);
|
||||
|
||||
// do open
|
||||
by_bool_t ok = by_false;
|
||||
by_char_t realpath[512];
|
||||
by_fake_dlctx_ref_t dlctx = by_null;
|
||||
do
|
||||
{
|
||||
// attempt to find the load bias address and real path
|
||||
by_pointer_t biasaddr = by_fake_find_biasaddr(filename, realpath, sizeof(realpath));
|
||||
by_check_break(biasaddr);
|
||||
|
||||
// init context
|
||||
dlctx = calloc(1, sizeof(by_fake_dlctx_t));
|
||||
by_assert_and_check_break(dlctx);
|
||||
|
||||
dlctx->magic = BY_FAKE_DLCTX_MAGIC;
|
||||
dlctx->biasaddr = biasaddr;
|
||||
|
||||
// open file
|
||||
dlctx->filedata = by_fake_open_file(realpath, &dlctx->filesize);
|
||||
by_assert_and_check_break(dlctx->filedata && dlctx->filesize);
|
||||
|
||||
// trace
|
||||
by_trace("fake_dlopen: biasaddr: %p, realpath: %s, filesize: %d", biasaddr, realpath, (by_int_t)dlctx->filesize);
|
||||
|
||||
// get elf
|
||||
ElfW(Ehdr)* elf = (ElfW(Ehdr)*)dlctx->filedata;
|
||||
by_pointer_t end = dlctx->filedata + dlctx->filesize;
|
||||
by_assert_and_check_break((by_pointer_t)(elf + 1) < end);
|
||||
|
||||
// get .shstrtab section
|
||||
by_pointer_t shoff = dlctx->filedata + elf->e_shoff;
|
||||
ElfW(Shdr)* shstrtab = (ElfW(Shdr)*)(shoff + elf->e_shstrndx * elf->e_shentsize);
|
||||
by_assert_and_check_break((by_pointer_t)(shstrtab + 1) <= end);
|
||||
|
||||
by_pointer_t shstr = dlctx->filedata + shstrtab->sh_offset;
|
||||
by_assert_and_check_break(shstr < end);
|
||||
|
||||
// parse elf sections
|
||||
by_int_t i = 0;
|
||||
by_bool_t broken = by_false;
|
||||
for (i = 0; !broken && i < elf->e_shnum && shoff; i++, shoff += elf->e_shentsize)
|
||||
{
|
||||
// get section
|
||||
ElfW(Shdr)* sh = (ElfW(Shdr)*)shoff;
|
||||
by_assert_and_check_break((by_pointer_t)(sh + 1) <= end && shstr + sh->sh_name < end);
|
||||
by_assert_and_check_break(dlctx->filedata + sh->sh_offset < end);
|
||||
|
||||
// trace
|
||||
by_trace("elf section(%d): type: %d, name: %s", i, sh->sh_type, shstr + sh->sh_name);
|
||||
|
||||
// get .dynsym and .symtab sections
|
||||
switch(sh->sh_type)
|
||||
{
|
||||
case SHT_DYNSYM:
|
||||
// get .dynsym
|
||||
if (dlctx->dynsym)
|
||||
{
|
||||
by_trace("%s: duplicate .dynsym sections", realpath);
|
||||
broken = by_true;
|
||||
break;
|
||||
}
|
||||
dlctx->dynsym = dlctx->filedata + sh->sh_offset;
|
||||
dlctx->dynsym_num = (sh->sh_size / sizeof(ElfW(Sym)));
|
||||
by_trace(".dynsym: %p %d", dlctx->dynsym, dlctx->dynsym_num);
|
||||
break;
|
||||
case SHT_SYMTAB:
|
||||
// get .symtab
|
||||
if (dlctx->symtab)
|
||||
{
|
||||
by_trace("%s: duplicate .symtab sections", realpath);
|
||||
broken = by_true;
|
||||
break;
|
||||
}
|
||||
dlctx->symtab = dlctx->filedata + sh->sh_offset;
|
||||
dlctx->symtab_num = (sh->sh_size / sizeof(ElfW(Sym)));
|
||||
by_trace(".symtab: %p %d", dlctx->symtab, dlctx->symtab_num);
|
||||
break;
|
||||
case SHT_STRTAB:
|
||||
// get .dynstr
|
||||
if (!strcmp(shstr + sh->sh_name, ".dynstr"))
|
||||
{
|
||||
// .dynstr is guaranteed to be the first STRTAB
|
||||
if (dlctx->dynstr) break;
|
||||
dlctx->dynstr = dlctx->filedata + sh->sh_offset;
|
||||
by_trace(".dynstr: %p", dlctx->dynstr);
|
||||
}
|
||||
// get .strtab
|
||||
else if (!strcmp(shstr + sh->sh_name, ".strtab"))
|
||||
{
|
||||
if (dlctx->strtab) break;
|
||||
dlctx->strtab = dlctx->filedata + sh->sh_offset;
|
||||
by_trace(".strtab: %p", dlctx->strtab);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
by_check_break(!broken && dlctx->dynstr && dlctx->dynsym);
|
||||
|
||||
// ok
|
||||
ok = by_true;
|
||||
|
||||
} while (0);
|
||||
|
||||
// failed?
|
||||
if (!ok)
|
||||
{
|
||||
if (dlctx) by_fake_dlclose(dlctx);
|
||||
dlctx = by_null;
|
||||
}
|
||||
return dlctx;
|
||||
}
|
||||
static by_void_t by_linker_init()
|
||||
{
|
||||
static by_bool_t s_inited = by_false;
|
||||
if (!s_inited)
|
||||
{
|
||||
// we need linker mutex only for android 5.0 and 5.1
|
||||
by_size_t apilevel = by_rt_api_level();
|
||||
if (apilevel == __ANDROID_API_L__ || apilevel == __ANDROID_API_L_MR1__)
|
||||
{
|
||||
by_fake_dlctx_ref_t linker = by_fake_dlopen_impl(BY_LINKER_NAME, BY_RTLD_NOW);
|
||||
by_trace("init linker: %p", linker);
|
||||
if (linker)
|
||||
{
|
||||
g_linker_mutex = (pthread_mutex_t*)by_fake_dlsym(linker, BY_LINKER_MUTEX);
|
||||
by_trace("load g_dl_mutex: %p", g_linker_mutex);
|
||||
by_fake_dlclose(linker);
|
||||
}
|
||||
}
|
||||
s_inited = by_true;
|
||||
}
|
||||
}
|
||||
static by_fake_dlctx_ref_t by_fake_dlopen(by_char_t const* filename, by_int_t flag)
|
||||
{
|
||||
by_linker_init();
|
||||
return by_fake_dlopen_impl(filename, flag);
|
||||
}
|
||||
static by_void_t by_jni_clearException(JNIEnv* env, by_bool_t report)
|
||||
{
|
||||
jthrowable e = report? (*env)->ExceptionOccurred(env) : by_null;
|
||||
(*env)->ExceptionClear(env);
|
||||
if (e)
|
||||
{
|
||||
jclass clazz = (*env)->GetObjectClass(env, e);
|
||||
jmethodID printStackTrace_id = (*env)->GetMethodID(env, clazz, "printStackTrace", "()V");
|
||||
if (!(*env)->ExceptionCheck(env) && printStackTrace_id)
|
||||
(*env)->CallVoidMethod(env, e, printStackTrace_id);
|
||||
if ((*env)->ExceptionCheck(env))
|
||||
(*env)->ExceptionClear(env);
|
||||
}
|
||||
}
|
||||
static jobject by_jni_Class_getDeclaredMethod(JNIEnv* env)
|
||||
{
|
||||
// check
|
||||
by_assert_and_check_return_val(env, by_null);
|
||||
|
||||
// push
|
||||
if ((*env)->PushLocalFrame(env, 10) < 0) return by_null;
|
||||
|
||||
// get unreachable memory info
|
||||
jboolean check = by_false;
|
||||
jobject getDeclaredMethod_method = by_null;
|
||||
do
|
||||
{
|
||||
// get class
|
||||
jclass clazz = (*env)->FindClass(env, "java/lang/Class");
|
||||
by_assert_and_check_break(!(check = (*env)->ExceptionCheck(env)) && clazz);
|
||||
|
||||
// get string class
|
||||
jclass string_clazz = (*env)->FindClass(env, "java/lang/String");
|
||||
by_assert_and_check_break(!(check = (*env)->ExceptionCheck(env)) && string_clazz);
|
||||
|
||||
// get class/array class
|
||||
jclass classarray_clazz = (*env)->FindClass(env, "[Ljava/lang/Class;");
|
||||
by_assert_and_check_break(!(check = (*env)->ExceptionCheck(env)) && classarray_clazz);
|
||||
|
||||
// get getDeclaredMethod id
|
||||
jmethodID getDeclaredMethod_id = (*env)->GetMethodID(env, clazz, "getDeclaredMethod", "(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;");
|
||||
by_assert_and_check_break(!(check = (*env)->ExceptionCheck(env)) && getDeclaredMethod_id);
|
||||
|
||||
// get getDeclaredMethod name
|
||||
jstring getDeclaredMethod_name = (*env)->NewStringUTF(env, "getDeclaredMethod");
|
||||
by_assert_and_check_break(!(check = (*env)->ExceptionCheck(env)) && getDeclaredMethod_name);
|
||||
|
||||
// get getDeclaredMethod args
|
||||
jobjectArray getDeclaredMethod_args = (*env)->NewObjectArray(env, 2, clazz, by_null);
|
||||
by_assert_and_check_break(!(check = (*env)->ExceptionCheck(env)) && getDeclaredMethod_args);
|
||||
|
||||
(*env)->SetObjectArrayElement(env, getDeclaredMethod_args, 0, string_clazz);
|
||||
(*env)->SetObjectArrayElement(env, getDeclaredMethod_args, 1, classarray_clazz);
|
||||
|
||||
// Method getDeclaredMethod = Class.class.getDeclaredMethod("getDeclaredMethod", String.class, Class[].class);
|
||||
getDeclaredMethod_method = (jobject)(*env)->CallObjectMethod(env, clazz, getDeclaredMethod_id, getDeclaredMethod_name, getDeclaredMethod_args);
|
||||
by_assert_and_check_break(!(check = (*env)->ExceptionCheck(env)) && getDeclaredMethod_method);
|
||||
|
||||
} while (0);
|
||||
|
||||
// exception? clear it
|
||||
if (check)
|
||||
{
|
||||
getDeclaredMethod_method = by_null;
|
||||
by_jni_clearException(env, by_true);
|
||||
}
|
||||
return (jstring)(*env)->PopLocalFrame(env, getDeclaredMethod_method);
|
||||
}
|
||||
|
||||
/* load library via system call
|
||||
*
|
||||
* @see http://weishu.me/2018/06/07/free-reflection-above-android-p/
|
||||
* https://github.com/tiann/FreeReflection/blob/c995ef100f39c2eb2d7c344384ca06e8c13b9a4c/library/src/main/java/me/weishu/reflection/Reflection.java#L23-L34
|
||||
*
|
||||
* System.load(libraryPath)
|
||||
*
|
||||
* @code
|
||||
Method forName = Class.class.getDeclaredMethod("forName", String.class);
|
||||
Method getDeclaredMethod = Class.class.getDeclaredMethod("getDeclaredMethod", String.class, Class[].class);
|
||||
Class<?> systemClass = (Class<?>)forName.invoke(null, "java.lang.System");
|
||||
Method load = (Method)getDeclaredMethod.invoke(systemClass, "load", new Class[]{String.class});
|
||||
load.invoke(systemClass, libraryPath);
|
||||
* @endcode
|
||||
*
|
||||
* System.loadLibrary(libraryName)
|
||||
*
|
||||
* @code
|
||||
Method forName = Class.class.getDeclaredMethod("forName", String.class);
|
||||
Method getDeclaredMethod = Class.class.getDeclaredMethod("getDeclaredMethod", String.class, Class[].class);
|
||||
Class<?> systemClass = (Class<?>)forName.invoke(null, "java.lang.System");
|
||||
Method loadLibrary = (Method)getDeclaredMethod.invoke(systemClass, "loadLibrary", new Class[]{String.class});
|
||||
loadLibrary.invoke(systemClass, libraryName);
|
||||
* @endcode
|
||||
*/
|
||||
static by_bool_t by_jni_System_load_or_loadLibrary_from_sys(JNIEnv* env, by_char_t const* loadName, by_char_t const* libraryPath)
|
||||
{
|
||||
// check
|
||||
by_assert_and_check_return_val(env && loadName && libraryPath, by_false);
|
||||
|
||||
// push
|
||||
if ((*env)->PushLocalFrame(env, 20) < 0) return by_false;
|
||||
|
||||
// do load
|
||||
jboolean check = by_false;
|
||||
do
|
||||
{
|
||||
// get getDeclaredMethod method
|
||||
jobject getDeclaredMethod_method = by_jni_Class_getDeclaredMethod(env);
|
||||
by_assert_and_check_break(!(check = (*env)->ExceptionCheck(env)) && getDeclaredMethod_method);
|
||||
|
||||
// get class
|
||||
jclass clazz = (*env)->FindClass(env, "java/lang/Class");
|
||||
by_assert_and_check_break(!(check = (*env)->ExceptionCheck(env)) && clazz);
|
||||
|
||||
// get object class
|
||||
jclass object_clazz = (*env)->FindClass(env, "java/lang/Object");
|
||||
by_assert_and_check_break(!(check = (*env)->ExceptionCheck(env)) && object_clazz);
|
||||
|
||||
// get string class
|
||||
jclass string_clazz = (*env)->FindClass(env, "java/lang/String");
|
||||
by_assert_and_check_break(!(check = (*env)->ExceptionCheck(env)) && string_clazz);
|
||||
|
||||
// get system class
|
||||
jclass system_clazz = (*env)->FindClass(env, "java/lang/System");
|
||||
by_assert_and_check_break(!(check = (*env)->ExceptionCheck(env)) && system_clazz);
|
||||
|
||||
// get method class
|
||||
jclass method_clazz = (*env)->FindClass(env, "java/lang/reflect/Method");
|
||||
by_assert_and_check_break(!(check = (*env)->ExceptionCheck(env)) && method_clazz);
|
||||
|
||||
// get getDeclaredMethod_method.invoke id
|
||||
jmethodID invoke_id = (*env)->GetMethodID(env, method_clazz, "invoke", "(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;");
|
||||
by_assert_and_check_break(!(check = (*env)->ExceptionCheck(env)) && invoke_id);
|
||||
|
||||
// get load name
|
||||
jstring load_name = (*env)->NewStringUTF(env, loadName);
|
||||
by_assert_and_check_break(!(check = (*env)->ExceptionCheck(env)) && load_name);
|
||||
|
||||
// get invoke args
|
||||
jobjectArray invoke_args = (*env)->NewObjectArray(env, 2, object_clazz, by_null);
|
||||
by_assert_and_check_break(!(check = (*env)->ExceptionCheck(env)) && invoke_args);
|
||||
|
||||
// get load args
|
||||
jobjectArray load_args = (*env)->NewObjectArray(env, 1, clazz, string_clazz);
|
||||
by_assert_and_check_break(!(check = (*env)->ExceptionCheck(env)) && load_args);
|
||||
|
||||
(*env)->SetObjectArrayElement(env, invoke_args, 0, load_name);
|
||||
(*env)->SetObjectArrayElement(env, invoke_args, 1, load_args);
|
||||
|
||||
// Method load = (Method)getDeclaredMethod.invoke(systemClass, "load", new Class[]{String.class});
|
||||
jobject load_method = (jobject)(*env)->CallObjectMethod(env, getDeclaredMethod_method, invoke_id, system_clazz, invoke_args);
|
||||
by_assert_and_check_break(!(check = (*env)->ExceptionCheck(env)) && load_method);
|
||||
|
||||
// load.invoke(systemClass, libraryPath)
|
||||
jstring libraryPath_jstr = (*env)->NewStringUTF(env, libraryPath);
|
||||
by_assert_and_check_break(!(check = (*env)->ExceptionCheck(env)) && libraryPath_jstr);
|
||||
|
||||
invoke_args = (*env)->NewObjectArray(env, 1, object_clazz, libraryPath_jstr);
|
||||
by_assert_and_check_break(!(check = (*env)->ExceptionCheck(env)) && invoke_args);
|
||||
|
||||
(*env)->CallObjectMethod(env, load_method, invoke_id, system_clazz, invoke_args);
|
||||
by_assert_and_check_break(!(check = (*env)->ExceptionCheck(env)));
|
||||
|
||||
} while (0);
|
||||
|
||||
// exception? clear it
|
||||
if (check) by_jni_clearException(env, by_true);
|
||||
(*env)->PopLocalFrame(env, by_null);
|
||||
return !check;
|
||||
}
|
||||
static by_bool_t by_jni_System_load_or_loadLibrary_from_app(JNIEnv* env, by_char_t const* loadName, by_char_t const* libraryPath)
|
||||
{
|
||||
// check
|
||||
by_assert_and_check_return_val(env && loadName && libraryPath, by_false);
|
||||
|
||||
// push
|
||||
if ((*env)->PushLocalFrame(env, 10) < 0) return by_false;
|
||||
|
||||
// do load
|
||||
jboolean check = by_false;
|
||||
do
|
||||
{
|
||||
// get system class
|
||||
jclass system_clazz = (*env)->FindClass(env, "java/lang/System");
|
||||
by_assert_and_check_break(!(check = (*env)->ExceptionCheck(env)) && system_clazz);
|
||||
|
||||
// get load/loadLibrary id
|
||||
jmethodID load_id = (*env)->GetStaticMethodID(env, system_clazz, loadName, "(Ljava/lang/String;)V");
|
||||
by_assert_and_check_break(!(check = (*env)->ExceptionCheck(env)) && load_id);
|
||||
|
||||
// get library path
|
||||
jstring libraryPath_jstr = (*env)->NewStringUTF(env, libraryPath);
|
||||
by_assert_and_check_break(!(check = (*env)->ExceptionCheck(env)) && libraryPath_jstr);
|
||||
|
||||
// load library
|
||||
(*env)->CallStaticVoidMethod(env, system_clazz, load_id, libraryPath_jstr);
|
||||
by_assert_and_check_break(!(check = (*env)->ExceptionCheck(env)));
|
||||
|
||||
} while (0);
|
||||
|
||||
// exception? clear it
|
||||
if (check) by_jni_clearException(env, by_true);
|
||||
(*env)->PopLocalFrame(env, by_null);
|
||||
return !check;
|
||||
}
|
||||
|
||||
// System.load(libraryPath)
|
||||
static by_bool_t by_jni_System_load(JNIEnv* env, by_char_t const* libraryPath)
|
||||
{
|
||||
by_trace("load: %s", libraryPath);
|
||||
return by_jni_System_load_or_loadLibrary_from_app(env, "load", libraryPath) ||
|
||||
by_jni_System_load_or_loadLibrary_from_sys(env, "load", libraryPath);
|
||||
}
|
||||
|
||||
// System.loadLibrary(libraryName)
|
||||
static by_bool_t by_jni_System_loadLibrary(JNIEnv* env, by_char_t const* libraryName)
|
||||
{
|
||||
by_trace("loadLibrary: %s", libraryName);
|
||||
return by_jni_System_load_or_loadLibrary_from_app(env, "loadLibrary", libraryName) ||
|
||||
by_jni_System_load_or_loadLibrary_from_sys(env, "loadLibrary", libraryName);
|
||||
}
|
||||
|
||||
/* get the current jni environment
|
||||
*
|
||||
* @see frameworks/base/core/jni/include/android_runtime/AndroidRuntime.h
|
||||
*
|
||||
* static AndroidRuntime* runtime = AndroidRuntime::getRuntime();
|
||||
* static JavaVM* getJavaVM() { return mJavaVM; }
|
||||
* static JNIEnv* getJNIEnv();
|
||||
*/
|
||||
static JNIEnv* by_jni_getenv()
|
||||
{
|
||||
if (g_jvm)
|
||||
{
|
||||
JNIEnv* env = by_null;
|
||||
if (JNI_OK == (*g_jvm)->GetEnv(g_jvm, (by_pointer_t*)&env, g_jversion))
|
||||
return env;
|
||||
}
|
||||
if (!g_tls_jnienv)
|
||||
{
|
||||
by_fake_dlctx_ref_t dlctx = by_fake_dlopen("libandroid_runtime.so", BY_RTLD_NOW);
|
||||
if (dlctx)
|
||||
{
|
||||
typedef by_pointer_t (*getJNIEnv_t)();
|
||||
getJNIEnv_t getJNIEnv = (getJNIEnv_t)by_fake_dlsym(dlctx, "_ZN7android14AndroidRuntime9getJNIEnvEv");
|
||||
if (getJNIEnv)
|
||||
g_tls_jnienv = getJNIEnv();
|
||||
by_fake_dlclose(dlctx);
|
||||
}
|
||||
|
||||
// trace
|
||||
by_trace("get jnienv: %p", g_tls_jnienv);
|
||||
}
|
||||
return g_tls_jnienv;
|
||||
}
|
||||
|
||||
by_void_t by_jni_javavm_set(JavaVM* jvm, by_int_t jversion)
|
||||
{
|
||||
g_jvm = jvm;
|
||||
g_jversion = jversion;
|
||||
}
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////////////////////
|
||||
* implementation
|
||||
*/
|
||||
by_pointer_t by_dlopen(by_char_t const* filename, by_int_t flag)
|
||||
{
|
||||
// check
|
||||
by_assert_and_check_return_val(filename, by_null);
|
||||
|
||||
// attempt to use original dlopen to load it fist
|
||||
// TODO we disable the original dlopen now, load /data/xxx.so may be returned an invalid address
|
||||
by_pointer_t handle = by_null;//dlopen(filename, flag == BY_RTLD_LAZY? RTLD_LAZY : RTLD_NOW);
|
||||
|
||||
// uses the fake dlopen to load it from maps directly
|
||||
if (!handle) handle = (by_pointer_t)by_fake_dlopen(filename, flag);
|
||||
|
||||
// uses the fake dlopen to load it from maps directly
|
||||
if (!handle)
|
||||
{
|
||||
// load it via system call
|
||||
JNIEnv* env = by_jni_getenv();
|
||||
if (env && (((strstr(filename, "/") || strstr(filename, ".so")) && by_jni_System_load(env, filename)) || by_jni_System_loadLibrary(env, filename)))
|
||||
handle = (by_pointer_t)by_fake_dlopen(filename, flag);
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
by_pointer_t by_dlsym(by_pointer_t handle, by_char_t const* symbol)
|
||||
{
|
||||
// check
|
||||
by_fake_dlctx_ref_t dlctx = (by_fake_dlctx_ref_t)handle;
|
||||
by_assert_and_check_return_val(dlctx && symbol, by_null);
|
||||
|
||||
// do dlsym
|
||||
return (dlctx->magic == BY_FAKE_DLCTX_MAGIC)? by_fake_dlsym(dlctx, symbol) : dlsym(handle, symbol);
|
||||
}
|
||||
by_int_t by_dlclose(by_pointer_t handle)
|
||||
{
|
||||
// check
|
||||
by_fake_dlctx_ref_t dlctx = (by_fake_dlctx_ref_t)handle;
|
||||
by_assert_and_check_return_val(dlctx, -1);
|
||||
|
||||
// do dlclose
|
||||
return (dlctx->magic == BY_FAKE_DLCTX_MAGIC)? by_fake_dlclose(dlctx) : dlclose(handle);
|
||||
}
|
||||
|
|
@ -1,232 +0,0 @@
|
|||
/*!A dlopen library that bypasses mobile system limitation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* Copyright (C) 2020-present, TBOOX Open Source Group.
|
||||
*
|
||||
* @author ruki
|
||||
* @file prefix.h
|
||||
*
|
||||
*/
|
||||
#ifndef BY_PREFIX_H
|
||||
#define BY_PREFIX_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////////////////////
|
||||
* includes
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <ctype.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/time.h>
|
||||
#if defined(__ANDROID__)
|
||||
# include <jni.h>
|
||||
# include <android/log.h>
|
||||
#elif defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__)
|
||||
# include <asl.h>
|
||||
#endif
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////////////////////
|
||||
* macros
|
||||
*/
|
||||
|
||||
// bool values
|
||||
#ifdef __ANDROID__
|
||||
# define by_true ((by_bool_t)JNI_TRUE)
|
||||
# define by_false ((by_bool_t)JNI_FALSE)
|
||||
#else
|
||||
# define by_true ((by_bool_t)1)
|
||||
# define by_false ((by_bool_t)0)
|
||||
#endif
|
||||
|
||||
// null
|
||||
#ifdef __cplusplus
|
||||
# define by_null (0)
|
||||
#else
|
||||
# define by_null ((by_pointer_t)0)
|
||||
#endif
|
||||
|
||||
// print
|
||||
#define by_print(fmt, arg ...) by_printf(fmt "\n", ## arg)
|
||||
|
||||
// trace
|
||||
#ifdef BY_DEBUG
|
||||
# define by_tracef(fmt, arg ...) by_printf(fmt, ## arg)
|
||||
# define by_trace(fmt, arg ...) by_printf(fmt "\n", ## arg)
|
||||
# define by_trace_line(fmt, arg ...) by_printf(fmt " at func: %s, line: %d, file: %s\n", ##arg, __FUNCTION__, __LINE__, __FILE__)
|
||||
#else
|
||||
# define by_tracef(...)
|
||||
# define by_trace(...)
|
||||
# define by_trace_line(...)
|
||||
#endif
|
||||
|
||||
// check
|
||||
#define by_check_return(x) do { if (!(x)) return ; } while (0)
|
||||
#define by_check_return_val(x, v) do { if (!(x)) return (v); } while (0)
|
||||
#define by_check_goto(x, b) do { if (!(x)) goto b; } while (0)
|
||||
#define by_check_break(x) { if (!(x)) break ; }
|
||||
#define by_check_continue(x) { if (!(x)) continue ; }
|
||||
|
||||
// assert
|
||||
#ifdef BY_DEBUG
|
||||
# define by_assert(x) do { if (!(x)) {by_trace_line("[assert]: expr: %s", #x); } } while(0)
|
||||
# define by_assert_return(x) do { if (!(x)) {by_trace_line("[assert]: expr: %s", #x); return ; } } while(0)
|
||||
# define by_assert_return_val(x, v) do { if (!(x)) {by_trace_line("[assert]: expr: %s", #x); return (v); } } while(0)
|
||||
# define by_assert_goto(x, b) do { if (!(x)) {by_trace_line("[assert]: expr: %s", #x); goto b; } } while(0)
|
||||
# define by_assert_break(x) { if (!(x)) {by_trace_line("[assert]: expr: %s", #x); break ; } }
|
||||
# define by_assert_continue(x) { if (!(x)) {by_trace_line("[assert]: expr: %s", #x); continue ; } }
|
||||
# define by_assert_and_check_return(x) by_assert_return(x)
|
||||
# define by_assert_and_check_return_val(x, v) by_assert_return_val(x, v)
|
||||
# define by_assert_and_check_goto(x, b) by_assert_goto(x, b)
|
||||
# define by_assert_and_check_break(x) by_assert_break(x)
|
||||
# define by_assert_and_check_continue(x) by_assert_continue(x)
|
||||
#else
|
||||
# define by_assert(x)
|
||||
# define by_assert_return(x)
|
||||
# define by_assert_return_val(x, v)
|
||||
# define by_assert_goto(x, b)
|
||||
# define by_assert_break(x)
|
||||
# define by_assert_continue(x)
|
||||
# define by_assert_and_check_return(x) by_check_return(x)
|
||||
# define by_assert_and_check_return_val(x, v) by_check_return_val(x, v)
|
||||
# define by_assert_and_check_goto(x, b) by_check_goto(x, b)
|
||||
# define by_assert_and_check_break(x) by_check_break(x)
|
||||
# define by_assert_and_check_continue(x) by_check_continue(x)
|
||||
#endif
|
||||
|
||||
// printf
|
||||
#if defined(__ANDROID__)
|
||||
# define by_printf(fmt, arg ...) __android_log_print(ANDROID_LOG_INFO, "byOpen", fmt, ## arg)
|
||||
#elif defined(__ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__)
|
||||
# define by_printf(fmt, arg ...) asl_log(by_null, by_null, ASL_LEVEL_WARNING, "[byOpen]: " fmt, ## arg);
|
||||
#else
|
||||
# define by_printf(fmt, arg ...) printf(fmt, ## arg)
|
||||
#endif
|
||||
|
||||
/* arch
|
||||
*
|
||||
* gcc builtin macros for gcc -dM -E - < /dev/null
|
||||
*
|
||||
* .e.g gcc -m64 -dM -E - < /dev/null | grep 64
|
||||
* .e.g gcc -m32 -dM -E - < /dev/null | grep 86
|
||||
* .e.g gcc -march=armv6 -dM -E - < /dev/null | grep ARM
|
||||
*/
|
||||
#if defined(__i386) \
|
||||
|| defined(__i686) \
|
||||
|| defined(__i386__) \
|
||||
|| defined(__i686__) \
|
||||
|| defined(_M_IX86)
|
||||
# define BY_ARCH_x86
|
||||
#elif defined(__x86_64) \
|
||||
|| defined(__amd64__) \
|
||||
|| defined(__amd64) \
|
||||
|| defined(_M_IA64) \
|
||||
|| defined(_M_X64)
|
||||
# define BY_ARCH_x64
|
||||
#elif defined(__arm__) || defined(__arm64) || defined(__arm64__) || (defined(__aarch64__) && __aarch64__)
|
||||
# define BY_ARCH_ARM
|
||||
# if defined(__ARM64_ARCH_8__)
|
||||
# define BY_ARCH_ARM64
|
||||
# define BY_ARCH_ARM_v8
|
||||
# elif defined(__ARM_ARCH_7A__)
|
||||
# define BY_ARCH_ARM_v7A
|
||||
# elif defined(__ARM_ARCH_7__)
|
||||
# define BY_ARCH_ARM_v7
|
||||
# elif defined(__ARM_ARCH_6__)
|
||||
# define BY_ARCH_ARM_v6
|
||||
# elif defined(__ARM_ARCH_5TE__)
|
||||
# define BY_ARCH_ARM_v5te
|
||||
# elif defined(__ARM_ARCH_5__)
|
||||
# define BY_ARCH_ARM_v5
|
||||
# elif defined(__ARM_ARCH_4T__)
|
||||
# define BY_ARCH_ARM_v4t
|
||||
# elif defined(__ARM_ARCH)
|
||||
# define BY_ARCH_ARM_VERSION __ARM_ARCH
|
||||
# if __ARM_ARCH >= 8
|
||||
# define BY_ARCH_ARM_v8
|
||||
# if defined(__arm64) || defined(__arm64__)
|
||||
# define BY_ARCH_ARM64
|
||||
# elif (defined(__aarch64__) && __aarch64__)
|
||||
# define BY_ARCH_ARM64
|
||||
# endif
|
||||
# elif __ARM_ARCH >= 7
|
||||
# define BY_ARCH_ARM_v7
|
||||
# elif __ARM_ARCH >= 6
|
||||
# define BY_ARCH_ARM_v6
|
||||
# else
|
||||
# define BY_ARCH_ARM_v5
|
||||
# endif
|
||||
# elif defined(__aarch64__) && __aarch64__
|
||||
# define BY_ARCH_ARM_v8
|
||||
# define BY_ARCH_ARM64
|
||||
# else
|
||||
# error unknown arm arch version
|
||||
# endif
|
||||
# if !defined(BY_ARCH_ARM64) && (defined(__arm64) || defined(__arm64__) || (defined(__aarch64__) && __aarch64__))
|
||||
# define BY_ARCH_ARM64
|
||||
# endif
|
||||
# if defined(__thumb__)
|
||||
# define BY_ARCH_ARM_THUMB
|
||||
# endif
|
||||
# if defined(__ARM_NEON__)
|
||||
# define BY_ARCH_ARM_NEON
|
||||
# endif
|
||||
#else
|
||||
# error unknown arch
|
||||
#endif
|
||||
|
||||
/* //////////////////////////////////////////////////////////////////////////////////////
|
||||
* types
|
||||
*/
|
||||
|
||||
// basic
|
||||
typedef signed int by_int_t;
|
||||
typedef unsigned int by_uint_t;
|
||||
typedef signed long by_long_t;
|
||||
typedef unsigned long by_ulong_t;
|
||||
typedef by_ulong_t by_size_t;
|
||||
typedef by_int_t by_bool_t;
|
||||
typedef signed char by_int8_t;
|
||||
typedef by_int8_t by_sint8_t;
|
||||
typedef unsigned char by_uint8_t;
|
||||
typedef signed short by_int16_t;
|
||||
typedef by_int16_t by_sint16_t;
|
||||
typedef unsigned short by_uint16_t;
|
||||
typedef by_int_t by_int32_t;
|
||||
typedef by_int32_t by_sint32_t;
|
||||
typedef by_uint_t by_uint32_t;
|
||||
typedef char by_char_t;
|
||||
typedef by_int32_t by_wchar_t;
|
||||
typedef by_int32_t by_uchar_t;
|
||||
typedef by_uint8_t by_byte_t;
|
||||
typedef void by_void_t;
|
||||
typedef by_void_t* by_pointer_t;
|
||||
typedef by_void_t const* by_cpointer_t;
|
||||
typedef by_pointer_t by_handle_t;
|
||||
typedef signed long long by_int64_t;
|
||||
typedef unsigned long long by_uint64_t;
|
||||
typedef by_int64_t by_sint64_t;
|
||||
typedef by_sint64_t by_hong_t;
|
||||
typedef by_uint64_t by_hize_t;
|
||||
typedef float by_float_t;
|
||||
typedef double by_double_t;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
#endif
|
|
@ -11,7 +11,6 @@
|
|||
#include <dlfcn.h>
|
||||
|
||||
#include <internal.h>
|
||||
#include "byopen/byopen.h"
|
||||
|
||||
typedef VkFlags VkAndroidSurfaceCreateFlagsKHR;
|
||||
|
||||
|
|
|
@ -6,7 +6,6 @@
|
|||
#include "common_tools.h"
|
||||
#include "FCLLWJGL.h"
|
||||
#include <dlfcn.h>
|
||||
#include "byopen/byopen.h"
|
||||
|
||||
EXTERN_C_ENTER
|
||||
|
||||
|
|
Loading…
Reference in New Issue