first commit
This commit is contained in:
commit
bb00b43b3c
11
.gitignore
vendored
Normal file
11
.gitignore
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
.idea/
|
||||
assets/
|
||||
data/
|
||||
tmp/
|
||||
libs/libminecraftpe.so
|
||||
libs/libgnustl_shared.so
|
||||
*.apk
|
||||
mcpelauncher
|
||||
build/
|
||||
libs/
|
||||
!libs/.gitkeep
|
||||
37
CMakeLists.txt
Normal file
37
CMakeLists.txt
Normal file
@ -0,0 +1,37 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
project(mcpelauncher)
|
||||
|
||||
enable_language(C ASM)
|
||||
|
||||
set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} -m32")
|
||||
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -m32")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32")
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11")
|
||||
set(CMAKE_LIBRARY_ARCHITECTURE "i386-linux-gnu")
|
||||
|
||||
link_directories(/usr/lib32)
|
||||
include_directories(/usr/include)
|
||||
set(X11_X11_LIB /usr/lib32/libX11.so)
|
||||
|
||||
#SET(CMAKE_CXX_COMPILER "g++-4.9")
|
||||
#SET(CMAKE_C_COMPILER "gcc-4.9")
|
||||
|
||||
find_package(Threads REQUIRED)
|
||||
find_package(ZLIB REQUIRED)
|
||||
find_package(X11 REQUIRED)
|
||||
|
||||
include(FindEGL.cmake)
|
||||
|
||||
include_directories(${PNG_INCLUDE_DIRS})
|
||||
include_directories(${EGL_INCLUDE_DIRS})
|
||||
include_directories(eglut)
|
||||
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -D_GLIBCXX_USE_CXX11_ABI=0")
|
||||
|
||||
set(HYBRIS_SOURCES hybris/src/cache.c hybris/src/dlfcn.c hybris/src/hooks.c hybris/src/hooks_shm.c hybris/src/logging.c hybris/src/properties.c hybris/src/strlcpy.c hybris/src/sysconf.c hybris/src/jb/dlfcn.c hybris/src/jb/linker.c hybris/src/jb/linker_environ.c hybris/src/jb/linker_format.c hybris/src/jb/rt.c)
|
||||
set(EGLUT_SOURCES eglut/eglut.c eglut/eglut_x11.c)
|
||||
|
||||
set(SOURCE_FILES src/main.cpp src/common.cpp src/hook.cpp src/amdfix.s src/LinuxAppPlatform.cpp mcpe/types.cpp mcpe/ImagePickingCallback.h mcpe/FilePickerSettings.h)
|
||||
add_executable(mcpelauncher ${HYBRIS_SOURCES} ${EGLUT_SOURCES} ${SOURCE_FILES})
|
||||
target_link_libraries(mcpelauncher ${CMAKE_DL_LIBS} ${CMAKE_THREAD_LIBS_INIT} rt libEGL.so libGLESv2.so ${X11_X11_LIB} uuid)
|
||||
target_compile_definitions(mcpelauncher PRIVATE ANDROID_X86_LINKER _GNU_SOURCE LINKER_TEXT_BASE=0xB0000100 LINKER_AREA_SIZE=0x01000000 LINKER_DEBUG=1)
|
||||
set_target_properties(mcpelauncher PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
|
||||
26
LICENSE
Normal file
26
LICENSE
Normal file
@ -0,0 +1,26 @@
|
||||
Copyright (c) 2015, MCMrARM
|
||||
All rights reserved.
|
||||
|
||||
Redistribution and use in source and binary forms, with or without
|
||||
modification, are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice, this
|
||||
list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation
|
||||
and/or other materials provided with the distribution.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
|
||||
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
The views and conclusions contained in the software and documentation are those
|
||||
of the authors and should not be interpreted as representing official policies,
|
||||
either expressed or implied, of the FreeBSD Project.
|
||||
42
README.md
Normal file
42
README.md
Normal file
@ -0,0 +1,42 @@
|
||||
MCPE Linux Launcher
|
||||
===================
|
||||
|
||||
## Required packages
|
||||
|
||||
```
|
||||
sudo apt-get install cmake zlib1g-dev:i386 libncurses5-dev:i386 libgles2-mesa-dev gcc-multilib g++-multilib zlib1g-dev:i386 libx11-dev:i386 linux-libc-dev:i386 uuid-dev:i386 libpng-dev:i386 libx11-dev:i386 libxext6:i386
|
||||
```
|
||||
|
||||
If g++-4.9 fails to install and you're using Ubuntu 14.04 you may need to add the repository ppa:ubuntu-toolchain-r/test.
|
||||
|
||||
You'll also need to install 32-bit version of the graphic drivers (nvidia drivers ask you about that at installation, so
|
||||
you may need to reinstall/reconfigure them; if you use mesa you'll need to install the libgles2-mesa-dev:i386 and
|
||||
libegl1-mesa-dev:i386 packages)
|
||||
|
||||
You may also need to do `sudo dpkg --add-architecture i386` if you have never installed i386 packages before.
|
||||
|
||||
## Compiling
|
||||
This app uses cmake so it is enough to do:
|
||||
|
||||
```
|
||||
cmake .
|
||||
make
|
||||
```
|
||||
|
||||
## Running
|
||||
1. Clone this repository
|
||||
2. Compile the launcher
|
||||
3. You'll need to obtain a x86 MCPE .apk. The easiest way to do so is to use the
|
||||
[Google Play downloader tool](https://github.com/MCMrARM/Google-Play-API) (it is an console app; remember that
|
||||
you need to type 'y' when you are asked if you want to use x86 as the architecture, and you must have purchased MCPE
|
||||
on the Google account you are logging in with; the package name of MCPE is `com.mojang.minecraftpe`)
|
||||
4. After you have downloaded MCPE, place it in the directory where you'll be running this app, and run ./extract.sh _filename_
|
||||
5. Run the launcher!
|
||||
|
||||
If the extract script fails with an error about the .apk not being x86, it means that you have provided it a bad .apk.
|
||||
You'll need to purchase MCPE on Google Play and use the downloader tool.
|
||||
|
||||
## License and thanks
|
||||
Most of the code in this repo is licensed under BSD. This project uses libc, libstdc++, libz and libm - libraries
|
||||
extracted from the Android OS. A modified version of libhybris is also included, which is licensed under GPL. This project
|
||||
also uses the EGLUT library and FMOD library (for sound).
|
||||
398
eglut/eglut.c
Normal file
398
eglut/eglut.c
Normal file
@ -0,0 +1,398 @@
|
||||
/*
|
||||
* Copyright (C) 2010 LunarG Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Chia-I Wu <olv@lunarg.com>
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdarg.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#include "EGL/egl.h"
|
||||
#include "EGL/eglext.h"
|
||||
|
||||
#include "eglutint.h"
|
||||
|
||||
static struct eglut_state _eglut_state = {
|
||||
.api_mask = EGLUT_OPENGL_ES1_BIT,
|
||||
.window_width = 300,
|
||||
.window_height = 300,
|
||||
.window_fullscreen = EGLUT_WINDOWED,
|
||||
.verbose = 0,
|
||||
.num_windows = 0,
|
||||
};
|
||||
|
||||
struct eglut_state *_eglut = &_eglut_state;
|
||||
|
||||
void
|
||||
_eglutFatal(char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
|
||||
va_start(args, format);
|
||||
|
||||
fprintf(stderr, "EGLUT: ");
|
||||
vfprintf(stderr, format, args);
|
||||
va_end(args);
|
||||
putc('\n', stderr);
|
||||
|
||||
exit(1);
|
||||
}
|
||||
|
||||
/* return current time (in milliseconds) */
|
||||
int
|
||||
_eglutNow(void)
|
||||
{
|
||||
struct timeval tv;
|
||||
#ifdef __VMS
|
||||
(void) gettimeofday(&tv, NULL );
|
||||
#else
|
||||
struct timezone tz;
|
||||
(void) gettimeofday(&tv, &tz);
|
||||
#endif
|
||||
return tv.tv_sec * 1000 + tv.tv_usec / 1000;
|
||||
}
|
||||
|
||||
static void
|
||||
_eglutDestroyWindow(struct eglut_window *win)
|
||||
{
|
||||
if (_eglut->surface_type != EGL_PBUFFER_BIT)
|
||||
eglDestroySurface(_eglut->dpy, win->surface);
|
||||
|
||||
_eglutNativeFiniWindow(win);
|
||||
|
||||
eglDestroyContext(_eglut->dpy, win->context);
|
||||
}
|
||||
|
||||
static EGLConfig
|
||||
_eglutChooseConfig(void)
|
||||
{
|
||||
EGLConfig config;
|
||||
EGLint config_attribs[32];
|
||||
EGLint renderable_type, num_configs, i;
|
||||
|
||||
i = 0;
|
||||
config_attribs[i++] = EGL_RED_SIZE;
|
||||
config_attribs[i++] = 1;
|
||||
config_attribs[i++] = EGL_GREEN_SIZE;
|
||||
config_attribs[i++] = 1;
|
||||
config_attribs[i++] = EGL_BLUE_SIZE;
|
||||
config_attribs[i++] = 1;
|
||||
config_attribs[i++] = EGL_DEPTH_SIZE;
|
||||
config_attribs[i++] = 1;
|
||||
config_attribs[i++] = EGL_STENCIL_SIZE;
|
||||
config_attribs[i++] = 8;
|
||||
|
||||
config_attribs[i++] = EGL_SURFACE_TYPE;
|
||||
config_attribs[i++] = _eglut->surface_type;
|
||||
|
||||
config_attribs[i++] = EGL_RENDERABLE_TYPE;
|
||||
renderable_type = 0x0;
|
||||
if (_eglut->api_mask & EGLUT_OPENGL_BIT)
|
||||
renderable_type |= EGL_OPENGL_BIT;
|
||||
if (_eglut->api_mask & EGLUT_OPENGL_ES1_BIT)
|
||||
renderable_type |= EGL_OPENGL_ES_BIT;
|
||||
if (_eglut->api_mask & EGLUT_OPENGL_ES2_BIT)
|
||||
renderable_type |= EGL_OPENGL_ES2_BIT;
|
||||
if (_eglut->api_mask & EGLUT_OPENVG_BIT)
|
||||
renderable_type |= EGL_OPENVG_BIT;
|
||||
config_attribs[i++] = renderable_type;
|
||||
|
||||
config_attribs[i] = EGL_NONE;
|
||||
|
||||
if (!eglChooseConfig(_eglut->dpy,
|
||||
config_attribs, &config, 1, &num_configs) || !num_configs)
|
||||
_eglutFatal("failed to choose a config");
|
||||
|
||||
return config;
|
||||
}
|
||||
|
||||
static struct eglut_window *
|
||||
_eglutCreateWindow(const char *title, int x, int y, int w, int h)
|
||||
{
|
||||
struct eglut_window *win;
|
||||
EGLint context_attribs[4];
|
||||
EGLint api, i;
|
||||
|
||||
win = calloc(1, sizeof(*win));
|
||||
if (!win)
|
||||
_eglutFatal("failed to allocate window");
|
||||
|
||||
win->config = _eglutChooseConfig();
|
||||
|
||||
i = 0;
|
||||
context_attribs[i] = EGL_NONE;
|
||||
|
||||
/* multiple APIs? */
|
||||
|
||||
api = EGL_OPENGL_ES_API;
|
||||
if (_eglut->api_mask & EGLUT_OPENGL_BIT) {
|
||||
api = EGL_OPENGL_API;
|
||||
}
|
||||
else if (_eglut->api_mask & EGLUT_OPENVG_BIT) {
|
||||
api = EGL_OPENVG_API;
|
||||
}
|
||||
else if (_eglut->api_mask & EGLUT_OPENGL_ES2_BIT) {
|
||||
context_attribs[i++] = EGL_CONTEXT_CLIENT_VERSION;
|
||||
context_attribs[i++] = 2;
|
||||
}
|
||||
|
||||
context_attribs[i] = EGL_NONE;
|
||||
|
||||
eglBindAPI(api);
|
||||
win->context = eglCreateContext(_eglut->dpy,
|
||||
win->config, EGL_NO_CONTEXT, context_attribs);
|
||||
if (!win->context)
|
||||
_eglutFatal("failed to create context");
|
||||
|
||||
_eglutNativeInitWindow(win, title, x, y, w, h);
|
||||
switch (_eglut->surface_type) {
|
||||
case EGL_WINDOW_BIT:
|
||||
win->surface = eglCreateWindowSurface(_eglut->dpy,
|
||||
win->config, win->native.u.window, NULL);
|
||||
break;
|
||||
case EGL_PIXMAP_BIT:
|
||||
win->surface = eglCreatePixmapSurface(_eglut->dpy,
|
||||
win->config, win->native.u.pixmap, NULL);
|
||||
break;
|
||||
case EGL_PBUFFER_BIT:
|
||||
win->surface = win->native.u.surface;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (win->surface == EGL_NO_SURFACE)
|
||||
_eglutFatal("failed to create surface");
|
||||
|
||||
return win;
|
||||
}
|
||||
|
||||
void
|
||||
eglutInitAPIMask(int mask)
|
||||
{
|
||||
_eglut->api_mask = mask;
|
||||
}
|
||||
|
||||
void
|
||||
eglutInitWindowSize(int width, int height)
|
||||
{
|
||||
_eglut->window_width = width;
|
||||
_eglut->window_height = height;
|
||||
}
|
||||
|
||||
void
|
||||
eglutInit(int argc, char **argv)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "-display") == 0)
|
||||
_eglut->display_name = argv[++i];
|
||||
else if (strcmp(argv[i], "-info") == 0) {
|
||||
_eglut->verbose = 1;
|
||||
}
|
||||
}
|
||||
|
||||
_eglutNativeInitDisplay();
|
||||
_eglut->dpy = eglGetDisplay(_eglut->native_dpy);
|
||||
|
||||
if (!eglInitialize(_eglut->dpy, &_eglut->major, &_eglut->minor))
|
||||
_eglutFatal("failed to initialize EGL display");
|
||||
|
||||
_eglut->init_time = _eglutNow();
|
||||
|
||||
printf("EGL_VERSION = %s\n", eglQueryString(_eglut->dpy, EGL_VERSION));
|
||||
if (_eglut->verbose) {
|
||||
printf("EGL_VENDOR = %s\n", eglQueryString(_eglut->dpy, EGL_VENDOR));
|
||||
printf("EGL_EXTENSIONS = %s\n",
|
||||
eglQueryString(_eglut->dpy, EGL_EXTENSIONS));
|
||||
printf("EGL_CLIENT_APIS = %s\n",
|
||||
eglQueryString(_eglut->dpy, EGL_CLIENT_APIS));
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
eglutGet(int state)
|
||||
{
|
||||
int val;
|
||||
|
||||
switch (state) {
|
||||
case EGLUT_ELAPSED_TIME:
|
||||
val = _eglutNow() - _eglut->init_time;
|
||||
break;
|
||||
case EGLUT_FULLSCREEN_MODE:
|
||||
val = _eglut->window_fullscreen;
|
||||
break;
|
||||
default:
|
||||
val = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return val;
|
||||
}
|
||||
|
||||
void
|
||||
eglutIdleFunc(EGLUTidleCB func)
|
||||
{
|
||||
_eglut->idle_cb = func;
|
||||
}
|
||||
|
||||
void
|
||||
eglutPostRedisplay(void)
|
||||
{
|
||||
_eglut->redisplay = 1;
|
||||
}
|
||||
|
||||
void
|
||||
eglutMainLoop(void)
|
||||
{
|
||||
struct eglut_window *win = _eglut->current;
|
||||
|
||||
if (!win)
|
||||
_eglutFatal("no window is created\n");
|
||||
|
||||
if (win->reshape_cb)
|
||||
win->reshape_cb(win->native.width, win->native.height);
|
||||
|
||||
_eglutNativeEventLoop();
|
||||
}
|
||||
|
||||
void
|
||||
eglutFini(void)
|
||||
{
|
||||
eglTerminate(_eglut->dpy);
|
||||
_eglutNativeFiniDisplay();
|
||||
}
|
||||
|
||||
void
|
||||
eglutDestroyWindow(int win)
|
||||
{
|
||||
struct eglut_window *window = _eglut->current;
|
||||
|
||||
if (window->index != win)
|
||||
return;
|
||||
|
||||
eglMakeCurrent(_eglut->dpy, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
|
||||
|
||||
_eglutDestroyWindow(_eglut->current);
|
||||
}
|
||||
|
||||
static void
|
||||
_eglutDefaultKeyboard(char *key, int modifiers)
|
||||
{
|
||||
if (key && *key == 27) { // 27 is ESC
|
||||
if (_eglut->current)
|
||||
eglutDestroyWindow(_eglut->current->index);
|
||||
eglutFini();
|
||||
exit(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
eglutCreateWindow(const char *title)
|
||||
{
|
||||
struct eglut_window *win;
|
||||
|
||||
win = _eglutCreateWindow(title, 0, 0,
|
||||
_eglut->window_width, _eglut->window_height);
|
||||
|
||||
win->index = _eglut->num_windows++;
|
||||
win->reshape_cb = NULL;
|
||||
win->display_cb = NULL;
|
||||
win->keyboard_cb = _eglutDefaultKeyboard;
|
||||
win->special_cb = NULL;
|
||||
win->mouse_cb = NULL;
|
||||
win->mouse_button_cb = NULL;
|
||||
|
||||
if (!eglMakeCurrent(_eglut->dpy, win->surface, win->surface, win->context))
|
||||
_eglutFatal("failed to make window current");
|
||||
_eglut->current = win;
|
||||
|
||||
return win->index;
|
||||
}
|
||||
|
||||
int
|
||||
eglutGetWindowWidth(void)
|
||||
{
|
||||
struct eglut_window *win = _eglut->current;
|
||||
return win->native.width;
|
||||
}
|
||||
|
||||
int
|
||||
eglutGetWindowHeight(void)
|
||||
{
|
||||
struct eglut_window *win = _eglut->current;
|
||||
return win->native.height;
|
||||
}
|
||||
|
||||
void
|
||||
eglutDisplayFunc(EGLUTdisplayCB func)
|
||||
{
|
||||
struct eglut_window *win = _eglut->current;
|
||||
win->display_cb = func;
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
eglutReshapeFunc(EGLUTreshapeCB func)
|
||||
{
|
||||
struct eglut_window *win = _eglut->current;
|
||||
win->reshape_cb = func;
|
||||
}
|
||||
|
||||
void
|
||||
eglutKeyboardFunc(EGLUTkeyboardCB func)
|
||||
{
|
||||
struct eglut_window *win = _eglut->current;
|
||||
win->keyboard_cb = func;
|
||||
}
|
||||
|
||||
void
|
||||
eglutSpecialFunc(EGLUTspecialCB func)
|
||||
{
|
||||
struct eglut_window *win = _eglut->current;
|
||||
win->special_cb = func;
|
||||
}
|
||||
|
||||
void
|
||||
eglutMouseFunc(EGLUTmouseCB func)
|
||||
{
|
||||
struct eglut_window *win = _eglut->current;
|
||||
win->mouse_cb = func;
|
||||
}
|
||||
|
||||
void
|
||||
eglutMouseButtonFunc(EGLUTmouseButtonCB func)
|
||||
{
|
||||
struct eglut_window *win = _eglut->current;
|
||||
win->mouse_button_cb = func;
|
||||
}
|
||||
|
||||
void
|
||||
eglutCloseWindowFunc(EGLUTcloseCB func)
|
||||
{
|
||||
struct eglut_window *win = _eglut->current;
|
||||
win->close_cb = func;
|
||||
}
|
||||
128
eglut/eglut.h
Normal file
128
eglut/eglut.h
Normal file
@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (C) 2010 LunarG Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Chia-I Wu <olv@lunarg.com>
|
||||
*/
|
||||
|
||||
#ifndef EGLUT_H
|
||||
#define EGLUT_H
|
||||
|
||||
/* used by eglutInitAPIMask */
|
||||
enum {
|
||||
EGLUT_OPENGL_BIT = 0x1,
|
||||
EGLUT_OPENGL_ES1_BIT = 0x2,
|
||||
EGLUT_OPENGL_ES2_BIT = 0x4,
|
||||
EGLUT_OPENVG_BIT = 0x8
|
||||
};
|
||||
|
||||
/* used by EGLUTspecialCB */
|
||||
enum {
|
||||
/* function keys */
|
||||
EGLUT_KEY_F1,
|
||||
EGLUT_KEY_F2,
|
||||
EGLUT_KEY_F3,
|
||||
EGLUT_KEY_F4,
|
||||
EGLUT_KEY_F5,
|
||||
EGLUT_KEY_F6,
|
||||
EGLUT_KEY_F7,
|
||||
EGLUT_KEY_F8,
|
||||
EGLUT_KEY_F9,
|
||||
EGLUT_KEY_F10,
|
||||
EGLUT_KEY_F11,
|
||||
EGLUT_KEY_F12,
|
||||
|
||||
/* directional keys */
|
||||
EGLUT_KEY_LEFT,
|
||||
EGLUT_KEY_UP,
|
||||
EGLUT_KEY_RIGHT,
|
||||
EGLUT_KEY_DOWN,
|
||||
};
|
||||
|
||||
/* used by eglutGet */
|
||||
enum {
|
||||
EGLUT_ELAPSED_TIME,
|
||||
EGLUT_FULLSCREEN_MODE
|
||||
};
|
||||
|
||||
/* used by EGLUTkeyboardCB */
|
||||
enum {
|
||||
EGLUT_KEY_PRESS,
|
||||
EGLUT_KEY_RELEASE,
|
||||
EGLUT_KEY_REPEAT
|
||||
};
|
||||
|
||||
/* used by EGLUTmouseButtonCB */
|
||||
enum {
|
||||
EGLUT_MOUSE_PRESS,
|
||||
EGLUT_MOUSE_RELEASE
|
||||
};
|
||||
|
||||
enum {
|
||||
EGLUT_POINTER_INVISIBLE = 0,
|
||||
EGLUT_POINTER_VISIBLE = 1
|
||||
};
|
||||
|
||||
enum {
|
||||
EGLUT_WINDOWED = 0,
|
||||
EGLUT_FULLSCREEN = 1
|
||||
};
|
||||
|
||||
typedef void (*EGLUTidleCB)(void);
|
||||
typedef void (*EGLUTreshapeCB)(int, int);
|
||||
typedef void (*EGLUTdisplayCB)(void);
|
||||
typedef void (*EGLUTkeyboardCB)(char[5], int);
|
||||
typedef void (*EGLUTspecialCB)(int, int);
|
||||
typedef void (*EGLUTmouseCB)(int, int);
|
||||
typedef void (*EGLUTmouseButtonCB)(int, int, int, int);
|
||||
typedef void (*EGLUTcloseCB)(void);
|
||||
|
||||
void eglutInitAPIMask(int mask);
|
||||
void eglutInitWindowSize(int width, int height);
|
||||
void eglutInit(int argc, char **argv);
|
||||
|
||||
int eglutGet(int state);
|
||||
|
||||
void eglutIdleFunc(EGLUTidleCB func);
|
||||
void eglutPostRedisplay(void);
|
||||
|
||||
void eglutMainLoop(void);
|
||||
void eglutFini(void);
|
||||
|
||||
int eglutCreateWindow(const char *title);
|
||||
void eglutDestroyWindow(int win);
|
||||
|
||||
int eglutGetWindowWidth(void);
|
||||
int eglutGetWindowHeight(void);
|
||||
int eglutToggleFullscreen(void);
|
||||
|
||||
void eglutDisplayFunc(EGLUTdisplayCB func);
|
||||
void eglutReshapeFunc(EGLUTreshapeCB func);
|
||||
void eglutKeyboardFunc(EGLUTkeyboardCB func);
|
||||
void eglutSpecialFunc(EGLUTspecialCB func);
|
||||
void eglutMouseFunc(EGLUTmouseCB func);
|
||||
void eglutMouseButtonFunc(EGLUTmouseButtonCB func);
|
||||
void eglutCloseWindowFunc(EGLUTcloseCB func);
|
||||
|
||||
void eglutWarpMousePointer(int x, int y);
|
||||
void eglutSetMousePointerVisiblity(int visible);
|
||||
|
||||
#endif /* EGLUT_H */
|
||||
222
eglut/eglut_wayland.c
Normal file
222
eglut/eglut_wayland.c
Normal file
@ -0,0 +1,222 @@
|
||||
#include <wayland-client.h>
|
||||
#include <wayland-egl.h>
|
||||
|
||||
#include <poll.h>
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "eglutint.h"
|
||||
|
||||
struct display {
|
||||
struct wl_display *display;
|
||||
struct wl_compositor *compositor;
|
||||
struct wl_shell *shell;
|
||||
uint32_t mask;
|
||||
};
|
||||
|
||||
struct window {
|
||||
struct wl_surface *surface;
|
||||
struct wl_shell_surface *shell_surface;
|
||||
struct wl_callback *callback;
|
||||
};
|
||||
|
||||
static struct display display = {0, };
|
||||
static struct window window = {0, };
|
||||
|
||||
static void
|
||||
registry_handle_global(void *data, struct wl_registry *registry, uint32_t id,
|
||||
const char *interface, uint32_t version)
|
||||
{
|
||||
struct display *d = data;
|
||||
|
||||
if (strcmp(interface, "wl_compositor") == 0) {
|
||||
d->compositor =
|
||||
wl_registry_bind(registry, id, &wl_compositor_interface, 1);
|
||||
} else if (strcmp(interface, "wl_shell") == 0) {
|
||||
d->shell = wl_registry_bind(registry, id, &wl_shell_interface, 1);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
registry_handle_global_remove(void *data, struct wl_registry *registry,
|
||||
uint32_t name)
|
||||
{
|
||||
}
|
||||
|
||||
static const struct wl_registry_listener registry_listener = {
|
||||
registry_handle_global,
|
||||
registry_handle_global_remove
|
||||
};
|
||||
|
||||
static void
|
||||
sync_callback(void *data, struct wl_callback *callback, uint32_t serial)
|
||||
{
|
||||
int *done = data;
|
||||
|
||||
*done = 1;
|
||||
wl_callback_destroy(callback);
|
||||
}
|
||||
|
||||
static const struct wl_callback_listener sync_listener = {
|
||||
sync_callback
|
||||
};
|
||||
|
||||
static int
|
||||
wayland_roundtrip(struct wl_display *display)
|
||||
{
|
||||
struct wl_callback *callback;
|
||||
int done = 0, ret = 0;
|
||||
|
||||
callback = wl_display_sync(display);
|
||||
wl_callback_add_listener(callback, &sync_listener, &done);
|
||||
while (ret != -1 && !done)
|
||||
ret = wl_display_dispatch(display);
|
||||
|
||||
if (!done)
|
||||
wl_callback_destroy(callback);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
_eglutNativeInitDisplay(void)
|
||||
{
|
||||
struct wl_registry *registry;
|
||||
|
||||
_eglut->native_dpy = display.display = wl_display_connect(NULL);
|
||||
|
||||
if (!_eglut->native_dpy)
|
||||
_eglutFatal("failed to initialize native display");
|
||||
|
||||
registry = wl_display_get_registry(_eglut->native_dpy);
|
||||
wl_registry_add_listener(registry, ®istry_listener, &display);
|
||||
wayland_roundtrip(_eglut->native_dpy);
|
||||
wl_registry_destroy(registry);
|
||||
|
||||
_eglut->surface_type = EGL_WINDOW_BIT;
|
||||
}
|
||||
|
||||
void
|
||||
_eglutNativeFiniDisplay(void)
|
||||
{
|
||||
wl_display_flush(_eglut->native_dpy);
|
||||
wl_display_disconnect(_eglut->native_dpy);
|
||||
}
|
||||
|
||||
void
|
||||
_eglutNativeInitWindow(struct eglut_window *win, const char *title,
|
||||
int x, int y, int w, int h)
|
||||
{
|
||||
struct wl_egl_window *native;
|
||||
struct wl_region *region;
|
||||
|
||||
window.surface = wl_compositor_create_surface(display.compositor);
|
||||
|
||||
region = wl_compositor_create_region(display.compositor);
|
||||
wl_region_add(region, 0, 0, w, h);
|
||||
wl_surface_set_opaque_region(window.surface, region);
|
||||
wl_region_destroy(region);
|
||||
|
||||
window.shell_surface = wl_shell_get_shell_surface(display.shell,
|
||||
window.surface);
|
||||
native = wl_egl_window_create(window.surface, w, h);
|
||||
|
||||
wl_shell_surface_set_toplevel(window.shell_surface);
|
||||
|
||||
win->native.u.window = native;
|
||||
win->native.width = w;
|
||||
win->native.height = h;
|
||||
}
|
||||
|
||||
void
|
||||
_eglutNativeFiniWindow(struct eglut_window *win)
|
||||
{
|
||||
wl_egl_window_destroy(win->native.u.window);
|
||||
|
||||
wl_shell_surface_destroy(window.shell_surface);
|
||||
wl_surface_destroy(window.surface);
|
||||
|
||||
if (window.callback)
|
||||
wl_callback_destroy(window.callback);
|
||||
}
|
||||
|
||||
static void
|
||||
draw(void *data, struct wl_callback *callback, uint32_t time);
|
||||
|
||||
static const struct wl_callback_listener frame_listener = {
|
||||
draw
|
||||
};
|
||||
|
||||
static void
|
||||
draw(void *data, struct wl_callback *callback, uint32_t time)
|
||||
{
|
||||
struct window *window = (struct window *)data;
|
||||
struct eglut_window *win = _eglut->current;
|
||||
|
||||
if (win->display_cb)
|
||||
win->display_cb();
|
||||
eglSwapBuffers(_eglut->dpy, win->surface);
|
||||
|
||||
if (callback)
|
||||
wl_callback_destroy(callback);
|
||||
|
||||
window->callback = wl_surface_frame(window->surface);
|
||||
wl_callback_add_listener(window->callback, &frame_listener, window);
|
||||
}
|
||||
|
||||
void
|
||||
_eglutNativeEventLoop(void)
|
||||
{
|
||||
struct pollfd pollfd;
|
||||
int ret;
|
||||
|
||||
draw(&window, NULL, 0);
|
||||
|
||||
pollfd.fd = wl_display_get_fd(display.display);
|
||||
pollfd.events = POLLIN;
|
||||
pollfd.revents = 0;
|
||||
|
||||
while (1) {
|
||||
wl_display_dispatch_pending(display.display);
|
||||
|
||||
if (_eglut->idle_cb)
|
||||
_eglut->idle_cb();
|
||||
|
||||
ret = wl_display_flush(display.display);
|
||||
if (ret < 0 && errno == EAGAIN)
|
||||
pollfd.events |= POLLOUT;
|
||||
else if (ret < 0)
|
||||
break;
|
||||
|
||||
if (poll(&pollfd, 1, _eglut->redisplay ? 0 : -1) == -1)
|
||||
break;
|
||||
|
||||
if (pollfd.revents & (POLLERR | POLLHUP))
|
||||
break;
|
||||
|
||||
if (pollfd.revents & POLLIN) {
|
||||
ret = wl_display_dispatch(display.display);
|
||||
if (ret == -1)
|
||||
break;
|
||||
}
|
||||
|
||||
if (pollfd.revents & POLLOUT) {
|
||||
ret = wl_display_flush(display.display);
|
||||
if (ret == 0)
|
||||
pollfd.events &= ~POLLOUT;
|
||||
else if (ret == -1 && errno != EAGAIN)
|
||||
break;
|
||||
}
|
||||
|
||||
if (_eglut->redisplay) {
|
||||
struct eglut_window *win = _eglut->current;
|
||||
|
||||
_eglut->redisplay = 0;
|
||||
|
||||
if (win->display_cb)
|
||||
win->display_cb();
|
||||
|
||||
eglSwapBuffers(_eglut->dpy, win->surface);
|
||||
}
|
||||
}
|
||||
}
|
||||
378
eglut/eglut_x11.c
Normal file
378
eglut/eglut_x11.c
Normal file
@ -0,0 +1,378 @@
|
||||
/*
|
||||
* Copyright (C) 2010 LunarG Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Chia-I Wu <olv@lunarg.com>
|
||||
*/
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/keysym.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "eglutint.h"
|
||||
|
||||
void
|
||||
_eglutNativeInitDisplay(void)
|
||||
{
|
||||
_eglut->native_dpy = XOpenDisplay(_eglut->display_name);
|
||||
if (!_eglut->native_dpy)
|
||||
_eglutFatal("failed to initialize native display");
|
||||
|
||||
_eglut->surface_type = EGL_WINDOW_BIT;
|
||||
}
|
||||
|
||||
void
|
||||
_eglutNativeFiniDisplay(void)
|
||||
{
|
||||
XCloseDisplay(_eglut->native_dpy);
|
||||
_eglut->native_dpy = NULL;
|
||||
}
|
||||
|
||||
XIC x11_ic;
|
||||
|
||||
void
|
||||
_eglutNativeInitWindow(struct eglut_window *win, const char *title,
|
||||
int x, int y, int w, int h)
|
||||
{
|
||||
XVisualInfo *visInfo, visTemplate;
|
||||
int num_visuals;
|
||||
Window root, xwin;
|
||||
XSetWindowAttributes attr;
|
||||
unsigned long mask;
|
||||
EGLint vid;
|
||||
|
||||
if (!eglGetConfigAttrib(_eglut->dpy,
|
||||
win->config, EGL_NATIVE_VISUAL_ID, &vid))
|
||||
_eglutFatal("failed to get visual id");
|
||||
|
||||
/* The X window visual must match the EGL config */
|
||||
visTemplate.visualid = vid;
|
||||
visInfo = XGetVisualInfo(_eglut->native_dpy,
|
||||
VisualIDMask, &visTemplate, &num_visuals);
|
||||
if (!visInfo)
|
||||
_eglutFatal("failed to get an visual of id 0x%x", vid);
|
||||
|
||||
root = RootWindow(_eglut->native_dpy, DefaultScreen(_eglut->native_dpy));
|
||||
|
||||
/* window attributes */
|
||||
attr.background_pixel = 0;
|
||||
attr.border_pixel = 0;
|
||||
attr.colormap = XCreateColormap(_eglut->native_dpy,
|
||||
root, visInfo->visual, AllocNone);
|
||||
attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask | KeyReleaseMask | PointerMotionMask | ButtonPressMask | ButtonReleaseMask;
|
||||
mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
|
||||
|
||||
xwin = XCreateWindow(_eglut->native_dpy, root, x, y, w, h,
|
||||
0, visInfo->depth, InputOutput, visInfo->visual, mask, &attr);
|
||||
if (!xwin)
|
||||
_eglutFatal("failed to create a window");
|
||||
|
||||
XFree(visInfo);
|
||||
|
||||
/* set hints and properties */
|
||||
{
|
||||
XSizeHints sizehints;
|
||||
sizehints.x = x;
|
||||
sizehints.y = y;
|
||||
sizehints.width = w;
|
||||
sizehints.height = h;
|
||||
sizehints.flags = USSize | USPosition;
|
||||
XSetNormalHints(_eglut->native_dpy, xwin, &sizehints);
|
||||
XSetStandardProperties(_eglut->native_dpy, xwin,
|
||||
title, title, None, (char **) NULL, 0, &sizehints);
|
||||
}
|
||||
|
||||
XMapWindow(_eglut->native_dpy, xwin);
|
||||
|
||||
win->native.u.window = xwin;
|
||||
win->native.width = w;
|
||||
win->native.height = h;
|
||||
|
||||
Atom WM_DELETE_WINDOW = XInternAtom(_eglut->native_dpy, "WM_DELETE_WINDOW", False);
|
||||
XSetWMProtocols(_eglut->native_dpy, xwin, &WM_DELETE_WINDOW, 1);
|
||||
|
||||
XIM im = XOpenIM(_eglut->native_dpy, NULL, NULL, NULL);
|
||||
if (im != NULL) {
|
||||
x11_ic = XCreateIC(im, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, xwin, NULL);
|
||||
if (x11_ic != NULL) {
|
||||
XSetICFocus(x11_ic);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_eglutNativeFiniWindow(struct eglut_window *win)
|
||||
{
|
||||
XDestroyWindow(_eglut->native_dpy, win->native.u.window);
|
||||
}
|
||||
|
||||
static int
|
||||
lookup_keysym(KeySym sym)
|
||||
{
|
||||
int special;
|
||||
|
||||
switch (sym) {
|
||||
case XK_F1:
|
||||
special = EGLUT_KEY_F1;
|
||||
break;
|
||||
case XK_F2:
|
||||
special = EGLUT_KEY_F2;
|
||||
break;
|
||||
case XK_F3:
|
||||
special = EGLUT_KEY_F3;
|
||||
break;
|
||||
case XK_F4:
|
||||
special = EGLUT_KEY_F4;
|
||||
break;
|
||||
case XK_F5:
|
||||
special = EGLUT_KEY_F5;
|
||||
break;
|
||||
case XK_F6:
|
||||
special = EGLUT_KEY_F6;
|
||||
break;
|
||||
case XK_F7:
|
||||
special = EGLUT_KEY_F7;
|
||||
break;
|
||||
case XK_F8:
|
||||
special = EGLUT_KEY_F8;
|
||||
break;
|
||||
case XK_F9:
|
||||
special = EGLUT_KEY_F9;
|
||||
break;
|
||||
case XK_F10:
|
||||
special = EGLUT_KEY_F10;
|
||||
break;
|
||||
case XK_F11:
|
||||
special = EGLUT_KEY_F11;
|
||||
break;
|
||||
case XK_F12:
|
||||
special = EGLUT_KEY_F12;
|
||||
break;
|
||||
case XK_KP_Left:
|
||||
case XK_Left:
|
||||
special = EGLUT_KEY_LEFT;
|
||||
break;
|
||||
case XK_KP_Up:
|
||||
case XK_Up:
|
||||
special = EGLUT_KEY_UP;
|
||||
break;
|
||||
case XK_KP_Right:
|
||||
case XK_Right:
|
||||
special = EGLUT_KEY_RIGHT;
|
||||
break;
|
||||
case XK_KP_Down:
|
||||
case XK_Down:
|
||||
special = EGLUT_KEY_DOWN;
|
||||
break;
|
||||
default:
|
||||
special = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
return special;
|
||||
}
|
||||
|
||||
static void
|
||||
next_event(struct eglut_window *win)
|
||||
{
|
||||
int redraw = 0;
|
||||
XEvent event, ahead;
|
||||
|
||||
if (!XPending(_eglut->native_dpy)) {
|
||||
/* there is an idle callback */
|
||||
if (_eglut->idle_cb) {
|
||||
_eglut->idle_cb();
|
||||
return;
|
||||
}
|
||||
|
||||
/* the app requests re-display */
|
||||
if (_eglut->redisplay)
|
||||
return;
|
||||
}
|
||||
|
||||
/* block for next event */
|
||||
XNextEvent(_eglut->native_dpy, &event);
|
||||
|
||||
if (XFilterEvent(&event, win->native.u.window)) {
|
||||
_eglut->redisplay = redraw;
|
||||
return;
|
||||
}
|
||||
|
||||
switch (event.type) {
|
||||
case Expose:
|
||||
redraw = 1;
|
||||
break;
|
||||
case ConfigureNotify:
|
||||
win->native.width = event.xconfigure.width;
|
||||
win->native.height = event.xconfigure.height;
|
||||
if (win->reshape_cb)
|
||||
win->reshape_cb(win->native.width, win->native.height);
|
||||
break;
|
||||
case KeyPress:
|
||||
case KeyRelease:
|
||||
{
|
||||
char buffer[5];
|
||||
memset(buffer, 0, 5);
|
||||
KeySym sym;
|
||||
int r;
|
||||
int type;
|
||||
if (event.type == KeyPress) {
|
||||
r = Xutf8LookupString(x11_ic, (XKeyPressedEvent*) &event, buffer, sizeof(buffer), &sym, NULL);
|
||||
type = EGLUT_KEY_PRESS;
|
||||
} else {
|
||||
r = XLookupString(&event.xkey, buffer, sizeof(buffer), &sym, NULL);
|
||||
type = EGLUT_KEY_RELEASE;
|
||||
}
|
||||
|
||||
if (event.type == KeyRelease) {
|
||||
if (XEventsQueued(_eglut->native_dpy, QueuedAfterReading)) {
|
||||
XPeekEvent(_eglut->native_dpy, &ahead);
|
||||
if (ahead.type == KeyPress &&
|
||||
ahead.xkey.window == event.xkey.window &&
|
||||
ahead.xkey.keycode == event.xkey.keycode &&
|
||||
ahead.xkey.time == event.xkey.time) {
|
||||
type = EGLUT_KEY_REPEAT;
|
||||
XNextEvent(_eglut->native_dpy, &event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (r > 0 && win->keyboard_cb) {
|
||||
win->keyboard_cb(buffer, type);
|
||||
}
|
||||
|
||||
if (win->special_cb) {
|
||||
/*r = lookup_keysym(sym);
|
||||
if (r == -1)*/
|
||||
r = sym;
|
||||
if (r >= 0)
|
||||
win->special_cb(r, type);
|
||||
}
|
||||
if (type != EGLUT_KEY_REPEAT)
|
||||
redraw = 1;
|
||||
break;
|
||||
}
|
||||
case MotionNotify:
|
||||
{
|
||||
if (win->mouse_cb)
|
||||
win->mouse_cb(event.xmotion.x, event.xmotion.y);
|
||||
break;
|
||||
}
|
||||
case ButtonPress:
|
||||
{
|
||||
if (win->mouse_button_cb)
|
||||
win->mouse_button_cb(event.xbutton.x, event.xbutton.y, event.xbutton.button, EGLUT_MOUSE_PRESS);
|
||||
break;
|
||||
}
|
||||
case ButtonRelease:
|
||||
{
|
||||
if (win->mouse_button_cb)
|
||||
win->mouse_button_cb(event.xbutton.x, event.xbutton.y, event.xbutton.button, EGLUT_MOUSE_RELEASE);
|
||||
break;
|
||||
}
|
||||
case ClientMessage:
|
||||
{
|
||||
if ((ulong) event.xclient.data.l[0] == XInternAtom(_eglut->native_dpy, "WM_DELETE_WINDOW", False)) {
|
||||
if (win->close_cb) {
|
||||
win->close_cb();
|
||||
} else {
|
||||
if (_eglut->current)
|
||||
eglutDestroyWindow(_eglut->current->index);
|
||||
eglutFini();
|
||||
}
|
||||
}
|
||||
}
|
||||
default:
|
||||
; /*no-op*/
|
||||
}
|
||||
|
||||
_eglut->redisplay = redraw;
|
||||
}
|
||||
|
||||
void
|
||||
_eglutNativeEventLoop(void)
|
||||
{
|
||||
while (1) {
|
||||
struct eglut_window *win = _eglut->current;
|
||||
|
||||
if (_eglut->native_dpy == NULL)
|
||||
break;
|
||||
|
||||
next_event(win);
|
||||
|
||||
if (_eglut->redisplay) {
|
||||
_eglut->redisplay = 0;
|
||||
|
||||
if (win->display_cb)
|
||||
win->display_cb();
|
||||
eglSwapBuffers(_eglut->dpy, win->surface);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void eglutWarpMousePointer(int x, int y) {
|
||||
XWarpPointer(_eglut->native_dpy, None, _eglut->current->native.u.window, 0, 0, 0, 0, x, y);
|
||||
XFlush(_eglut->native_dpy);
|
||||
}
|
||||
|
||||
void eglutSetMousePointerVisiblity(int visible) {
|
||||
if (visible == EGLUT_POINTER_INVISIBLE) {
|
||||
char emptyData[] = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
XColor black;
|
||||
black.red = 0;
|
||||
black.green = 0;
|
||||
black.blue = 0;
|
||||
Pixmap emptyBitmap = XCreateBitmapFromData(_eglut->native_dpy, _eglut->current->native.u.window, emptyData, 8, 8);
|
||||
Cursor cursor = XCreatePixmapCursor(_eglut->native_dpy, emptyBitmap, emptyBitmap, &black, &black, 0, 0);
|
||||
XDefineCursor(_eglut->native_dpy, _eglut->current->native.u.window, cursor);
|
||||
XFreeCursor(_eglut->native_dpy, cursor);
|
||||
XFreePixmap(_eglut->native_dpy, emptyBitmap);
|
||||
} else if (visible == EGLUT_POINTER_VISIBLE) {
|
||||
XUndefineCursor(_eglut->native_dpy, _eglut->current->native.u.window);
|
||||
}
|
||||
}
|
||||
int eglutToggleFullscreen()
|
||||
{
|
||||
// http://stackoverflow.com/questions/10897503/opening-a-fullscreen-opengl-window
|
||||
_eglut->window_fullscreen = (_eglut->window_fullscreen == EGLUT_WINDOWED ? EGLUT_FULLSCREEN : EGLUT_WINDOWED);
|
||||
Atom wm_state = XInternAtom(_eglut->native_dpy, "_NET_WM_STATE", False);
|
||||
Atom fullscreen = XInternAtom(_eglut->native_dpy, "_NET_WM_STATE_FULLSCREEN", False);
|
||||
|
||||
XEvent xev;
|
||||
memset(&xev, 0, sizeof(xev));
|
||||
xev.type = ClientMessage;
|
||||
xev.xclient.window = _eglut->current->native.u.window;
|
||||
xev.xclient.message_type = wm_state;
|
||||
xev.xclient.format = 32;
|
||||
xev.xclient.data.l[0] = _eglut->window_fullscreen;
|
||||
xev.xclient.data.l[1] = fullscreen;
|
||||
xev.xclient.data.l[2] = 0;
|
||||
|
||||
XMapWindow(_eglut->native_dpy, _eglut->current->native.u.window);
|
||||
|
||||
XSendEvent (_eglut->native_dpy, DefaultRootWindow(_eglut->native_dpy), False,
|
||||
SubstructureRedirectMask | SubstructureNotifyMask, &xev);
|
||||
|
||||
XFlush(_eglut->native_dpy);
|
||||
return -1;
|
||||
}
|
||||
107
eglut/eglutint.h
Normal file
107
eglut/eglutint.h
Normal file
@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (C) 2010 LunarG Inc.
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a
|
||||
* copy of this software and associated documentation files (the "Software"),
|
||||
* to deal in the Software without restriction, including without limitation
|
||||
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||
* and/or sell copies of the Software, and to permit persons to whom the
|
||||
* Software is furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included
|
||||
* in all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
* Authors:
|
||||
* Chia-I Wu <olv@lunarg.com>
|
||||
*/
|
||||
|
||||
#ifndef _EGLUTINT_H_
|
||||
#define _EGLUTINT_H_
|
||||
|
||||
#include "EGL/egl.h"
|
||||
#include "eglut.h"
|
||||
|
||||
struct eglut_window {
|
||||
EGLConfig config;
|
||||
EGLContext context;
|
||||
|
||||
/* initialized by native display */
|
||||
struct {
|
||||
union {
|
||||
EGLNativeWindowType window;
|
||||
EGLNativePixmapType pixmap;
|
||||
EGLSurface surface; /* pbuffer or screen surface */
|
||||
} u;
|
||||
int width, height;
|
||||
} native;
|
||||
|
||||
EGLSurface surface;
|
||||
|
||||
int index;
|
||||
|
||||
EGLUTreshapeCB reshape_cb;
|
||||
EGLUTdisplayCB display_cb;
|
||||
EGLUTkeyboardCB keyboard_cb;
|
||||
EGLUTspecialCB special_cb;
|
||||
EGLUTmouseCB mouse_cb;
|
||||
EGLUTmouseButtonCB mouse_button_cb;
|
||||
EGLUTcloseCB close_cb;
|
||||
};
|
||||
|
||||
struct eglut_state {
|
||||
int api_mask;
|
||||
int window_width, window_height;
|
||||
int window_fullscreen;
|
||||
const char *display_name;
|
||||
int verbose;
|
||||
int init_time;
|
||||
|
||||
EGLUTidleCB idle_cb;
|
||||
|
||||
int num_windows;
|
||||
|
||||
/* initialized by native display */
|
||||
EGLNativeDisplayType native_dpy;
|
||||
EGLint surface_type;
|
||||
|
||||
EGLDisplay dpy;
|
||||
EGLint major, minor;
|
||||
|
||||
struct eglut_window *current;
|
||||
|
||||
int redisplay;
|
||||
};
|
||||
|
||||
extern struct eglut_state *_eglut;
|
||||
|
||||
void
|
||||
_eglutFatal(char *format, ...);
|
||||
|
||||
int
|
||||
_eglutNow(void);
|
||||
|
||||
void
|
||||
_eglutNativeInitDisplay(void);
|
||||
|
||||
void
|
||||
_eglutNativeFiniDisplay(void);
|
||||
|
||||
void
|
||||
_eglutNativeInitWindow(struct eglut_window *win, const char *title,
|
||||
int x, int y, int w, int h);
|
||||
|
||||
void
|
||||
_eglutNativeFiniWindow(struct eglut_window *win);
|
||||
|
||||
void
|
||||
_eglutNativeEventLoop(void);
|
||||
|
||||
#endif /* _EGLUTINT_H_ */
|
||||
19
extract.sh
Executable file
19
extract.sh
Executable file
@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
if [ -z ${1} ]; then
|
||||
echo "Please specify the archive"
|
||||
exit
|
||||
fi
|
||||
if [ ! -f ${1} ]; then
|
||||
echo "The specified file doesn't exist!"
|
||||
exit
|
||||
fi
|
||||
if ! [[ ${1} =~ \.apk$ ]]; then
|
||||
echo "The file must be an .apk"
|
||||
exit
|
||||
fi
|
||||
|
||||
rm -rf assets/
|
||||
|
||||
unzip "${1}" "assets/*"
|
||||
unzip -p "${1}" lib/x86/libminecraftpe.so > libs/libminecraftpe.so
|
||||
448
hybris/include/hybris/binding.h
Normal file
448
hybris/include/hybris/binding.h
Normal file
@ -0,0 +1,448 @@
|
||||
|
||||
/**
|
||||
* Copyright (C) 2013 Simon Busch <morphis@gravedo.de>
|
||||
* 2012 Canonical Ltd
|
||||
* 2013 Jolla Ltd.
|
||||
*
|
||||
* Auto-generated via "generate_wrapper_macros.py"
|
||||
*
|
||||
* 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.
|
||||
**/
|
||||
|
||||
#ifndef HYBRIS_BINDING_H_
|
||||
#define HYBRIS_BINDING_H_
|
||||
|
||||
/* floating_point_abi.h defines FP_ATTRIB */
|
||||
#include "floating_point_abi.h"
|
||||
|
||||
void *android_dlopen(const char *filename, int flag);
|
||||
void *android_dlsym(void *name, const char *symbol);
|
||||
int android_dlclose(void *handle);
|
||||
const char *android_dlerror(void);
|
||||
int android_dladdr(const void *addr, void *info);
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* XXX AUTO-GENERATED FILE XXX
|
||||
*
|
||||
* Do not edit this file directly, but update the templates in
|
||||
* utils/generate_wrapper_macros.py and run it again to build
|
||||
* an updated version of this header file:
|
||||
*
|
||||
* python utils/generate_wrapper_macros.py > \
|
||||
* hybris/include/hybris/common/binding.h
|
||||
*
|
||||
* If you need macros with more arguments, just customize the
|
||||
* MAX_ARGS variable in generate_wrapper_macros.py.
|
||||
*
|
||||
* XXX AUTO-GENERATED FILE XXX
|
||||
**/
|
||||
|
||||
|
||||
#define HYBRIS_DLSYSM(name, fptr, sym) \
|
||||
if (!name##_handle) \
|
||||
hybris_##name##_initialize(); \
|
||||
if (*(fptr) == NULL) \
|
||||
{ \
|
||||
*(fptr) = (void *) android_dlsym(name##_handle, sym); \
|
||||
}
|
||||
|
||||
#define HYBRIS_LIBRARY_INITIALIZE(name, path) \
|
||||
void *name##_handle; \
|
||||
void hybris_##name##_initialize() \
|
||||
{ \
|
||||
name##_handle = android_dlopen(path, RTLD_LAZY); \
|
||||
}
|
||||
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_FUNCTION0(name, return_type, symbol) \
|
||||
return_type symbol() \
|
||||
{ \
|
||||
static return_type (*f)() FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
return f(); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_FUNCTION1(name, return_type, symbol, a1) \
|
||||
return_type symbol(a1 n1) \
|
||||
{ \
|
||||
static return_type (*f)(a1) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
return f(n1); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_FUNCTION2(name, return_type, symbol, a1, a2) \
|
||||
return_type symbol(a1 n1, a2 n2) \
|
||||
{ \
|
||||
static return_type (*f)(a1, a2) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
return f(n1, n2); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_FUNCTION3(name, return_type, symbol, a1, a2, a3) \
|
||||
return_type symbol(a1 n1, a2 n2, a3 n3) \
|
||||
{ \
|
||||
static return_type (*f)(a1, a2, a3) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
return f(n1, n2, n3); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_FUNCTION4(name, return_type, symbol, a1, a2, a3, a4) \
|
||||
return_type symbol(a1 n1, a2 n2, a3 n3, a4 n4) \
|
||||
{ \
|
||||
static return_type (*f)(a1, a2, a3, a4) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
return f(n1, n2, n3, n4); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_FUNCTION5(name, return_type, symbol, a1, a2, a3, a4, a5) \
|
||||
return_type symbol(a1 n1, a2 n2, a3 n3, a4 n4, a5 n5) \
|
||||
{ \
|
||||
static return_type (*f)(a1, a2, a3, a4, a5) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
return f(n1, n2, n3, n4, n5); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_FUNCTION6(name, return_type, symbol, a1, a2, a3, a4, a5, a6) \
|
||||
return_type symbol(a1 n1, a2 n2, a3 n3, a4 n4, a5 n5, a6 n6) \
|
||||
{ \
|
||||
static return_type (*f)(a1, a2, a3, a4, a5, a6) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
return f(n1, n2, n3, n4, n5, n6); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_FUNCTION7(name, return_type, symbol, a1, a2, a3, a4, a5, a6, a7) \
|
||||
return_type symbol(a1 n1, a2 n2, a3 n3, a4 n4, a5 n5, a6 n6, a7 n7) \
|
||||
{ \
|
||||
static return_type (*f)(a1, a2, a3, a4, a5, a6, a7) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
return f(n1, n2, n3, n4, n5, n6, n7); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_FUNCTION8(name, return_type, symbol, a1, a2, a3, a4, a5, a6, a7, a8) \
|
||||
return_type symbol(a1 n1, a2 n2, a3 n3, a4 n4, a5 n5, a6 n6, a7 n7, a8 n8) \
|
||||
{ \
|
||||
static return_type (*f)(a1, a2, a3, a4, a5, a6, a7, a8) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
return f(n1, n2, n3, n4, n5, n6, n7, n8); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_FUNCTION9(name, return_type, symbol, a1, a2, a3, a4, a5, a6, a7, a8, a9) \
|
||||
return_type symbol(a1 n1, a2 n2, a3 n3, a4 n4, a5 n5, a6 n6, a7 n7, a8 n8, a9 n9) \
|
||||
{ \
|
||||
static return_type (*f)(a1, a2, a3, a4, a5, a6, a7, a8, a9) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
return f(n1, n2, n3, n4, n5, n6, n7, n8, n9); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_FUNCTION10(name, return_type, symbol, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) \
|
||||
return_type symbol(a1 n1, a2 n2, a3 n3, a4 n4, a5 n5, a6 n6, a7 n7, a8 n8, a9 n9, a10 n10) \
|
||||
{ \
|
||||
static return_type (*f)(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
return f(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_FUNCTION11(name, return_type, symbol, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11) \
|
||||
return_type symbol(a1 n1, a2 n2, a3 n3, a4 n4, a5 n5, a6 n6, a7 n7, a8 n8, a9 n9, a10 n10, a11 n11) \
|
||||
{ \
|
||||
static return_type (*f)(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
return f(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_FUNCTION12(name, return_type, symbol, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12) \
|
||||
return_type symbol(a1 n1, a2 n2, a3 n3, a4 n4, a5 n5, a6 n6, a7 n7, a8 n8, a9 n9, a10 n10, a11 n11, a12 n12) \
|
||||
{ \
|
||||
static return_type (*f)(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
return f(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_FUNCTION13(name, return_type, symbol, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13) \
|
||||
return_type symbol(a1 n1, a2 n2, a3 n3, a4 n4, a5 n5, a6 n6, a7 n7, a8 n8, a9 n9, a10 n10, a11 n11, a12 n12, a13 n13) \
|
||||
{ \
|
||||
static return_type (*f)(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
return f(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_FUNCTION14(name, return_type, symbol, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14) \
|
||||
return_type symbol(a1 n1, a2 n2, a3 n3, a4 n4, a5 n5, a6 n6, a7 n7, a8 n8, a9 n9, a10 n10, a11 n11, a12 n12, a13 n13, a14 n14) \
|
||||
{ \
|
||||
static return_type (*f)(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
return f(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_FUNCTION15(name, return_type, symbol, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) \
|
||||
return_type symbol(a1 n1, a2 n2, a3 n3, a4 n4, a5 n5, a6 n6, a7 n7, a8 n8, a9 n9, a10 n10, a11 n11, a12 n12, a13 n13, a14 n14, a15 n15) \
|
||||
{ \
|
||||
static return_type (*f)(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
return f(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_FUNCTION16(name, return_type, symbol, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16) \
|
||||
return_type symbol(a1 n1, a2 n2, a3 n3, a4 n4, a5 n5, a6 n6, a7 n7, a8 n8, a9 n9, a10 n10, a11 n11, a12 n12, a13 n13, a14 n14, a15 n15, a16 n16) \
|
||||
{ \
|
||||
static return_type (*f)(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
return f(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_FUNCTION17(name, return_type, symbol, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17) \
|
||||
return_type symbol(a1 n1, a2 n2, a3 n3, a4 n4, a5 n5, a6 n6, a7 n7, a8 n8, a9 n9, a10 n10, a11 n11, a12 n12, a13 n13, a14 n14, a15 n15, a16 n16, a17 n17) \
|
||||
{ \
|
||||
static return_type (*f)(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
return f(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16, n17); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_FUNCTION18(name, return_type, symbol, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18) \
|
||||
return_type symbol(a1 n1, a2 n2, a3 n3, a4 n4, a5 n5, a6 n6, a7 n7, a8 n8, a9 n9, a10 n10, a11 n11, a12 n12, a13 n13, a14 n14, a15 n15, a16 n16, a17 n17, a18 n18) \
|
||||
{ \
|
||||
static return_type (*f)(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
return f(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16, n17, n18); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_FUNCTION19(name, return_type, symbol, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19) \
|
||||
return_type symbol(a1 n1, a2 n2, a3 n3, a4 n4, a5 n5, a6 n6, a7 n7, a8 n8, a9 n9, a10 n10, a11 n11, a12 n12, a13 n13, a14 n14, a15 n15, a16 n16, a17 n17, a18 n18, a19 n19) \
|
||||
{ \
|
||||
static return_type (*f)(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
return f(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16, n17, n18, n19); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_VOID_FUNCTION0(name, symbol) \
|
||||
void symbol() \
|
||||
{ \
|
||||
static void (*f)() FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
f(); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_VOID_FUNCTION1(name, symbol, a1) \
|
||||
void symbol(a1 n1) \
|
||||
{ \
|
||||
static void (*f)(a1) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
f(n1); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_VOID_FUNCTION2(name, symbol, a1, a2) \
|
||||
void symbol(a1 n1, a2 n2) \
|
||||
{ \
|
||||
static void (*f)(a1, a2) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
f(n1, n2); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_VOID_FUNCTION3(name, symbol, a1, a2, a3) \
|
||||
void symbol(a1 n1, a2 n2, a3 n3) \
|
||||
{ \
|
||||
static void (*f)(a1, a2, a3) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
f(n1, n2, n3); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_VOID_FUNCTION4(name, symbol, a1, a2, a3, a4) \
|
||||
void symbol(a1 n1, a2 n2, a3 n3, a4 n4) \
|
||||
{ \
|
||||
static void (*f)(a1, a2, a3, a4) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
f(n1, n2, n3, n4); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_VOID_FUNCTION5(name, symbol, a1, a2, a3, a4, a5) \
|
||||
void symbol(a1 n1, a2 n2, a3 n3, a4 n4, a5 n5) \
|
||||
{ \
|
||||
static void (*f)(a1, a2, a3, a4, a5) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
f(n1, n2, n3, n4, n5); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_VOID_FUNCTION6(name, symbol, a1, a2, a3, a4, a5, a6) \
|
||||
void symbol(a1 n1, a2 n2, a3 n3, a4 n4, a5 n5, a6 n6) \
|
||||
{ \
|
||||
static void (*f)(a1, a2, a3, a4, a5, a6) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
f(n1, n2, n3, n4, n5, n6); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_VOID_FUNCTION7(name, symbol, a1, a2, a3, a4, a5, a6, a7) \
|
||||
void symbol(a1 n1, a2 n2, a3 n3, a4 n4, a5 n5, a6 n6, a7 n7) \
|
||||
{ \
|
||||
static void (*f)(a1, a2, a3, a4, a5, a6, a7) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
f(n1, n2, n3, n4, n5, n6, n7); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_VOID_FUNCTION8(name, symbol, a1, a2, a3, a4, a5, a6, a7, a8) \
|
||||
void symbol(a1 n1, a2 n2, a3 n3, a4 n4, a5 n5, a6 n6, a7 n7, a8 n8) \
|
||||
{ \
|
||||
static void (*f)(a1, a2, a3, a4, a5, a6, a7, a8) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
f(n1, n2, n3, n4, n5, n6, n7, n8); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_VOID_FUNCTION9(name, symbol, a1, a2, a3, a4, a5, a6, a7, a8, a9) \
|
||||
void symbol(a1 n1, a2 n2, a3 n3, a4 n4, a5 n5, a6 n6, a7 n7, a8 n8, a9 n9) \
|
||||
{ \
|
||||
static void (*f)(a1, a2, a3, a4, a5, a6, a7, a8, a9) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
f(n1, n2, n3, n4, n5, n6, n7, n8, n9); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_VOID_FUNCTION10(name, symbol, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) \
|
||||
void symbol(a1 n1, a2 n2, a3 n3, a4 n4, a5 n5, a6 n6, a7 n7, a8 n8, a9 n9, a10 n10) \
|
||||
{ \
|
||||
static void (*f)(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
f(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_VOID_FUNCTION11(name, symbol, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11) \
|
||||
void symbol(a1 n1, a2 n2, a3 n3, a4 n4, a5 n5, a6 n6, a7 n7, a8 n8, a9 n9, a10 n10, a11 n11) \
|
||||
{ \
|
||||
static void (*f)(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
f(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_VOID_FUNCTION12(name, symbol, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12) \
|
||||
void symbol(a1 n1, a2 n2, a3 n3, a4 n4, a5 n5, a6 n6, a7 n7, a8 n8, a9 n9, a10 n10, a11 n11, a12 n12) \
|
||||
{ \
|
||||
static void (*f)(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
f(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_VOID_FUNCTION13(name, symbol, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13) \
|
||||
void symbol(a1 n1, a2 n2, a3 n3, a4 n4, a5 n5, a6 n6, a7 n7, a8 n8, a9 n9, a10 n10, a11 n11, a12 n12, a13 n13) \
|
||||
{ \
|
||||
static void (*f)(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
f(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_VOID_FUNCTION14(name, symbol, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14) \
|
||||
void symbol(a1 n1, a2 n2, a3 n3, a4 n4, a5 n5, a6 n6, a7 n7, a8 n8, a9 n9, a10 n10, a11 n11, a12 n12, a13 n13, a14 n14) \
|
||||
{ \
|
||||
static void (*f)(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
f(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_VOID_FUNCTION15(name, symbol, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) \
|
||||
void symbol(a1 n1, a2 n2, a3 n3, a4 n4, a5 n5, a6 n6, a7 n7, a8 n8, a9 n9, a10 n10, a11 n11, a12 n12, a13 n13, a14 n14, a15 n15) \
|
||||
{ \
|
||||
static void (*f)(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
f(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_VOID_FUNCTION16(name, symbol, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16) \
|
||||
void symbol(a1 n1, a2 n2, a3 n3, a4 n4, a5 n5, a6 n6, a7 n7, a8 n8, a9 n9, a10 n10, a11 n11, a12 n12, a13 n13, a14 n14, a15 n15, a16 n16) \
|
||||
{ \
|
||||
static void (*f)(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
f(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_VOID_FUNCTION17(name, symbol, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17) \
|
||||
void symbol(a1 n1, a2 n2, a3 n3, a4 n4, a5 n5, a6 n6, a7 n7, a8 n8, a9 n9, a10 n10, a11 n11, a12 n12, a13 n13, a14 n14, a15 n15, a16 n16, a17 n17) \
|
||||
{ \
|
||||
static void (*f)(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
f(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16, n17); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_VOID_FUNCTION18(name, symbol, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18) \
|
||||
void symbol(a1 n1, a2 n2, a3 n3, a4 n4, a5 n5, a6 n6, a7 n7, a8 n8, a9 n9, a10 n10, a11 n11, a12 n12, a13 n13, a14 n14, a15 n15, a16 n16, a17 n17, a18 n18) \
|
||||
{ \
|
||||
static void (*f)(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
f(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16, n17, n18); \
|
||||
}
|
||||
|
||||
|
||||
#define HYBRIS_IMPLEMENT_VOID_FUNCTION19(name, symbol, a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19) \
|
||||
void symbol(a1 n1, a2 n2, a3 n3, a4 n4, a5 n5, a6 n6, a7 n7, a8 n8, a9 n9, a10 n10, a11 n11, a12 n12, a13 n13, a14 n14, a15 n15, a16 n16, a17 n17, a18 n18, a19 n19) \
|
||||
{ \
|
||||
static void (*f)(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11, a12, a13, a14, a15, a16, a17, a18, a19) FP_ATTRIB = NULL; \
|
||||
HYBRIS_DLSYSM(name, &f, #symbol); \
|
||||
f(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16, n17, n18, n19); \
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* XXX AUTO-GENERATED FILE XXX
|
||||
*
|
||||
* Do not edit this file directly, but update the templates in
|
||||
* utils/generate_wrapper_macros.py and run it again to build
|
||||
* an updated version of this header file:
|
||||
*
|
||||
* python utils/generate_wrapper_macros.py > \
|
||||
* hybris/include/hybris/common/binding.h
|
||||
*
|
||||
* If you need macros with more arguments, just customize the
|
||||
* MAX_ARGS variable in generate_wrapper_macros.py.
|
||||
*
|
||||
* XXX AUTO-GENERATED FILE XXX
|
||||
**/
|
||||
|
||||
|
||||
#endif /* HYBRIS_BINDING_H_ */
|
||||
|
||||
39
hybris/include/hybris/dlfcn.h
Normal file
39
hybris/include/hybris/dlfcn.h
Normal file
@ -0,0 +1,39 @@
|
||||
/*
|
||||
* Copyright (c) 2013 Intel Corporation
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HYBRIS_DLFCN_H_
|
||||
#define _HYBRIS_DLFCN_H_
|
||||
|
||||
#include <dlfcn.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void *hybris_dlopen(const char *filename, int flag);
|
||||
void *hybris_dlsym(void *handle, const char *symbol);
|
||||
int hybris_dlclose(void *handle);
|
||||
int hybris_dladdr(const void *addr, Dl_info *info);
|
||||
char *hybris_dlerror(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _HYBRIS_DLFCN_H_
|
||||
|
||||
// vim: noai:ts=4:sw=4:ss=4:expandtab
|
||||
42
hybris/include/hybris/floating_point_abi.h
Normal file
42
hybris/include/hybris/floating_point_abi.h
Normal file
@ -0,0 +1,42 @@
|
||||
/*
|
||||
* Copyright (C) 2013 Jolla Ltd.
|
||||
* Contact: Thomas Perl <thomas.perl@jollamobile.com>
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#ifndef HYBRIS_FLOATING_POINT_ABI_H_
|
||||
#define HYBRIS_FLOATING_POINT_ABI_H_
|
||||
|
||||
/**
|
||||
* Make sure to use FP_ATTRIB on all functions that are loaded from
|
||||
* Android (bionic libc) libraries to make sure floating point arguments
|
||||
* are passed the right way.
|
||||
*
|
||||
* See: http://wiki.debian.org/ArmHardFloatPort/VfpComparison
|
||||
* http://gcc.gnu.org/onlinedocs/gcc/Function-Attributes.html
|
||||
*
|
||||
* It doesn't hurt to have it added for non-floating point arguments and
|
||||
* return types, even though it does not really have any effect.
|
||||
*
|
||||
* If you use the convenience macros in hybris/common/binding.h, your
|
||||
* wrapper functions will automatically make use of this attribute.
|
||||
**/
|
||||
|
||||
#ifdef __ARM_PCS_VFP
|
||||
# define FP_ATTRIB __attribute__((pcs("aapcs")))
|
||||
#else
|
||||
# define FP_ATTRIB
|
||||
#endif
|
||||
|
||||
#endif /* HYBRIS_FLOATING_POINT_ABI_H_ */
|
||||
33
hybris/include/hybris/hook.h
Normal file
33
hybris/include/hybris/hook.h
Normal file
@ -0,0 +1,33 @@
|
||||
/*
|
||||
* Copyright (c) 2013 Intel Corporation
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _HYBRIS_HOOK_H_
|
||||
#define _HYBRIS_HOOK_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void hybris_hook(const char *name, void* func);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // _HYBRIS_HOOK_H_
|
||||
|
||||
// vim: noai:ts=4:sw=4:ss=4:expandtab
|
||||
58
hybris/include/hybris/properties.h
Normal file
58
hybris/include/hybris/properties.h
Normal file
@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Carsten Munk <carsten.munk@gmail.com>
|
||||
* 2013 Simon Busch <morphis@gravedo.de>
|
||||
* 2008 The Android Open Source Project
|
||||
* 2013 Canonical Ltd
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef PROPERTIES_H_
|
||||
#define PROPERTIES_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* Based on Android */
|
||||
#define PROP_SERVICE_NAME "property_service"
|
||||
|
||||
#define PROP_NAME_MAX 32
|
||||
#define PROP_VALUE_MAX 92
|
||||
|
||||
/* Only SETPROP is defined by Android, for GETPROP and LISTPROP to work
|
||||
* an extended Android init service needs to be in place */
|
||||
#define PROP_MSG_SETPROP 1
|
||||
#define PROP_MSG_GETPROP 2
|
||||
#define PROP_MSG_LISTPROP 3
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
typedef struct prop_msg_s {
|
||||
unsigned cmd;
|
||||
char name[PROP_NAME_MAX];
|
||||
char value[PROP_VALUE_MAX];
|
||||
} prop_msg_t;
|
||||
|
||||
int property_set(const char *key, const char *value);
|
||||
int property_get(const char *key, char *value, const char *default_value);
|
||||
int property_list(void (*propfn)(const char *key, const char *value, void *cookie), void *cookie);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif // PROPERTIES_H_
|
||||
278
hybris/src/cache.c
Normal file
278
hybris/src/cache.c
Normal file
@ -0,0 +1,278 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Carsten Munk <carsten.munk@gmail.com>
|
||||
* Copyright (c) 2008 The Android Open Source Project
|
||||
* Copyright (c) 2013 Simon Busch <morphis@gravedo.de>
|
||||
* Copyright (c) 2013 Canonical Ltd
|
||||
* Copyright (c) 2013 Jolla Ltd. <robin.burchell@jollamobile.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "../include/hybris/properties.h"
|
||||
#include "properties_p.h"
|
||||
|
||||
struct hybris_prop_value
|
||||
{
|
||||
char *key;
|
||||
char *value;
|
||||
};
|
||||
|
||||
/* surely enough for anyone */
|
||||
#define MAX_PROPS 1000
|
||||
|
||||
/* the sorted prop array */
|
||||
static struct hybris_prop_value prop_array[MAX_PROPS];
|
||||
|
||||
/* the current highest index in prop_array */
|
||||
static int max_prop;
|
||||
|
||||
/* helpers */
|
||||
static void cache_update();
|
||||
static int prop_qcmp(const void *a, const void *b);
|
||||
static struct hybris_prop_value *cache_find_internal(const char *key);
|
||||
static void cache_add_internal(const char *key, const char *value);
|
||||
static void cache_repopulate_internal(FILE *f);
|
||||
static void cache_empty_internal();
|
||||
static void cache_repopulate_cmdline_internal();
|
||||
|
||||
/* the inode/mtime of the prop cache, used for invalidation */
|
||||
static ino_t static_prop_inode;
|
||||
static time_t static_prop_mtime;
|
||||
|
||||
|
||||
/* public:
|
||||
* find a prop value from the file cache.
|
||||
*
|
||||
* the return value is the value of the given property key, or NULL if the
|
||||
* property key is not found. the returned value is owned by the caller,
|
||||
* and must be freed.
|
||||
*/
|
||||
char *hybris_propcache_find(const char *key)
|
||||
{
|
||||
char *ret = NULL;
|
||||
|
||||
cache_update();
|
||||
|
||||
/* then look up the key and do a copy if we get a result */
|
||||
struct hybris_prop_value *prop = cache_find_internal(key);
|
||||
if (prop)
|
||||
return prop->value;
|
||||
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
|
||||
void hybris_propcache_list(hybris_propcache_list_cb cb, void *cookie)
|
||||
{
|
||||
int n;
|
||||
struct hybris_prop_value *current;
|
||||
|
||||
if (!cb)
|
||||
return;
|
||||
|
||||
cache_update();
|
||||
|
||||
for (n = 0; n < max_prop; n++) {
|
||||
current = &prop_array[n];
|
||||
cb(current->key, current->value, cookie);
|
||||
}
|
||||
}
|
||||
|
||||
static void cache_update()
|
||||
{
|
||||
struct stat st;
|
||||
FILE *f = fopen("/system/build.prop", "r");
|
||||
char *ret = NULL;
|
||||
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
/* before searching, we must first determine whether our cache is valid. if
|
||||
* it isn't, we must discard our results and re-create the cache.
|
||||
*
|
||||
* we use fstat here to avoid a race between stat and something else
|
||||
* touching the file.
|
||||
*/
|
||||
if (fstat(fileno(f), &st) != 0) {
|
||||
perror("cache_find can't stat build.prop");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* TODO: is there any better way to detect changes? */
|
||||
if (static_prop_inode != st.st_ino ||
|
||||
static_prop_mtime != st.st_mtime) {
|
||||
static_prop_inode = st.st_ino;
|
||||
static_prop_mtime = st.st_mtime;
|
||||
|
||||
/* cache is stale. fill it back up with fresh data first. */
|
||||
cache_empty_internal();
|
||||
cache_repopulate_internal(f);
|
||||
cache_repopulate_cmdline_internal();
|
||||
|
||||
/* sort by keys */
|
||||
qsort(prop_array, max_prop, sizeof(struct hybris_prop_value), prop_qcmp);
|
||||
}
|
||||
|
||||
out:
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
/* private:
|
||||
* empties the prop cache, ready for repopulation
|
||||
*/
|
||||
static void cache_empty_internal()
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < max_prop; ++i) {
|
||||
free(prop_array[i].key);
|
||||
free(prop_array[i].value);
|
||||
}
|
||||
|
||||
max_prop = 0;
|
||||
}
|
||||
|
||||
/* private:
|
||||
* compares two hybris_prop_value by key, so as to maintain a qsorted array of
|
||||
* props, and search the array.
|
||||
*/
|
||||
static int prop_qcmp(const void *a, const void *b)
|
||||
{
|
||||
struct hybris_prop_value *aa = (struct hybris_prop_value *)a;
|
||||
struct hybris_prop_value *bb = (struct hybris_prop_value *)b;
|
||||
|
||||
return strcmp(aa->key, bb->key);
|
||||
}
|
||||
|
||||
/* private:
|
||||
* find a given key in the in-memory prop cache.
|
||||
*
|
||||
* returns the value of the given property key, or NULL if the property is not
|
||||
* found. Note that this does not pass ownership of the hybris_prop_value or the
|
||||
* data inside it.
|
||||
*/
|
||||
static struct hybris_prop_value *cache_find_internal(const char *key)
|
||||
{
|
||||
struct hybris_prop_value prop_key;
|
||||
prop_key.key = (char*)key;
|
||||
|
||||
return bsearch(&prop_key, prop_array, max_prop, sizeof(struct hybris_prop_value), prop_qcmp);
|
||||
}
|
||||
|
||||
/* private:
|
||||
* add a given property to the in-memory prop cache for later retrieval.
|
||||
*
|
||||
* both `key' and `value' are copied from the caller.
|
||||
*/
|
||||
static void cache_add_internal(const char *key, const char *value)
|
||||
{
|
||||
/* Skip values that can be bigger than value max */
|
||||
if (strlen(value) >= PROP_VALUE_MAX -1)
|
||||
return;
|
||||
|
||||
/* preserve current behavior of first prop key => match */
|
||||
if (cache_find_internal(key))
|
||||
return;
|
||||
|
||||
prop_array[max_prop].key = strdup(key);
|
||||
prop_array[max_prop++].value = strdup(value);
|
||||
|
||||
if (max_prop >= MAX_PROPS) {
|
||||
fprintf(stderr, "libhybris: ran out of props, increase MAX_PROPS");
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
/* private:
|
||||
* repopulates the prop cache from a given file `f'.
|
||||
*/
|
||||
static void cache_repopulate_internal(FILE *f)
|
||||
{
|
||||
char buf[1024];
|
||||
char *mkey, *value;
|
||||
|
||||
while (fgets(buf, 1024, f) != NULL) {
|
||||
if (strchr(buf, '\r'))
|
||||
*(strchr(buf, '\r')) = '\0';
|
||||
if (strchr(buf, '\n'))
|
||||
*(strchr(buf, '\n')) = '\0';
|
||||
|
||||
mkey = strtok(buf, "=");
|
||||
|
||||
if (!mkey)
|
||||
continue;
|
||||
|
||||
value = strtok(NULL, "=");
|
||||
if (!value)
|
||||
continue;
|
||||
|
||||
cache_add_internal(mkey, value);
|
||||
}
|
||||
}
|
||||
|
||||
/* private:
|
||||
* repopulate the prop cache from /proc/cmdline
|
||||
*/
|
||||
static void cache_repopulate_cmdline_internal()
|
||||
{
|
||||
/* Find a key value from the kernel command line, which is parsed
|
||||
* by Android at init (on an Android working system) */
|
||||
char cmdline[1024];
|
||||
char *ptr;
|
||||
int fd;
|
||||
|
||||
fd = open("/proc/cmdline", O_RDONLY);
|
||||
if (fd >= 0) {
|
||||
int n = read(fd, cmdline, 1023);
|
||||
if (n < 0) n = 0;
|
||||
|
||||
/* get rid of trailing newline, it happens */
|
||||
if (n > 0 && cmdline[n-1] == '\n') n--;
|
||||
|
||||
cmdline[n] = 0;
|
||||
close(fd);
|
||||
} else {
|
||||
cmdline[0] = 0;
|
||||
}
|
||||
|
||||
ptr = cmdline;
|
||||
|
||||
while (ptr && *ptr) {
|
||||
char *x = strchr(ptr, ' ');
|
||||
if (x != 0) *x++ = 0;
|
||||
|
||||
char *name = ptr;
|
||||
ptr = x;
|
||||
|
||||
char *value = strchr(name, '=');
|
||||
int name_len = strlen(name);
|
||||
|
||||
if (value == 0) continue;
|
||||
*value++ = 0;
|
||||
if (name_len == 0) continue;
|
||||
|
||||
if (!strncmp(name, "androidboot.", 12) && name_len > 12) {
|
||||
const char *boot_prop_name = name + 12;
|
||||
char prop[PROP_NAME_MAX];
|
||||
snprintf(prop, sizeof(prop) -1, "ro.%s", boot_prop_name);
|
||||
|
||||
cache_add_internal(prop, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
50
hybris/src/dlfcn.c
Normal file
50
hybris/src/dlfcn.c
Normal file
@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (c) 2013 Intel Corporation
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "../include/hybris/dlfcn.h"
|
||||
#include "../include/hybris/binding.h"
|
||||
|
||||
void *hybris_dlopen(const char *filename, int flag)
|
||||
{
|
||||
return android_dlopen(filename,flag);
|
||||
}
|
||||
|
||||
|
||||
void *hybris_dlsym(void *handle, const char *symbol)
|
||||
{
|
||||
return android_dlsym(handle,symbol);
|
||||
}
|
||||
|
||||
|
||||
int hybris_dlclose(void *handle)
|
||||
{
|
||||
return android_dlclose(handle);
|
||||
}
|
||||
|
||||
|
||||
int hybris_dladdr(const void *addr, Dl_info *info)
|
||||
{
|
||||
return android_dladdr(addr, info);
|
||||
}
|
||||
|
||||
|
||||
char *hybris_dlerror(void)
|
||||
{
|
||||
return android_dlerror();
|
||||
}
|
||||
|
||||
// vim: noai:ts=4:sw=4:ss=4:expandtab
|
||||
1869
hybris/src/hooks.c
Normal file
1869
hybris/src/hooks.c
Normal file
File diff suppressed because it is too large
Load Diff
252
hybris/src/hooks_shm.c
Normal file
252
hybris/src/hooks_shm.c
Normal file
@ -0,0 +1,252 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Carsten Munk <carsten.munk@gmail.com>
|
||||
* Copyright (c) 2013 Christophe Chapuis <chris.chapuis@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "hooks_shm.h"
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <sys/stat.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
#include <sys/mman.h>
|
||||
|
||||
/* Debug */
|
||||
#include "logging.h"
|
||||
#define LOGD(message, ...) HYBRIS_DEBUG_LOG(HOOKS, message, ##__VA_ARGS__)
|
||||
|
||||
#define HYBRIS_DATA_SIZE 4000
|
||||
#define HYBRIS_SHM_MASK 0xFF000000UL
|
||||
#define HYBRIS_SHM_PATH "/hybris_shm_data"
|
||||
|
||||
/* Structure of a shared memory region */
|
||||
typedef struct _hybris_shm_data_t {
|
||||
pthread_mutex_t access_mutex;
|
||||
int current_offset;
|
||||
int max_offset;
|
||||
unsigned char data;
|
||||
} hybris_shm_data_t;
|
||||
|
||||
/* A helper to switch between the size of the data and the size of the shm object */
|
||||
const int HYBRIS_SHM_DATA_HEADER_SIZE = (sizeof(hybris_shm_data_t) - sizeof(unsigned char));
|
||||
|
||||
/* pointer to the shared memory region */
|
||||
static hybris_shm_data_t *_hybris_shm_data = NULL;
|
||||
|
||||
/* the SHM mem_id of the shared memory region */
|
||||
static int _hybris_shm_fd = -1;
|
||||
|
||||
/* the size of the shared memory region that is currently mmap'ed to this process */
|
||||
static int _current_mapped_size = 0;
|
||||
|
||||
/* forward-declare the internal static methods */
|
||||
static void _release_shm(void);
|
||||
static void _sync_mmap_with_shm(void);
|
||||
static void _hybris_shm_init(void);
|
||||
static void _hybris_shm_extend_region(void);
|
||||
|
||||
/*
|
||||
* Detach the allocated memory region, and mark it for deletion
|
||||
*/
|
||||
static void _release_shm(void)
|
||||
{
|
||||
if (_hybris_shm_data) {
|
||||
munmap(_hybris_shm_data, _current_mapped_size); /* unmap from this process */
|
||||
_hybris_shm_data = NULL; /* pointer is no more valid */
|
||||
}
|
||||
if (_hybris_shm_fd >= 0) {
|
||||
close(_hybris_shm_fd); /* close the shm file descriptor */
|
||||
_hybris_shm_fd = -1;
|
||||
}
|
||||
shm_unlink(HYBRIS_SHM_PATH); /* request the deletion of the shm region */
|
||||
}
|
||||
|
||||
/*
|
||||
* Synchronize the size of the mmap with the size of the shm region
|
||||
*/
|
||||
static void _sync_mmap_with_shm()
|
||||
{
|
||||
if (_hybris_shm_fd >= 0 && _hybris_shm_data) {
|
||||
if (_current_mapped_size < _hybris_shm_data->max_offset + HYBRIS_SHM_DATA_HEADER_SIZE) {
|
||||
/* Note that mremap may change the address pointed by _hybris_shm_data.
|
||||
* But as we never point directly into _hybris_shm_data, it's fine.
|
||||
* */
|
||||
_hybris_shm_data = (hybris_shm_data_t *)mremap( _hybris_shm_data, _current_mapped_size,
|
||||
_hybris_shm_data->max_offset + HYBRIS_SHM_DATA_HEADER_SIZE,
|
||||
MREMAP_MAYMOVE );
|
||||
|
||||
_current_mapped_size = _hybris_shm_data->max_offset + HYBRIS_SHM_DATA_HEADER_SIZE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialize the shared memory region for hybris, in order to store
|
||||
* pshared mutex, condition and rwlock
|
||||
*/
|
||||
static void _hybris_shm_init()
|
||||
{
|
||||
if (_hybris_shm_fd < 0) {
|
||||
const size_t size_to_map = HYBRIS_SHM_DATA_HEADER_SIZE + HYBRIS_DATA_SIZE; /* 4000 bytes for the data, plus the header size */
|
||||
|
||||
/* initialize or get shared memory segment */
|
||||
_hybris_shm_fd = shm_open(HYBRIS_SHM_PATH, O_RDWR, 0660);
|
||||
if (_hybris_shm_fd >= 0) {
|
||||
/* Map the memory object */
|
||||
_hybris_shm_data = (hybris_shm_data_t *)mmap( NULL, size_to_map,
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED,
|
||||
_hybris_shm_fd, 0 );
|
||||
_current_mapped_size = size_to_map;
|
||||
|
||||
_sync_mmap_with_shm();
|
||||
}
|
||||
else {
|
||||
LOGD("Creating a new shared memory segment.");
|
||||
|
||||
_hybris_shm_fd = shm_open(HYBRIS_SHM_PATH, O_RDWR | O_CREAT, 0660);
|
||||
if (_hybris_shm_fd >= 0) {
|
||||
ftruncate( _hybris_shm_fd, size_to_map );
|
||||
/* Map the memory object */
|
||||
_hybris_shm_data = (hybris_shm_data_t *)mmap( NULL, size_to_map,
|
||||
PROT_READ | PROT_WRITE, MAP_SHARED,
|
||||
_hybris_shm_fd, 0 );
|
||||
if (_hybris_shm_data == MAP_FAILED) {
|
||||
HYBRIS_ERROR_LOG(HOOKS, "ERROR: mmap failed: %s\n", strerror(errno));
|
||||
_release_shm();
|
||||
}
|
||||
else {
|
||||
_current_mapped_size = size_to_map;
|
||||
/* Initialize the memory object */
|
||||
memset((void*)_hybris_shm_data, 0, size_to_map);
|
||||
_hybris_shm_data->max_offset = HYBRIS_DATA_SIZE;
|
||||
|
||||
pthread_mutexattr_t attr;
|
||||
pthread_mutexattr_init(&attr);
|
||||
pthread_mutexattr_setpshared(&attr, PTHREAD_PROCESS_SHARED);
|
||||
pthread_mutex_init(&_hybris_shm_data->access_mutex, &attr);
|
||||
pthread_mutexattr_destroy(&attr);
|
||||
|
||||
atexit(_release_shm);
|
||||
}
|
||||
}
|
||||
else {
|
||||
HYBRIS_ERROR_LOG(HOOKS, "ERROR: Couldn't create shared memory segment !");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Extend the SHM region's size
|
||||
*/
|
||||
static void _hybris_shm_extend_region()
|
||||
{
|
||||
ftruncate( _hybris_shm_fd, _current_mapped_size + HYBRIS_DATA_SIZE );
|
||||
_hybris_shm_data->max_offset += HYBRIS_DATA_SIZE;
|
||||
|
||||
_sync_mmap_with_shm();
|
||||
}
|
||||
|
||||
/************ public functions *******************/
|
||||
|
||||
/*
|
||||
* Determine if the pointer that has been extracted by hybris is
|
||||
* pointing to an address in the shared memory
|
||||
*/
|
||||
int hybris_is_pointer_in_shm(void *ptr)
|
||||
{
|
||||
if ((unsigned int)ptr >= HYBRIS_SHM_MASK)
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Convert this offset pointer to the shared memory to an
|
||||
* absolute pointer that can be used in user space
|
||||
*/
|
||||
void *hybris_get_shmpointer(hybris_shm_pointer_t handle)
|
||||
{
|
||||
void *realpointer = NULL;
|
||||
if (hybris_is_pointer_in_shm((void*)handle)) {
|
||||
if (_hybris_shm_fd < 0) {
|
||||
/* if we are not yet attached to any shm region, then do it now */
|
||||
_hybris_shm_init();
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&_hybris_shm_data->access_mutex);
|
||||
|
||||
_sync_mmap_with_shm(); /* make sure our mmap is sync'ed */
|
||||
|
||||
if (_hybris_shm_data != NULL) {
|
||||
unsigned int offset = handle & (~HYBRIS_SHM_MASK);
|
||||
realpointer = &(_hybris_shm_data->data) + offset;
|
||||
|
||||
/* Be careful when activating this trace: this method is called *a lot* !
|
||||
LOGD("handle = %x, offset = %d, realpointer = %x)", handle, offset, realpointer);
|
||||
*/
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&_hybris_shm_data->access_mutex);
|
||||
}
|
||||
|
||||
return realpointer;
|
||||
}
|
||||
|
||||
/*
|
||||
* Allocate a space in the shared memory region of hybris
|
||||
*/
|
||||
hybris_shm_pointer_t hybris_shm_alloc(size_t size)
|
||||
{
|
||||
hybris_shm_pointer_t location = 0;
|
||||
|
||||
if (_hybris_shm_fd < 0) {
|
||||
/* if we are not yet attached to any shm region, then do it now */
|
||||
_hybris_shm_init();
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&_hybris_shm_data->access_mutex);
|
||||
|
||||
/* Make sure our mmap is sync'ed */
|
||||
_sync_mmap_with_shm();
|
||||
|
||||
if (_hybris_shm_data == NULL || _hybris_shm_fd < 0)
|
||||
return 0;
|
||||
|
||||
if (_hybris_shm_data->current_offset + size >= _hybris_shm_data->max_offset) {
|
||||
/* the current buffer if full: extend it a little bit more */
|
||||
_hybris_shm_extend_region();
|
||||
_sync_mmap_with_shm();
|
||||
}
|
||||
|
||||
/* there is now enough place in this pool */
|
||||
location = _hybris_shm_data->current_offset | HYBRIS_SHM_MASK;
|
||||
LOGD("Allocated a shared object (size = %d, at offset %d)", size, _hybris_shm_data->current_offset);
|
||||
|
||||
_hybris_shm_data->current_offset += size;
|
||||
|
||||
pthread_mutex_unlock(&_hybris_shm_data->access_mutex);
|
||||
|
||||
return location;
|
||||
}
|
||||
41
hybris/src/hooks_shm.h
Normal file
41
hybris/src/hooks_shm.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Carsten Munk <carsten.munk@gmail.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HOOKS_SHM_H_
|
||||
#define HOOKS_SHM_H_
|
||||
|
||||
#include <stddef.h>
|
||||
|
||||
typedef unsigned int hybris_shm_pointer_t;
|
||||
|
||||
/*
|
||||
* Allocate a space in the shared memory region of hybris
|
||||
*/
|
||||
hybris_shm_pointer_t hybris_shm_alloc(size_t size);
|
||||
/*
|
||||
* Test if the pointers points to the shm region
|
||||
*/
|
||||
int hybris_is_pointer_in_shm(void *ptr);
|
||||
/*
|
||||
* Convert an offset pointer to the shared memory to an absolute pointer that can be used in user space
|
||||
* This function will return a NULL pointer if the handle does not actually point to the shm region
|
||||
*/
|
||||
void *hybris_get_shmpointer(hybris_shm_pointer_t handle);
|
||||
|
||||
#endif
|
||||
|
||||
// vim:ts=4:sw=4:noexpandtab
|
||||
45
hybris/src/jb/arch/arm/begin.S
Normal file
45
hybris/src/jb/arch/arm/begin.S
Normal file
@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
.text
|
||||
.align 4
|
||||
.type _start,#function
|
||||
.globl _start
|
||||
|
||||
_start:
|
||||
mov r0, sp
|
||||
mov r1, #0
|
||||
bl __linker_init
|
||||
|
||||
/* linker init returns the _entry address in the main image */
|
||||
mov pc, r0
|
||||
|
||||
.section .ctors, "wa"
|
||||
.globl __CTOR_LIST__
|
||||
__CTOR_LIST__:
|
||||
.long -1
|
||||
46
hybris/src/jb/arch/x86/begin.S
Normal file
46
hybris/src/jb/arch/x86/begin.S
Normal file
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
.text
|
||||
.align 4
|
||||
.type _start, @function
|
||||
.globl _start
|
||||
|
||||
_start:
|
||||
/* save the elfdata ptr to %eax, AND push it onto the stack */
|
||||
mov %esp, %eax
|
||||
pushl %esp
|
||||
|
||||
pushl %eax
|
||||
call __linker_init
|
||||
|
||||
/* linker init returns (%eax) the _entry address in the main image */
|
||||
/* entry point expects sp to point to elfdata */
|
||||
popl %esp
|
||||
jmp *%eax
|
||||
|
||||
240
hybris/src/jb/debugger.c
Normal file
240
hybris/src/jb/debugger.c
Normal file
@ -0,0 +1,240 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <ctype.h>
|
||||
#include <signal.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/prctl.h>
|
||||
#include <errno.h>
|
||||
|
||||
#include "linker.h"
|
||||
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
|
||||
extern int tgkill(int tgid, int tid, int sig);
|
||||
|
||||
void notify_gdb_of_libraries();
|
||||
|
||||
#define DEBUGGER_SOCKET_NAME "android:debuggerd"
|
||||
|
||||
typedef enum {
|
||||
// dump a crash
|
||||
DEBUGGER_ACTION_CRASH,
|
||||
// dump a tombstone file
|
||||
DEBUGGER_ACTION_DUMP_TOMBSTONE,
|
||||
// dump a backtrace only back to the socket
|
||||
DEBUGGER_ACTION_DUMP_BACKTRACE,
|
||||
} debugger_action_t;
|
||||
|
||||
/* message sent over the socket */
|
||||
typedef struct {
|
||||
debugger_action_t action;
|
||||
pid_t tid;
|
||||
} debugger_msg_t;
|
||||
|
||||
#define RETRY_ON_EINTR(ret,cond) \
|
||||
do { \
|
||||
ret = (cond); \
|
||||
} while (ret < 0 && errno == EINTR)
|
||||
|
||||
// see man(2) prctl, specifically the section about PR_GET_NAME
|
||||
#define MAX_TASK_NAME_LEN (16)
|
||||
|
||||
static int socket_abstract_client(const char *name, int type)
|
||||
{
|
||||
struct sockaddr_un addr;
|
||||
size_t namelen;
|
||||
socklen_t alen;
|
||||
int s, err;
|
||||
|
||||
namelen = strlen(name);
|
||||
|
||||
// Test with length +1 for the *initial* '\0'.
|
||||
if ((namelen + 1) > sizeof(addr.sun_path)) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* This is used for abstract socket namespace, we need
|
||||
* an initial '\0' at the start of the Unix socket path.
|
||||
*
|
||||
* Note: The path in this case is *not* supposed to be
|
||||
* '\0'-terminated. ("man 7 unix" for the gory details.)
|
||||
*/
|
||||
memset (&addr, 0, sizeof addr);
|
||||
addr.sun_family = AF_LOCAL;
|
||||
addr.sun_path[0] = 0;
|
||||
memcpy(addr.sun_path + 1, name, namelen);
|
||||
|
||||
alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
|
||||
|
||||
s = socket(AF_LOCAL, type, 0);
|
||||
if(s < 0) return -1;
|
||||
|
||||
RETRY_ON_EINTR(err,connect(s, (struct sockaddr *) &addr, alen));
|
||||
if (err < 0) {
|
||||
close(s);
|
||||
s = -1;
|
||||
}
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
#include "linker_format.h"
|
||||
#include <../libc/private/logd.h>
|
||||
|
||||
/*
|
||||
* Writes a summary of the signal to the log file.
|
||||
*
|
||||
* We could be here as a result of native heap corruption, or while a
|
||||
* mutex is being held, so we don't want to use any libc functions that
|
||||
* could allocate memory or hold a lock.
|
||||
*/
|
||||
static void logSignalSummary(int signum, const siginfo_t* info)
|
||||
{
|
||||
char buffer[128];
|
||||
char threadname[MAX_TASK_NAME_LEN + 1]; // one more for termination
|
||||
|
||||
char* signame;
|
||||
switch (signum) {
|
||||
case SIGILL: signame = "SIGILL"; break;
|
||||
case SIGABRT: signame = "SIGABRT"; break;
|
||||
case SIGBUS: signame = "SIGBUS"; break;
|
||||
case SIGFPE: signame = "SIGFPE"; break;
|
||||
case SIGSEGV: signame = "SIGSEGV"; break;
|
||||
case SIGSTKFLT: signame = "SIGSTKFLT"; break;
|
||||
case SIGPIPE: signame = "SIGPIPE"; break;
|
||||
default: signame = "???"; break;
|
||||
}
|
||||
|
||||
if (prctl(PR_GET_NAME, (unsigned long)threadname, 0, 0, 0) != 0) {
|
||||
strcpy(threadname, "<name unknown>");
|
||||
} else {
|
||||
// short names are null terminated by prctl, but the manpage
|
||||
// implies that 16 byte names are not.
|
||||
threadname[MAX_TASK_NAME_LEN] = 0;
|
||||
}
|
||||
format_buffer(buffer, sizeof(buffer),
|
||||
"Fatal signal %d (%s) at 0x%08x (code=%d), thread %d (%s)",
|
||||
signum, signame, info->si_addr, info->si_code, gettid(), threadname);
|
||||
|
||||
__libc_android_log_write(ANDROID_LOG_FATAL, "libc", buffer);
|
||||
}
|
||||
|
||||
/*
|
||||
* Catches fatal signals so we can ask debuggerd to ptrace us before
|
||||
* we crash.
|
||||
*/
|
||||
void debugger_signal_handler(int n, siginfo_t* info, void* unused)
|
||||
{
|
||||
char msgbuf[128];
|
||||
unsigned tid;
|
||||
int s;
|
||||
|
||||
logSignalSummary(n, info);
|
||||
|
||||
tid = gettid();
|
||||
s = socket_abstract_client(DEBUGGER_SOCKET_NAME, SOCK_STREAM);
|
||||
|
||||
if (s >= 0) {
|
||||
/* debugger knows our pid from the credentials on the
|
||||
* local socket but we need to tell it our tid. It
|
||||
* is paranoid and will verify that we are giving a tid
|
||||
* that's actually in our process
|
||||
*/
|
||||
int ret;
|
||||
debugger_msg_t msg;
|
||||
msg.action = DEBUGGER_ACTION_CRASH;
|
||||
msg.tid = tid;
|
||||
RETRY_ON_EINTR(ret, write(s, &msg, sizeof(msg)));
|
||||
if (ret == sizeof(msg)) {
|
||||
/* if the write failed, there is no point to read on
|
||||
* the file descriptor. */
|
||||
RETRY_ON_EINTR(ret, read(s, &tid, 1));
|
||||
int savedErrno = errno;
|
||||
notify_gdb_of_libraries();
|
||||
errno = savedErrno;
|
||||
}
|
||||
|
||||
if (ret < 0) {
|
||||
/* read or write failed -- broken connection? */
|
||||
format_buffer(msgbuf, sizeof(msgbuf),
|
||||
"Failed while talking to debuggerd: %s", strerror(errno));
|
||||
__libc_android_log_write(ANDROID_LOG_FATAL, "libc", msgbuf);
|
||||
}
|
||||
|
||||
close(s);
|
||||
} else {
|
||||
/* socket failed; maybe process ran out of fds */
|
||||
format_buffer(msgbuf, sizeof(msgbuf),
|
||||
"Unable to open connection to debuggerd: %s", strerror(errno));
|
||||
__libc_android_log_write(ANDROID_LOG_FATAL, "libc", msgbuf);
|
||||
}
|
||||
|
||||
/* remove our net so we fault for real when we return */
|
||||
signal(n, SIG_DFL);
|
||||
|
||||
/*
|
||||
* These signals are not re-thrown when we resume. This means that
|
||||
* crashing due to (say) SIGPIPE doesn't work the way you'd expect it
|
||||
* to. We work around this by throwing them manually. We don't want
|
||||
* to do this for *all* signals because it'll screw up the address for
|
||||
* faults like SIGSEGV.
|
||||
*/
|
||||
switch (n) {
|
||||
case SIGABRT:
|
||||
case SIGFPE:
|
||||
case SIGPIPE:
|
||||
case SIGSTKFLT:
|
||||
(void) tgkill(getpid(), gettid(), n);
|
||||
break;
|
||||
default: // SIGILL, SIGBUS, SIGSEGV
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void debugger_init()
|
||||
{
|
||||
struct sigaction act;
|
||||
memset(&act, 0, sizeof(act));
|
||||
act.sa_sigaction = debugger_signal_handler;
|
||||
act.sa_flags = SA_RESTART | SA_SIGINFO;
|
||||
sigemptyset(&act.sa_mask);
|
||||
|
||||
sigaction(SIGILL, &act, NULL);
|
||||
sigaction(SIGABRT, &act, NULL);
|
||||
sigaction(SIGBUS, &act, NULL);
|
||||
sigaction(SIGFPE, &act, NULL);
|
||||
sigaction(SIGSEGV, &act, NULL);
|
||||
sigaction(SIGSTKFLT, &act, NULL);
|
||||
sigaction(SIGPIPE, &act, NULL);
|
||||
}
|
||||
286
hybris/src/jb/dlfcn.c
Normal file
286
hybris/src/jb/dlfcn.c
Normal file
@ -0,0 +1,286 @@
|
||||
/*
|
||||
* Copyright (C) 2007 The Android Open Source Project
|
||||
*
|
||||
* 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.
|
||||
*/
|
||||
#define _GNU_SOURCE
|
||||
#include <dlfcn.h>
|
||||
#include <pthread.h>
|
||||
#include <stdio.h>
|
||||
#include "linker.h"
|
||||
#include "linker_format.h"
|
||||
#include <string.h>
|
||||
|
||||
/* This file hijacks the symbols stubbed out in libdl.so. */
|
||||
|
||||
#define DL_SUCCESS 0
|
||||
#define DL_ERR_CANNOT_LOAD_LIBRARY 1
|
||||
#define DL_ERR_INVALID_LIBRARY_HANDLE 2
|
||||
#define DL_ERR_BAD_SYMBOL_NAME 3
|
||||
#define DL_ERR_SYMBOL_NOT_FOUND 4
|
||||
#define DL_ERR_SYMBOL_NOT_GLOBAL 5
|
||||
|
||||
static char dl_err_buf[1024];
|
||||
static const char *dl_err_str;
|
||||
|
||||
static const char *dl_errors[] = {
|
||||
[DL_ERR_CANNOT_LOAD_LIBRARY] = "Cannot load library",
|
||||
[DL_ERR_INVALID_LIBRARY_HANDLE] = "Invalid library handle",
|
||||
[DL_ERR_BAD_SYMBOL_NAME] = "Invalid symbol name",
|
||||
[DL_ERR_SYMBOL_NOT_FOUND] = "Symbol not found",
|
||||
[DL_ERR_SYMBOL_NOT_GLOBAL] = "Symbol is not global",
|
||||
};
|
||||
|
||||
#define likely(expr) __builtin_expect (expr, 1)
|
||||
#define unlikely(expr) __builtin_expect (expr, 0)
|
||||
|
||||
static pthread_mutex_t dl_lock = PTHREAD_RECURSIVE_MUTEX_INITIALIZER_NP;
|
||||
|
||||
static void set_dlerror(int err)
|
||||
{
|
||||
format_buffer(dl_err_buf, sizeof(dl_err_buf), "%s: %s", dl_errors[err],
|
||||
linker_get_error());
|
||||
dl_err_str = (const char *)&dl_err_buf[0];
|
||||
};
|
||||
|
||||
void *android_dlopen(const char *filename, int flag)
|
||||
{
|
||||
soinfo *ret;
|
||||
|
||||
pthread_mutex_lock(&dl_lock);
|
||||
ret = find_library(filename);
|
||||
if (unlikely(ret == NULL)) {
|
||||
set_dlerror(DL_ERR_CANNOT_LOAD_LIBRARY);
|
||||
} else {
|
||||
call_constructors_recursive(ret);
|
||||
ret->refcount++;
|
||||
}
|
||||
pthread_mutex_unlock(&dl_lock);
|
||||
return ret;
|
||||
}
|
||||
|
||||
const char *android_dlerror(void)
|
||||
{
|
||||
const char *tmp = dl_err_str;
|
||||
dl_err_str = NULL;
|
||||
return (const char *)tmp;
|
||||
}
|
||||
|
||||
void *android_dlsym(void *handle, const char *symbol)
|
||||
{
|
||||
soinfo *found;
|
||||
Elf32_Sym *sym;
|
||||
unsigned bind;
|
||||
|
||||
pthread_mutex_lock(&dl_lock);
|
||||
|
||||
if(unlikely(handle == 0)) {
|
||||
set_dlerror(DL_ERR_INVALID_LIBRARY_HANDLE);
|
||||
goto err;
|
||||
}
|
||||
if(unlikely(symbol == 0)) {
|
||||
set_dlerror(DL_ERR_BAD_SYMBOL_NAME);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if(handle == RTLD_DEFAULT) {
|
||||
sym = lookup(symbol, &found, NULL);
|
||||
} else if(handle == RTLD_NEXT) {
|
||||
void *ret_addr = __builtin_return_address(0);
|
||||
soinfo *si = find_containing_library(ret_addr);
|
||||
|
||||
sym = NULL;
|
||||
if(si && si->next) {
|
||||
sym = lookup(symbol, &found, si->next);
|
||||
}
|
||||
} else {
|
||||
found = (soinfo*)handle;
|
||||
sym = lookup_in_library(found, symbol);
|
||||
}
|
||||
|
||||
if(likely(sym != 0)) {
|
||||
bind = ELF32_ST_BIND(sym->st_info);
|
||||
|
||||
if(likely((bind == STB_GLOBAL || bind == STB_WEAK) && (sym->st_shndx != 0))) {
|
||||
unsigned ret = sym->st_value + found->base;
|
||||
pthread_mutex_unlock(&dl_lock);
|
||||
return (void*)ret;
|
||||
}
|
||||
|
||||
set_dlerror(DL_ERR_SYMBOL_NOT_GLOBAL);
|
||||
}
|
||||
else
|
||||
set_dlerror(DL_ERR_SYMBOL_NOT_FOUND);
|
||||
|
||||
err:
|
||||
pthread_mutex_unlock(&dl_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int android_dladdr(const void *addr, Dl_info *info)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
pthread_mutex_lock(&dl_lock);
|
||||
|
||||
/* Determine if this address can be found in any library currently mapped */
|
||||
soinfo *si = find_containing_library(addr);
|
||||
|
||||
if(si) {
|
||||
memset(info, 0, sizeof(Dl_info));
|
||||
|
||||
info->dli_fname = si->name;
|
||||
info->dli_fbase = (void*)si->base;
|
||||
|
||||
/* Determine if any symbol in the library contains the specified address */
|
||||
Elf32_Sym *sym = find_containing_symbol(addr, si);
|
||||
|
||||
if(sym != NULL) {
|
||||
info->dli_sname = si->strtab + sym->st_name;
|
||||
info->dli_saddr = (void*)(si->base + sym->st_value);
|
||||
}
|
||||
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
pthread_mutex_unlock(&dl_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int android_dlclose(void *handle)
|
||||
{
|
||||
pthread_mutex_lock(&dl_lock);
|
||||
(void)unload_library((soinfo*)handle);
|
||||
pthread_mutex_unlock(&dl_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int android_dl_iterate_phdr(int (*cb)(struct dl_phdr_info *info, size_t size, void *data),void *data);
|
||||
|
||||
#if defined(ANDROID_ARM_LINKER)
|
||||
// 0000000 00011111 111112 22222222 2333333 333344444444445555555
|
||||
// 0123456 78901234 567890 12345678 9012345 678901234567890123456
|
||||
#define ANDROID_LIBDL_STRTAB \
|
||||
"dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_unwind_find_exidx\0dl_iterate_phdr\0"
|
||||
|
||||
_Unwind_Ptr android_dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount);
|
||||
|
||||
#elif defined(ANDROID_X86_LINKER)
|
||||
// 0000000 00011111 111112 22222222 2333333 3333444444444455
|
||||
// 0123456 78901234 567890 12345678 9012345 6789012345678901
|
||||
#define ANDROID_LIBDL_STRTAB \
|
||||
"dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_iterate_phdr\0"
|
||||
#elif defined(ANDROID_SH_LINKER)
|
||||
// 0000000 00011111 111112 22222222 2333333 3333444444444455
|
||||
// 0123456 78901234 567890 12345678 9012345 6789012345678901
|
||||
#define ANDROID_LIBDL_STRTAB \
|
||||
"dlopen\0dlclose\0dlsym\0dlerror\0dladdr\0dl_iterate_phdr\0"
|
||||
|
||||
#else /* !defined(ANDROID_ARM_LINKER) && !defined(ANDROID_X86_LINKER) */
|
||||
#error Unsupported architecture. Only ARM and x86 are presently supported.
|
||||
#endif
|
||||
|
||||
|
||||
static Elf32_Sym libdl_symtab[] = {
|
||||
// total length of libdl_info.strtab, including trailing 0
|
||||
// This is actually the the STH_UNDEF entry. Technically, it's
|
||||
// supposed to have st_name == 0, but instead, it points to an index
|
||||
// in the strtab with a \0 to make iterating through the symtab easier.
|
||||
{ st_name: sizeof(ANDROID_LIBDL_STRTAB) - 1,
|
||||
},
|
||||
{ st_name: 0, // starting index of the name in libdl_info.strtab
|
||||
st_value: (Elf32_Addr) &android_dlopen,
|
||||
st_info: STB_GLOBAL << 4,
|
||||
st_shndx: 1,
|
||||
},
|
||||
{ st_name: 7,
|
||||
st_value: (Elf32_Addr) &android_dlclose,
|
||||
st_info: STB_GLOBAL << 4,
|
||||
st_shndx: 1,
|
||||
},
|
||||
{ st_name: 15,
|
||||
st_value: (Elf32_Addr) &android_dlsym,
|
||||
st_info: STB_GLOBAL << 4,
|
||||
st_shndx: 1,
|
||||
},
|
||||
{ st_name: 21,
|
||||
st_value: (Elf32_Addr) &android_dlerror,
|
||||
st_info: STB_GLOBAL << 4,
|
||||
st_shndx: 1,
|
||||
},
|
||||
{ st_name: 29,
|
||||
st_value: (Elf32_Addr) &android_dladdr,
|
||||
st_info: STB_GLOBAL << 4,
|
||||
st_shndx: 1,
|
||||
},
|
||||
#ifdef ANDROID_ARM_LINKER
|
||||
{ st_name: 36,
|
||||
st_value: (Elf32_Addr) &android_dl_unwind_find_exidx,
|
||||
st_info: STB_GLOBAL << 4,
|
||||
st_shndx: 1,
|
||||
},
|
||||
{ st_name: 57,
|
||||
#else
|
||||
{ st_name: 36,
|
||||
#endif
|
||||
st_value: (Elf32_Addr) &android_dl_iterate_phdr,
|
||||
st_info: STB_GLOBAL << 4,
|
||||
st_shndx: 1,
|
||||
},
|
||||
};
|
||||
|
||||
/* Fake out a hash table with a single bucket.
|
||||
* A search of the hash table will look through
|
||||
* libdl_symtab starting with index [1], then
|
||||
* use libdl_chains to find the next index to
|
||||
* look at. libdl_chains should be set up to
|
||||
* walk through every element in libdl_symtab,
|
||||
* and then end with 0 (sentinel value).
|
||||
*
|
||||
* I.e., libdl_chains should look like
|
||||
* { 0, 2, 3, ... N, 0 } where N is the number
|
||||
* of actual symbols, or nelems(libdl_symtab)-1
|
||||
* (since the first element of libdl_symtab is not
|
||||
* a real symbol).
|
||||
*
|
||||
* (see _elf_lookup())
|
||||
*
|
||||
* Note that adding any new symbols here requires
|
||||
* stubbing them out in libdl.
|
||||
*/
|
||||
static unsigned libdl_buckets[1] = { 1 };
|
||||
#if defined(ANDROID_ARM_LINKER)
|
||||
static unsigned libdl_chains[8] = { 0, 2, 3, 4, 5, 6, 7, 0 };
|
||||
#else
|
||||
static unsigned libdl_chains[7] = { 0, 2, 3, 4, 5, 6, 0 };
|
||||
#endif
|
||||
|
||||
soinfo libdl_info = {
|
||||
name: "libdl.so",
|
||||
flags: FLAG_LINKED,
|
||||
|
||||
strtab: ANDROID_LIBDL_STRTAB,
|
||||
symtab: libdl_symtab,
|
||||
|
||||
refcount: 1,
|
||||
nbucket: 1,
|
||||
#if defined(ANDROID_ARM_LINKER)
|
||||
nchain: 8,
|
||||
#else
|
||||
nchain: 7,
|
||||
#endif
|
||||
bucket: libdl_buckets,
|
||||
chain: libdl_chains,
|
||||
};
|
||||
|
||||
2337
hybris/src/jb/linker.c
Normal file
2337
hybris/src/jb/linker.c
Normal file
File diff suppressed because it is too large
Load Diff
219
hybris/src/jb/linker.h
Normal file
219
hybris/src/jb/linker.h
Normal file
@ -0,0 +1,219 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _LINKER_H_
|
||||
#define _LINKER_H_
|
||||
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
#include <elf.h>
|
||||
|
||||
#undef PAGE_MASK
|
||||
#undef PAGE_SIZE
|
||||
#define PAGE_SIZE 4096
|
||||
#define PAGE_MASK 4095
|
||||
|
||||
void debugger_init();
|
||||
const char *addr_to_name(unsigned addr);
|
||||
|
||||
/* magic shared structures that GDB knows about */
|
||||
|
||||
struct link_map
|
||||
{
|
||||
uintptr_t l_addr;
|
||||
char * l_name;
|
||||
uintptr_t l_ld;
|
||||
struct link_map * l_next;
|
||||
struct link_map * l_prev;
|
||||
};
|
||||
|
||||
/* needed for dl_iterate_phdr to be passed to the callbacks provided */
|
||||
struct dl_phdr_info
|
||||
{
|
||||
Elf32_Addr dlpi_addr;
|
||||
const char *dlpi_name;
|
||||
const Elf32_Phdr *dlpi_phdr;
|
||||
Elf32_Half dlpi_phnum;
|
||||
};
|
||||
|
||||
|
||||
// Values for r_debug->state
|
||||
enum {
|
||||
RT_CONSISTENT,
|
||||
RT_ADD,
|
||||
RT_DELETE
|
||||
};
|
||||
|
||||
struct r_debug
|
||||
{
|
||||
int32_t r_version;
|
||||
struct link_map * r_map;
|
||||
void (*r_brk)(void);
|
||||
int32_t r_state;
|
||||
uintptr_t r_ldbase;
|
||||
};
|
||||
|
||||
typedef struct soinfo soinfo;
|
||||
|
||||
#define FLAG_LINKED 0x00000001
|
||||
#define FLAG_ERROR 0x00000002
|
||||
#define FLAG_EXE 0x00000004 // The main executable
|
||||
#define FLAG_LINKER 0x00000010 // The linker itself
|
||||
|
||||
#define SOINFO_NAME_LEN 128
|
||||
|
||||
struct soinfo
|
||||
{
|
||||
const char name[SOINFO_NAME_LEN];
|
||||
Elf32_Phdr *phdr;
|
||||
int phnum;
|
||||
unsigned entry;
|
||||
unsigned base;
|
||||
unsigned size;
|
||||
|
||||
int unused; // DO NOT USE, maintained for compatibility.
|
||||
|
||||
unsigned *dynamic;
|
||||
|
||||
unsigned wrprotect_start;
|
||||
unsigned wrprotect_end;
|
||||
|
||||
soinfo *next;
|
||||
unsigned flags;
|
||||
|
||||
const char *strtab;
|
||||
Elf32_Sym *symtab;
|
||||
|
||||
unsigned nbucket;
|
||||
unsigned nchain;
|
||||
unsigned *bucket;
|
||||
unsigned *chain;
|
||||
|
||||
unsigned *plt_got;
|
||||
|
||||
Elf32_Rel *plt_rel;
|
||||
unsigned plt_rel_count;
|
||||
|
||||
Elf32_Rel *rel;
|
||||
unsigned rel_count;
|
||||
|
||||
unsigned *preinit_array;
|
||||
unsigned preinit_array_count;
|
||||
|
||||
unsigned *init_array;
|
||||
unsigned init_array_count;
|
||||
unsigned *fini_array;
|
||||
unsigned fini_array_count;
|
||||
|
||||
void (*init_func)(void);
|
||||
void (*fini_func)(void);
|
||||
|
||||
#ifdef ANDROID_ARM_LINKER
|
||||
/* ARM EABI section used for stack unwinding. */
|
||||
unsigned *ARM_exidx;
|
||||
unsigned ARM_exidx_count;
|
||||
#endif
|
||||
|
||||
unsigned refcount;
|
||||
struct link_map linkmap;
|
||||
|
||||
int constructors_called;
|
||||
|
||||
Elf32_Addr gnu_relro_start;
|
||||
unsigned gnu_relro_len;
|
||||
|
||||
};
|
||||
|
||||
|
||||
extern soinfo libdl_info;
|
||||
|
||||
#ifdef ANDROID_ARM_LINKER
|
||||
|
||||
#define R_ARM_COPY 20
|
||||
#define R_ARM_GLOB_DAT 21
|
||||
#define R_ARM_JUMP_SLOT 22
|
||||
#define R_ARM_RELATIVE 23
|
||||
|
||||
/* According to the AAPCS specification, we only
|
||||
* need the above relocations. However, in practice,
|
||||
* the following ones turn up from time to time.
|
||||
*/
|
||||
#define R_ARM_ABS32 2
|
||||
#define R_ARM_REL32 3
|
||||
|
||||
#elif defined(ANDROID_X86_LINKER)
|
||||
|
||||
#define R_386_32 1
|
||||
#define R_386_PC32 2
|
||||
#define R_386_GLOB_DAT 6
|
||||
#define R_386_JUMP_SLOT 7
|
||||
#define R_386_RELATIVE 8
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef DT_INIT_ARRAY
|
||||
#define DT_INIT_ARRAY 25
|
||||
#endif
|
||||
|
||||
#ifndef DT_FINI_ARRAY
|
||||
#define DT_FINI_ARRAY 26
|
||||
#endif
|
||||
|
||||
#ifndef DT_INIT_ARRAYSZ
|
||||
#define DT_INIT_ARRAYSZ 27
|
||||
#endif
|
||||
|
||||
#ifndef DT_FINI_ARRAYSZ
|
||||
#define DT_FINI_ARRAYSZ 28
|
||||
#endif
|
||||
|
||||
#ifndef DT_PREINIT_ARRAY
|
||||
#define DT_PREINIT_ARRAY 32
|
||||
#endif
|
||||
|
||||
#ifndef DT_PREINIT_ARRAYSZ
|
||||
#define DT_PREINIT_ARRAYSZ 33
|
||||
#endif
|
||||
|
||||
soinfo *find_library(const char *name);
|
||||
unsigned unload_library(soinfo *si);
|
||||
Elf32_Sym *lookup_in_library(soinfo *si, const char *name);
|
||||
Elf32_Sym *lookup(const char *name, soinfo **found, soinfo *start);
|
||||
soinfo *find_containing_library(const void *addr);
|
||||
Elf32_Sym *find_containing_symbol(const void *addr, soinfo *si);
|
||||
const char *linker_get_error(void);
|
||||
void call_constructors_recursive(soinfo *si);
|
||||
|
||||
#ifdef ANDROID_ARM_LINKER
|
||||
typedef long unsigned int *_Unwind_Ptr;
|
||||
_Unwind_Ptr dl_unwind_find_exidx(_Unwind_Ptr pc, int *pcount);
|
||||
#elif defined(ANDROID_X86_LINKER)
|
||||
int dl_iterate_phdr(int (*cb)(struct dl_phdr_info *, size_t, void *), void *);
|
||||
#endif
|
||||
|
||||
#endif
|
||||
149
hybris/src/jb/linker_debug.h
Normal file
149
hybris/src/jb/linker_debug.h
Normal file
@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (C) 2008-2010 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _LINKER_DEBUG_H_
|
||||
#define _LINKER_DEBUG_H_
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#ifndef LINKER_DEBUG
|
||||
#error LINKER_DEBUG should be defined to either 1 or 0 in Android.mk
|
||||
#endif
|
||||
|
||||
#define TRACE_DEBUG 1
|
||||
#define DO_TRACE_LOOKUP 1
|
||||
#define DO_TRACE_RELO 1
|
||||
#define TIMING 0
|
||||
#define STATS 0
|
||||
#define COUNT_PAGES 0
|
||||
|
||||
/*********************************************************************
|
||||
* You shouldn't need to modify anything below unless you are adding
|
||||
* more debugging information.
|
||||
*
|
||||
* To enable/disable specific debug options, change the defines above
|
||||
*********************************************************************/
|
||||
|
||||
|
||||
/*********************************************************************/
|
||||
#undef TRUE
|
||||
#undef FALSE
|
||||
#define TRUE 1
|
||||
#define FALSE 0
|
||||
|
||||
/* Only use printf() during debugging. We have seen occasional memory
|
||||
* corruption when the linker uses printf().
|
||||
*/
|
||||
#if LINKER_DEBUG
|
||||
#include "linker_format.h"
|
||||
extern int debug_verbosity;
|
||||
extern int debug_stdout;
|
||||
extern int format_log(int, const char *, const char *, ...);
|
||||
extern int format_fd(int, const char *, ...);
|
||||
#define _PRINTVF(v,f,x...) \
|
||||
do { \
|
||||
if (debug_verbosity > (v)) \
|
||||
if (debug_stdout) \
|
||||
format_fd(1, x); \
|
||||
else \
|
||||
format_log(5-(v),"linker",x); \
|
||||
} while (0)
|
||||
#else /* !LINKER_DEBUG */
|
||||
#define _PRINTVF(v,f,x...) do {} while(0)
|
||||
#endif /* LINKER_DEBUG */
|
||||
|
||||
#define PRINT(x...) _PRINTVF(-1, FALSE, x)
|
||||
#define INFO(x...) _PRINTVF(0, TRUE, x)
|
||||
#define TRACE(x...) _PRINTVF(1, TRUE, x)
|
||||
#define WARN(fmt,args...) \
|
||||
_PRINTVF(-1, TRUE, "%s:%d| WARNING: " fmt, __FILE__, __LINE__, ## args)
|
||||
#define ERROR(fmt,args...) \
|
||||
_PRINTVF(-1, TRUE, "%s:%d| ERROR: " fmt, __FILE__, __LINE__, ## args)
|
||||
|
||||
|
||||
#if TRACE_DEBUG
|
||||
#define DEBUG(x...) _PRINTVF(2, TRUE, "DEBUG: " x)
|
||||
#else /* !TRACE_DEBUG */
|
||||
#define DEBUG(x...) do {} while (0)
|
||||
#endif /* TRACE_DEBUG */
|
||||
|
||||
#if LINKER_DEBUG
|
||||
#define TRACE_TYPE(t,x...) do { if (DO_TRACE_##t) { TRACE(x); } } while (0)
|
||||
#else /* !LINKER_DEBUG */
|
||||
#define TRACE_TYPE(t,x...) do {} while (0)
|
||||
#endif /* LINKER_DEBUG */
|
||||
|
||||
#if STATS
|
||||
#define RELOC_ABSOLUTE 0
|
||||
#define RELOC_RELATIVE 1
|
||||
#define RELOC_COPY 2
|
||||
#define RELOC_SYMBOL 3
|
||||
#define NUM_RELOC_STATS 4
|
||||
|
||||
struct _link_stats {
|
||||
int reloc[NUM_RELOC_STATS];
|
||||
};
|
||||
extern struct _link_stats linker_stats;
|
||||
|
||||
#define COUNT_RELOC(type) \
|
||||
do { if (type >= 0 && type < NUM_RELOC_STATS) { \
|
||||
linker_stats.reloc[type] += 1; \
|
||||
} else { \
|
||||
PRINT("Unknown reloc stat requested\n"); \
|
||||
} \
|
||||
} while(0)
|
||||
#else /* !STATS */
|
||||
#define COUNT_RELOC(type) do {} while(0)
|
||||
#endif /* STATS */
|
||||
|
||||
#if TIMING
|
||||
#undef WARN
|
||||
#define WARN(x...) do {} while (0)
|
||||
#endif /* TIMING */
|
||||
|
||||
#if COUNT_PAGES
|
||||
extern unsigned bitmask[];
|
||||
#define MARK(offset) do { \
|
||||
bitmask[((offset) >> 12) >> 3] |= (1 << (((offset) >> 12) & 7)); \
|
||||
} while(0)
|
||||
#else
|
||||
#define MARK(x) do {} while (0)
|
||||
#endif
|
||||
|
||||
#define DEBUG_DUMP_PHDR(phdr, name, pid) do { \
|
||||
DEBUG("%5d %s (phdr = 0x%08x)\n", (pid), (name), (unsigned)(phdr)); \
|
||||
DEBUG("\t\tphdr->offset = 0x%08x\n", (unsigned)((phdr)->p_offset)); \
|
||||
DEBUG("\t\tphdr->p_vaddr = 0x%08x\n", (unsigned)((phdr)->p_vaddr)); \
|
||||
DEBUG("\t\tphdr->p_paddr = 0x%08x\n", (unsigned)((phdr)->p_paddr)); \
|
||||
DEBUG("\t\tphdr->p_filesz = 0x%08x\n", (unsigned)((phdr)->p_filesz)); \
|
||||
DEBUG("\t\tphdr->p_memsz = 0x%08x\n", (unsigned)((phdr)->p_memsz)); \
|
||||
DEBUG("\t\tphdr->p_flags = 0x%08x\n", (unsigned)((phdr)->p_flags)); \
|
||||
DEBUG("\t\tphdr->p_align = 0x%08x\n", (unsigned)((phdr)->p_align)); \
|
||||
} while (0)
|
||||
|
||||
#endif /* _LINKER_DEBUG_H_ */
|
||||
204
hybris/src/jb/linker_environ.c
Normal file
204
hybris/src/jb/linker_environ.c
Normal file
@ -0,0 +1,204 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
#include "linker_environ.h"
|
||||
#include <stddef.h>
|
||||
|
||||
static char** _envp;
|
||||
|
||||
/* Returns 1 if 'str' points to a valid environment variable definition.
|
||||
* For now, we check that:
|
||||
* - It is smaller than MAX_ENV_LEN (to detect non-zero terminated strings)
|
||||
* - It contains at least one equal sign that is not the first character
|
||||
*/
|
||||
static int
|
||||
_is_valid_definition(const char* str)
|
||||
{
|
||||
int pos = 0;
|
||||
int first_equal_pos = -1;
|
||||
|
||||
/* According to its sources, the kernel uses 32*PAGE_SIZE by default
|
||||
* as the maximum size for an env. variable definition.
|
||||
*/
|
||||
const int MAX_ENV_LEN = 32*4096;
|
||||
|
||||
if (str == NULL)
|
||||
return 0;
|
||||
|
||||
/* Parse the string, looking for the first '=' there, and its size */
|
||||
do {
|
||||
if (str[pos] == '\0')
|
||||
break;
|
||||
if (str[pos] == '=' && first_equal_pos < 0)
|
||||
first_equal_pos = pos;
|
||||
pos++;
|
||||
} while (pos < MAX_ENV_LEN);
|
||||
|
||||
if (pos >= MAX_ENV_LEN) /* Too large */
|
||||
return 0;
|
||||
|
||||
if (first_equal_pos < 1) /* No equal sign, or it is the first character */
|
||||
return 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
unsigned*
|
||||
linker_env_init(unsigned* vecs)
|
||||
{
|
||||
/* Store environment pointer - can't be NULL */
|
||||
_envp = (char**) vecs;
|
||||
|
||||
/* Skip over all definitions */
|
||||
while (vecs[0] != 0)
|
||||
vecs++;
|
||||
/* The end of the environment block is marked by two NULL pointers */
|
||||
vecs++;
|
||||
|
||||
/* As a sanity check, we're going to remove all invalid variable
|
||||
* definitions from the environment array.
|
||||
*/
|
||||
{
|
||||
char** readp = _envp;
|
||||
char** writep = _envp;
|
||||
for ( ; readp[0] != NULL; readp++ ) {
|
||||
if (!_is_valid_definition(readp[0]))
|
||||
continue;
|
||||
writep[0] = readp[0];
|
||||
writep++;
|
||||
}
|
||||
writep[0] = NULL;
|
||||
}
|
||||
|
||||
/* Return the address of the aux vectors table */
|
||||
return vecs;
|
||||
}
|
||||
|
||||
/* Check if the environment variable definition at 'envstr'
|
||||
* starts with '<name>=', and if so return the address of the
|
||||
* first character after the equal sign. Otherwise return NULL.
|
||||
*/
|
||||
static char*
|
||||
env_match(char* envstr, const char* name)
|
||||
{
|
||||
size_t cnt = 0;
|
||||
|
||||
while (envstr[cnt] == name[cnt] && name[cnt] != '\0')
|
||||
cnt++;
|
||||
|
||||
if (name[cnt] == '\0' && envstr[cnt] == '=')
|
||||
return envstr + cnt + 1;
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#define MAX_ENV_LEN (16*4096)
|
||||
|
||||
const char*
|
||||
linker_env_get(const char* name)
|
||||
{
|
||||
char** readp = _envp;
|
||||
|
||||
if (name == NULL || name[0] == '\0')
|
||||
return NULL;
|
||||
|
||||
for ( ; readp[0] != NULL; readp++ ) {
|
||||
char* val = env_match(readp[0], name);
|
||||
if (val != NULL) {
|
||||
/* Return NULL for empty strings, or if it is too large */
|
||||
if (val[0] == '\0')
|
||||
val = NULL;
|
||||
return val;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
linker_env_unset(const char* name)
|
||||
{
|
||||
char** readp = _envp;
|
||||
char** writep = readp;
|
||||
|
||||
if (name == NULL || name[0] == '\0')
|
||||
return;
|
||||
|
||||
for ( ; readp[0] != NULL; readp++ ) {
|
||||
if (env_match(readp[0], name))
|
||||
continue;
|
||||
writep[0] = readp[0];
|
||||
writep++;
|
||||
}
|
||||
/* end list with a NULL */
|
||||
writep[0] = NULL;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/* Remove unsafe environment variables. This should be used when
|
||||
* running setuid programs. */
|
||||
void
|
||||
linker_env_secure(void)
|
||||
{
|
||||
/* The same list than GLibc at this point */
|
||||
static const char* const unsec_vars[] = {
|
||||
"GCONV_PATH",
|
||||
"GETCONF_DIR",
|
||||
"HOSTALIASES",
|
||||
"LD_AUDIT",
|
||||
"LD_DEBUG",
|
||||
"LD_DEBUG_OUTPUT",
|
||||
"LD_DYNAMIC_WEAK",
|
||||
"LD_LIBRARY_PATH",
|
||||
"LD_ORIGIN_PATH",
|
||||
"LD_PRELOAD",
|
||||
"LD_PROFILE",
|
||||
"LD_SHOW_AUXV",
|
||||
"LD_USE_LOAD_BIAS",
|
||||
"LOCALDOMAIN",
|
||||
"LOCPATH",
|
||||
"MALLOC_TRACE",
|
||||
"MALLOC_CHECK_",
|
||||
"NIS_PATH",
|
||||
"NLSPATH",
|
||||
"RESOLV_HOST_CONF",
|
||||
"RES_OPTIONS",
|
||||
"TMPDIR",
|
||||
"TZDIR",
|
||||
"LD_AOUT_LIBRARY_PATH",
|
||||
"LD_AOUT_PRELOAD",
|
||||
};
|
||||
|
||||
const char* const* cp = unsec_vars;
|
||||
const char* const* endp = cp + sizeof(unsec_vars)/sizeof(unsec_vars[0]);
|
||||
|
||||
while (cp < endp) {
|
||||
linker_env_unset(*cp);
|
||||
cp++;
|
||||
}
|
||||
}
|
||||
54
hybris/src/jb/linker_environ.h
Normal file
54
hybris/src/jb/linker_environ.h
Normal file
@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef LINKER_ENVIRON_H
|
||||
#define LINKER_ENVIRON_H
|
||||
|
||||
/* Call this function before anything else. 'vecs' must be the pointer
|
||||
* to the environment block in the ELF data block. The function returns
|
||||
* the start of the aux vectors after the env block.
|
||||
*/
|
||||
extern unsigned* linker_env_init(unsigned* vecs);
|
||||
|
||||
/* Unset a given environment variable. In case the variable is defined
|
||||
* multiple times, unset all instances. This modifies the environment
|
||||
* block, so any pointer returned by linker_env_get() after this call
|
||||
* might become invalid */
|
||||
extern void linker_env_unset(const char* name);
|
||||
|
||||
|
||||
/* Returns the value of environment variable 'name' if defined and not
|
||||
* empty, or NULL otherwise. Note that the returned pointer may become
|
||||
* invalid if linker_env_unset() or linker_env_secure() are called
|
||||
* after this function. */
|
||||
extern const char* linker_env_get(const char* name);
|
||||
|
||||
/* Remove unsecure environment variables. This should be used when
|
||||
* running setuid programs. */
|
||||
extern void linker_env_secure(void);
|
||||
|
||||
#endif /* LINKER_ENVIRON_H */
|
||||
703
hybris/src/jb/linker_format.c
Normal file
703
hybris/src/jb/linker_format.c
Normal file
@ -0,0 +1,703 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include "linker_format.h"
|
||||
#include "linker_debug.h"
|
||||
|
||||
/* define UNIT_TESTS to build this file as a single executable that runs
|
||||
* the formatter's unit tests
|
||||
*/
|
||||
#define xxUNIT_TESTS
|
||||
|
||||
/*** Generic output sink
|
||||
***/
|
||||
|
||||
typedef struct {
|
||||
void *opaque;
|
||||
void (*send)(void *opaque, const char *data, int len);
|
||||
} Out;
|
||||
|
||||
static void
|
||||
out_send(Out *o, const void *data, size_t len)
|
||||
{
|
||||
o->send(o->opaque, data, (int)len);
|
||||
}
|
||||
|
||||
static void
|
||||
out_send_repeat(Out *o, char ch, int count)
|
||||
{
|
||||
char pad[8];
|
||||
const int padSize = (int)sizeof(pad);
|
||||
|
||||
memset(pad, ch, sizeof(pad));
|
||||
while (count > 0) {
|
||||
int avail = count;
|
||||
if (avail > padSize) {
|
||||
avail = padSize;
|
||||
}
|
||||
o->send(o->opaque, pad, avail);
|
||||
count -= avail;
|
||||
}
|
||||
}
|
||||
|
||||
/* forward declaration */
|
||||
static void
|
||||
out_vformat(Out *o, const char *format, va_list args);
|
||||
|
||||
/*** Bounded buffer output
|
||||
***/
|
||||
|
||||
typedef struct {
|
||||
Out out[1];
|
||||
char *buffer;
|
||||
char *pos;
|
||||
char *end;
|
||||
int total;
|
||||
} BufOut;
|
||||
|
||||
static void
|
||||
buf_out_send(void *opaque, const char *data, int len)
|
||||
{
|
||||
BufOut *bo = opaque;
|
||||
|
||||
if (len < 0)
|
||||
len = strlen(data);
|
||||
|
||||
bo->total += len;
|
||||
|
||||
while (len > 0) {
|
||||
int avail = bo->end - bo->pos;
|
||||
if (avail == 0)
|
||||
break;
|
||||
if (avail > len)
|
||||
avail = len;
|
||||
memcpy(bo->pos, data, avail);
|
||||
bo->pos += avail;
|
||||
bo->pos[0] = '\0';
|
||||
len -= avail;
|
||||
}
|
||||
}
|
||||
|
||||
static Out*
|
||||
buf_out_init(BufOut *bo, char *buffer, size_t size)
|
||||
{
|
||||
if (size == 0)
|
||||
return NULL;
|
||||
|
||||
bo->out->opaque = bo;
|
||||
bo->out->send = buf_out_send;
|
||||
bo->buffer = buffer;
|
||||
bo->end = buffer + size - 1;
|
||||
bo->pos = bo->buffer;
|
||||
bo->pos[0] = '\0';
|
||||
bo->total = 0;
|
||||
|
||||
return bo->out;
|
||||
}
|
||||
|
||||
static int
|
||||
buf_out_length(BufOut *bo)
|
||||
{
|
||||
return bo->total;
|
||||
}
|
||||
|
||||
static int
|
||||
vformat_buffer(char *buff, size_t buffsize, const char *format, va_list args)
|
||||
{
|
||||
BufOut bo;
|
||||
Out *out;
|
||||
|
||||
out = buf_out_init(&bo, buff, buffsize);
|
||||
if (out == NULL)
|
||||
return 0;
|
||||
|
||||
out_vformat(out, format, args);
|
||||
|
||||
return buf_out_length(&bo);
|
||||
}
|
||||
|
||||
int
|
||||
format_buffer(char *buff, size_t buffsize, const char *format, ...)
|
||||
{
|
||||
va_list args;
|
||||
int ret;
|
||||
|
||||
va_start(args, format);
|
||||
ret = vformat_buffer(buff, buffsize, format, args);
|
||||
va_end(args);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* The __stack_chk_fail() function calls __libc_android_log_print()
|
||||
* which calls vsnprintf().
|
||||
*
|
||||
* We define our version of the function here to avoid dragging
|
||||
* about 25 KB of C library routines related to formatting.
|
||||
*/
|
||||
#if 0
|
||||
int
|
||||
vsnprintf(char *buff, size_t bufsize, const char *format, va_list args)
|
||||
{
|
||||
return format_buffer(buff, bufsize, format, args);
|
||||
}
|
||||
#endif
|
||||
|
||||
#if LINKER_DEBUG
|
||||
|
||||
/*** File descriptor output
|
||||
***/
|
||||
|
||||
typedef struct {
|
||||
Out out[1];
|
||||
int fd;
|
||||
int total;
|
||||
} FdOut;
|
||||
|
||||
static void
|
||||
fd_out_send(void *opaque, const char *data, int len)
|
||||
{
|
||||
FdOut *fdo = opaque;
|
||||
|
||||
if (len < 0)
|
||||
len = strlen(data);
|
||||
|
||||
while (len > 0) {
|
||||
int ret = write(fdo->fd, data, len);
|
||||
if (ret < 0) {
|
||||
if (errno == EINTR)
|
||||
continue;
|
||||
break;
|
||||
}
|
||||
data += ret;
|
||||
len -= ret;
|
||||
fdo->total += ret;
|
||||
}
|
||||
}
|
||||
|
||||
static Out*
|
||||
fd_out_init(FdOut *fdo, int fd)
|
||||
{
|
||||
fdo->out->opaque = fdo;
|
||||
fdo->out->send = fd_out_send;
|
||||
fdo->fd = fd;
|
||||
fdo->total = 0;
|
||||
|
||||
return fdo->out;
|
||||
}
|
||||
|
||||
static int
|
||||
fd_out_length(FdOut *fdo)
|
||||
{
|
||||
return fdo->total;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
format_fd(int fd, const char *format, ...)
|
||||
{
|
||||
FdOut fdo;
|
||||
Out* out;
|
||||
va_list args;
|
||||
|
||||
out = fd_out_init(&fdo, fd);
|
||||
if (out == NULL)
|
||||
return 0;
|
||||
|
||||
va_start(args, format);
|
||||
out_vformat(out, format, args);
|
||||
va_end(args);
|
||||
|
||||
return fd_out_length(&fdo);
|
||||
}
|
||||
|
||||
/*** Log output
|
||||
***/
|
||||
|
||||
/* We need our own version of __libc_android_log_vprint, otherwise
|
||||
* the log output is completely broken. Probably due to the fact
|
||||
* that the C library is not initialized yet.
|
||||
*
|
||||
* You can test that by setting CUSTOM_LOG_VPRINT to 0
|
||||
*/
|
||||
#define CUSTOM_LOG_VPRINT 1
|
||||
|
||||
#if CUSTOM_LOG_VPRINT
|
||||
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/uio.h>
|
||||
|
||||
static int log_vprint(int prio, const char *tag, const char *fmt, va_list args)
|
||||
{
|
||||
char buf[1024];
|
||||
int result;
|
||||
static int log_fd = -1;
|
||||
|
||||
result = vformat_buffer(buf, sizeof buf, fmt, args);
|
||||
|
||||
if (log_fd < 0) {
|
||||
log_fd = open("/dev/log/main", O_WRONLY);
|
||||
if (log_fd < 0) {
|
||||
log_fd = fileno(stdout); // kernel doesn't have android log
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
ssize_t ret;
|
||||
struct iovec vec[3];
|
||||
|
||||
vec[0].iov_base = (unsigned char *) &prio;
|
||||
vec[0].iov_len = 1;
|
||||
vec[1].iov_base = (void *) tag;
|
||||
vec[1].iov_len = strlen(tag) + 1;
|
||||
vec[2].iov_base = (void *) buf;
|
||||
vec[2].iov_len = strlen(buf) + 1;
|
||||
|
||||
do {
|
||||
ret = writev(log_fd, vec, 3);
|
||||
} while ((ret < 0) && (errno == EINTR));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
#define __libc_android_log_vprint log_vprint
|
||||
|
||||
#else /* !CUSTOM_LOG_VPRINT */
|
||||
|
||||
extern int __libc_android_log_vprint(int prio, const char* tag, const char* format, va_list ap);
|
||||
|
||||
#endif /* !CUSTOM_LOG_VPRINT */
|
||||
|
||||
int
|
||||
format_log(int prio, const char *tag, const char *format, ...)
|
||||
{
|
||||
int ret;
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
ret = __libc_android_log_vprint(prio, tag, format, args);
|
||||
va_end(args);
|
||||
return ret;
|
||||
}
|
||||
|
||||
#endif /* LINKER_DEBUG */
|
||||
|
||||
/*** formatted output implementation
|
||||
***/
|
||||
|
||||
/* Parse a decimal string from 'format + *ppos',
|
||||
* return the value, and writes the new position past
|
||||
* the decimal string in '*ppos' on exit.
|
||||
*
|
||||
* NOTE: Does *not* handle a sign prefix.
|
||||
*/
|
||||
static unsigned
|
||||
parse_decimal(const char *format, int *ppos)
|
||||
{
|
||||
const char* p = format + *ppos;
|
||||
unsigned result = 0;
|
||||
|
||||
for (;;) {
|
||||
int ch = *p;
|
||||
unsigned d = (unsigned)(ch - '0');
|
||||
|
||||
if (d >= 10U)
|
||||
break;
|
||||
|
||||
result = result*10 + d;
|
||||
p++;
|
||||
}
|
||||
*ppos = p - format;
|
||||
return result;
|
||||
}
|
||||
|
||||
/* write an octal/decimal/number into a bounded buffer.
|
||||
* assumes that bufsize > 0, and 'digits' is a string of
|
||||
* digits of at least 'base' values.
|
||||
*/
|
||||
static void
|
||||
format_number(char *buffer, size_t bufsize, uint64_t value, int base, const char *digits)
|
||||
{
|
||||
char *pos = buffer;
|
||||
char *end = buffer + bufsize - 1;
|
||||
|
||||
/* generate digit string in reverse order */
|
||||
while (value) {
|
||||
unsigned d = value % base;
|
||||
value /= base;
|
||||
if (pos < end) {
|
||||
*pos++ = digits[d];
|
||||
}
|
||||
}
|
||||
|
||||
/* special case for 0 */
|
||||
if (pos == buffer) {
|
||||
if (pos < end) {
|
||||
*pos++ = '0';
|
||||
}
|
||||
}
|
||||
pos[0] = '\0';
|
||||
|
||||
/* now reverse digit string in-place */
|
||||
end = pos - 1;
|
||||
pos = buffer;
|
||||
while (pos < end) {
|
||||
int ch = pos[0];
|
||||
pos[0] = end[0];
|
||||
end[0] = (char) ch;
|
||||
pos++;
|
||||
end--;
|
||||
}
|
||||
}
|
||||
|
||||
/* Write an integer (octal or decimal) into a buffer, assumes buffsize > 2 */
|
||||
static void
|
||||
format_integer(char *buffer, size_t buffsize, uint64_t value, int base, int isSigned)
|
||||
{
|
||||
if (isSigned && (int64_t)value < 0) {
|
||||
buffer[0] = '-';
|
||||
buffer += 1;
|
||||
buffsize -= 1;
|
||||
value = (uint64_t)(-(int64_t)value);
|
||||
}
|
||||
|
||||
format_number(buffer, buffsize, value, base, "0123456789");
|
||||
}
|
||||
|
||||
/* Write an octal into a buffer, assumes buffsize > 2 */
|
||||
static void
|
||||
format_octal(char *buffer, size_t buffsize, uint64_t value, int isSigned)
|
||||
{
|
||||
format_integer(buffer, buffsize, value, 8, isSigned);
|
||||
}
|
||||
|
||||
/* Write a decimal into a buffer, assumes buffsize > 2 */
|
||||
static void
|
||||
format_decimal(char *buffer, size_t buffsize, uint64_t value, int isSigned)
|
||||
{
|
||||
format_integer(buffer, buffsize, value, 10, isSigned);
|
||||
}
|
||||
|
||||
/* Write an hexadecimal into a buffer, isCap is true for capital alphas.
|
||||
* Assumes bufsize > 2 */
|
||||
static void
|
||||
format_hex(char *buffer, size_t buffsize, uint64_t value, int isCap)
|
||||
{
|
||||
const char *digits = isCap ? "0123456789ABCDEF" : "0123456789abcdef";
|
||||
|
||||
format_number(buffer, buffsize, value, 16, digits);
|
||||
}
|
||||
|
||||
|
||||
/* Perform formatted output to an output target 'o' */
|
||||
static void
|
||||
out_vformat(Out *o, const char *format, va_list args)
|
||||
{
|
||||
int nn = 0;
|
||||
|
||||
for (;;) {
|
||||
int mm;
|
||||
int padZero = 0;
|
||||
int padLeft = 0;
|
||||
char sign = '\0';
|
||||
int width = -1;
|
||||
int prec = -1;
|
||||
size_t bytelen = sizeof(int);
|
||||
const char* str;
|
||||
int slen;
|
||||
char buffer[32]; /* temporary buffer used to format numbers */
|
||||
|
||||
char c;
|
||||
|
||||
/* first, find all characters that are not 0 or '%' */
|
||||
/* then send them to the output directly */
|
||||
mm = nn;
|
||||
do {
|
||||
c = format[mm];
|
||||
if (c == '\0' || c == '%')
|
||||
break;
|
||||
mm++;
|
||||
} while (1);
|
||||
|
||||
if (mm > nn) {
|
||||
out_send(o, format+nn, mm-nn);
|
||||
nn = mm;
|
||||
}
|
||||
|
||||
/* is this it ? then exit */
|
||||
if (c == '\0')
|
||||
break;
|
||||
|
||||
/* nope, we are at a '%' modifier */
|
||||
nn++; // skip it
|
||||
|
||||
/* parse flags */
|
||||
for (;;) {
|
||||
c = format[nn++];
|
||||
if (c == '\0') { /* single trailing '%' ? */
|
||||
c = '%';
|
||||
out_send(o, &c, 1);
|
||||
return;
|
||||
}
|
||||
else if (c == '0') {
|
||||
padZero = 1;
|
||||
continue;
|
||||
}
|
||||
else if (c == '-') {
|
||||
padLeft = 1;
|
||||
continue;
|
||||
}
|
||||
else if (c == ' ' || c == '+') {
|
||||
sign = c;
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* parse field width */
|
||||
if ((c >= '0' && c <= '9')) {
|
||||
nn --;
|
||||
width = (int)parse_decimal(format, &nn);
|
||||
c = format[nn++];
|
||||
}
|
||||
|
||||
/* parse precision */
|
||||
if (c == '.') {
|
||||
prec = (int)parse_decimal(format, &nn);
|
||||
c = format[nn++];
|
||||
}
|
||||
|
||||
/* length modifier */
|
||||
switch (c) {
|
||||
case 'h':
|
||||
bytelen = sizeof(short);
|
||||
if (format[nn] == 'h') {
|
||||
bytelen = sizeof(char);
|
||||
nn += 1;
|
||||
}
|
||||
c = format[nn++];
|
||||
break;
|
||||
case 'l':
|
||||
bytelen = sizeof(long);
|
||||
if (format[nn] == 'l') {
|
||||
bytelen = sizeof(long long);
|
||||
nn += 1;
|
||||
}
|
||||
c = format[nn++];
|
||||
break;
|
||||
case 'z':
|
||||
bytelen = sizeof(size_t);
|
||||
c = format[nn++];
|
||||
break;
|
||||
case 't':
|
||||
bytelen = sizeof(ptrdiff_t);
|
||||
c = format[nn++];
|
||||
break;
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
||||
/* conversion specifier */
|
||||
if (c == 's') {
|
||||
/* string */
|
||||
str = va_arg(args, const char*);
|
||||
} else if (c == 'c') {
|
||||
/* character */
|
||||
/* NOTE: char is promoted to int when passed through the stack */
|
||||
buffer[0] = (char) va_arg(args, int);
|
||||
buffer[1] = '\0';
|
||||
str = buffer;
|
||||
} else if (c == 'p') {
|
||||
uint64_t value = (uintptr_t) va_arg(args, void*);
|
||||
buffer[0] = '0';
|
||||
buffer[1] = 'x';
|
||||
format_hex(buffer + 2, sizeof buffer-2, value, 0);
|
||||
str = buffer;
|
||||
} else {
|
||||
/* integers - first read value from stack */
|
||||
uint64_t value;
|
||||
int isSigned = (c == 'd' || c == 'i' || c == 'o');
|
||||
|
||||
/* NOTE: int8_t and int16_t are promoted to int when passed
|
||||
* through the stack
|
||||
*/
|
||||
switch (bytelen) {
|
||||
case 1: value = (uint8_t) va_arg(args, int); break;
|
||||
case 2: value = (uint16_t) va_arg(args, int); break;
|
||||
case 4: value = va_arg(args, uint32_t); break;
|
||||
case 8: value = va_arg(args, uint64_t); break;
|
||||
default: return; /* should not happen */
|
||||
}
|
||||
|
||||
/* sign extension, if needed */
|
||||
if (isSigned) {
|
||||
int shift = 64 - 8*bytelen;
|
||||
value = (uint64_t)(((int64_t)(value << shift)) >> shift);
|
||||
}
|
||||
|
||||
/* format the number properly into our buffer */
|
||||
switch (c) {
|
||||
case 'i': case 'd':
|
||||
format_integer(buffer, sizeof buffer, value, 10, isSigned);
|
||||
break;
|
||||
case 'o':
|
||||
format_integer(buffer, sizeof buffer, value, 8, isSigned);
|
||||
break;
|
||||
case 'x': case 'X':
|
||||
format_hex(buffer, sizeof buffer, value, (c == 'X'));
|
||||
break;
|
||||
default:
|
||||
buffer[0] = '\0';
|
||||
}
|
||||
/* then point to it */
|
||||
str = buffer;
|
||||
}
|
||||
|
||||
/* if we are here, 'str' points to the content that must be
|
||||
* outputted. handle padding and alignment now */
|
||||
|
||||
slen = strlen(str);
|
||||
|
||||
if (slen < width && !padLeft) {
|
||||
char padChar = padZero ? '0' : ' ';
|
||||
out_send_repeat(o, padChar, width - slen);
|
||||
}
|
||||
|
||||
out_send(o, str, slen);
|
||||
|
||||
if (slen < width && padLeft) {
|
||||
char padChar = padZero ? '0' : ' ';
|
||||
out_send_repeat(o, padChar, width - slen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#ifdef UNIT_TESTS
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
static int gFails = 0;
|
||||
|
||||
#define MARGIN 40
|
||||
|
||||
#define UTEST_CHECK(condition,message) \
|
||||
printf("Checking %-*s: ", MARGIN, message); fflush(stdout); \
|
||||
if (!(condition)) { \
|
||||
printf("KO\n"); \
|
||||
gFails += 1; \
|
||||
} else { \
|
||||
printf("ok\n"); \
|
||||
}
|
||||
|
||||
static void
|
||||
utest_BufOut(void)
|
||||
{
|
||||
char buffer[16];
|
||||
BufOut bo[1];
|
||||
Out* out;
|
||||
int ret;
|
||||
|
||||
buffer[0] = '1';
|
||||
out = buf_out_init(bo, buffer, sizeof buffer);
|
||||
UTEST_CHECK(buffer[0] == '\0', "buf_out_init clears initial byte");
|
||||
out_send(out, "abc", 3);
|
||||
UTEST_CHECK(!memcmp(buffer, "abc", 4), "out_send() works with BufOut");
|
||||
out_send_repeat(out, 'X', 4);
|
||||
UTEST_CHECK(!memcmp(buffer, "abcXXXX", 8), "out_send_repeat() works with BufOut");
|
||||
buffer[sizeof buffer-1] = 'x';
|
||||
out_send_repeat(out, 'Y', 2*sizeof(buffer));
|
||||
UTEST_CHECK(buffer[sizeof buffer-1] == '\0', "overflows always zero-terminates");
|
||||
|
||||
out = buf_out_init(bo, buffer, sizeof buffer);
|
||||
out_send_repeat(out, 'X', 2*sizeof(buffer));
|
||||
ret = buf_out_length(bo);
|
||||
UTEST_CHECK(ret == 2*sizeof(buffer), "correct size returned on overflow");
|
||||
}
|
||||
|
||||
static void
|
||||
utest_expect(const char* result, const char* format, ...)
|
||||
{
|
||||
va_list args;
|
||||
BufOut bo[1];
|
||||
char buffer[256];
|
||||
Out* out = buf_out_init(bo, buffer, sizeof buffer);
|
||||
|
||||
printf("Checking %-*s: ", MARGIN, format); fflush(stdout);
|
||||
va_start(args, format);
|
||||
out_vformat(out, format, args);
|
||||
va_end(args);
|
||||
|
||||
if (strcmp(result, buffer)) {
|
||||
printf("KO. got '%s' expecting '%s'\n", buffer, result);
|
||||
gFails += 1;
|
||||
} else {
|
||||
printf("ok. got '%s'\n", result);
|
||||
}
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
utest_BufOut();
|
||||
utest_expect("", "");
|
||||
utest_expect("a", "a");
|
||||
utest_expect("01234", "01234", "");
|
||||
utest_expect("01234", "%s", "01234");
|
||||
utest_expect("aabbcc", "aa%scc", "bb");
|
||||
utest_expect("a", "%c", 'a');
|
||||
utest_expect("1234", "%d", 1234);
|
||||
utest_expect("-8123", "%d", -8123);
|
||||
utest_expect("16", "%hd", 0x7fff0010);
|
||||
utest_expect("16", "%hhd", 0x7fffff10);
|
||||
utest_expect("68719476736", "%lld", 0x1000000000LL);
|
||||
utest_expect("70000", "%ld", 70000);
|
||||
utest_expect("0xb0001234", "%p", (void*)0xb0001234);
|
||||
utest_expect("12ab", "%x", 0x12ab);
|
||||
utest_expect("12AB", "%X", 0x12ab);
|
||||
utest_expect("00123456", "%08x", 0x123456);
|
||||
utest_expect("01234", "0%d", 1234);
|
||||
utest_expect(" 1234", "%5d", 1234);
|
||||
utest_expect("01234", "%05d", 1234);
|
||||
utest_expect(" 1234", "%8d", 1234);
|
||||
utest_expect("1234 ", "%-8d", 1234);
|
||||
utest_expect("abcdef ", "%-11s", "abcdef");
|
||||
utest_expect("something:1234", "%s:%d", "something", 1234);
|
||||
utest_expect("005:5:05", "%03d:%d:%02d", 5, 5, 5);
|
||||
utest_expect("5,0x0", "%d,%p", 5, NULL);
|
||||
utest_expect("68719476736,6,7,8", "%lld,%d,%d,%d", 0x1000000000LL, 6, 7, 8);
|
||||
return gFails != 0;
|
||||
}
|
||||
|
||||
#endif /* UNIT_TESTS */
|
||||
41
hybris/src/jb/linker_format.h
Normal file
41
hybris/src/jb/linker_format.h
Normal file
@ -0,0 +1,41 @@
|
||||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef _LINKER_FORMAT_H
|
||||
#define _LINKER_FORMAT_H
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/* Formatting routines for the dynamic linker's debug traces */
|
||||
/* We want to avoid dragging the whole C library fprintf() */
|
||||
/* implementation into the dynamic linker since this creates */
|
||||
/* issues (it uses malloc()/free()) and increases code size */
|
||||
|
||||
int format_buffer(char *buffer, size_t bufsize, const char *format, ...);
|
||||
|
||||
#endif /* _LINKER_FORMAT_H */
|
||||
36
hybris/src/jb/rt.c
Normal file
36
hybris/src/jb/rt.c
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* * Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in
|
||||
* the documentation and/or other materials provided with the
|
||||
* distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
||||
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
||||
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
||||
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
||||
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
||||
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
||||
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
||||
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/*
|
||||
* This function is an empty stub where GDB locates a breakpoint to get notified
|
||||
* about linker activity.
|
||||
*/
|
||||
void __attribute__((noinline)) rtld_db_dlactivity(void)
|
||||
{
|
||||
}
|
||||
|
||||
133
hybris/src/logging.c
Normal file
133
hybris/src/logging.c
Normal file
@ -0,0 +1,133 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013 Thomas Perl <m@thp.io>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "logging.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <pthread.h>
|
||||
#include <time.h>
|
||||
|
||||
FILE *hybris_logging_target = NULL;
|
||||
|
||||
pthread_mutex_t hybris_logging_mutex;
|
||||
|
||||
static enum hybris_log_level
|
||||
hybris_minimum_log_level = HYBRIS_LOG_WARN;
|
||||
|
||||
static enum hybris_log_format _hybris_logging_format = HYBRIS_LOG_FORMAT_NORMAL;
|
||||
|
||||
static int _hybris_should_trace = 0;
|
||||
|
||||
static int
|
||||
hybris_logging_initialized = 0;
|
||||
|
||||
static void
|
||||
hybris_logging_initialize()
|
||||
{
|
||||
const char *env = getenv("HYBRIS_LOGGING_LEVEL");
|
||||
|
||||
if (env == NULL) {
|
||||
/* Nothing to do - use default level */
|
||||
} else if (strcmp(env, "debug") == 0) {
|
||||
hybris_minimum_log_level = HYBRIS_LOG_DEBUG;
|
||||
} else if (strcmp(env, "info") == 0) {
|
||||
hybris_minimum_log_level = HYBRIS_LOG_INFO;
|
||||
} else if (strcmp(env, "warn") == 0) {
|
||||
hybris_minimum_log_level = HYBRIS_LOG_WARN;
|
||||
} else if (strcmp(env, "error") == 0) {
|
||||
hybris_minimum_log_level = HYBRIS_LOG_ERROR;
|
||||
} else if (strcmp(env, "disabled") == 0) {
|
||||
hybris_minimum_log_level = HYBRIS_LOG_DISABLED;
|
||||
}
|
||||
|
||||
env = getenv("HYBRIS_LOGGING_TARGET");
|
||||
if (env != NULL)
|
||||
{
|
||||
hybris_logging_target = fopen(env, "a");
|
||||
}
|
||||
if (hybris_logging_target == NULL)
|
||||
hybris_logging_target = stderr;
|
||||
|
||||
env = getenv("HYBRIS_LOGGING_FORMAT");
|
||||
if (env != NULL)
|
||||
{
|
||||
if (strcmp(env, "systrace") == 0) {
|
||||
_hybris_logging_format = HYBRIS_LOG_FORMAT_SYSTRACE;
|
||||
}
|
||||
else
|
||||
_hybris_logging_format = HYBRIS_LOG_FORMAT_NORMAL;
|
||||
}
|
||||
|
||||
env = getenv("HYBRIS_TRACE");
|
||||
if (env != NULL)
|
||||
{
|
||||
if (strcmp(env, "1") == 0) {
|
||||
_hybris_should_trace = 1;
|
||||
}
|
||||
}
|
||||
pthread_mutex_init(&hybris_logging_mutex, NULL);
|
||||
}
|
||||
|
||||
int
|
||||
hybris_should_log(enum hybris_log_level level)
|
||||
{
|
||||
/* Initialize logging level from environment */
|
||||
if (!hybris_logging_initialized) {
|
||||
hybris_logging_initialized = 1;
|
||||
hybris_logging_initialize();
|
||||
}
|
||||
|
||||
return (level >= hybris_minimum_log_level);
|
||||
}
|
||||
|
||||
void
|
||||
hybris_set_log_level(enum hybris_log_level level)
|
||||
{
|
||||
hybris_minimum_log_level = level;
|
||||
}
|
||||
|
||||
void *
|
||||
hybris_get_thread_id()
|
||||
{
|
||||
return (void *)pthread_self();
|
||||
}
|
||||
|
||||
double
|
||||
hybris_get_thread_time()
|
||||
{
|
||||
struct timespec now;
|
||||
if(clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now) == 0) {
|
||||
return (double)now.tv_sec + (double)now.tv_nsec / 1000000000.0;
|
||||
} else {
|
||||
return -1.0;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
hybris_should_trace(const char *module, const char *tracepoint)
|
||||
{
|
||||
return _hybris_should_trace;
|
||||
}
|
||||
|
||||
enum hybris_log_format hybris_logging_format()
|
||||
{
|
||||
return _hybris_logging_format;
|
||||
}
|
||||
165
hybris/src/logging.h
Normal file
165
hybris/src/logging.h
Normal file
@ -0,0 +1,165 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013 Thomas Perl <m@thp.io>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HYBRIS_LOGGING_H
|
||||
#define HYBRIS_LOGGING_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
enum hybris_log_level {
|
||||
/* Most verbose logging level */
|
||||
HYBRIS_LOG_DEBUG = 0,
|
||||
|
||||
/* Normal logging levels */
|
||||
HYBRIS_LOG_INFO,
|
||||
HYBRIS_LOG_WARN,
|
||||
HYBRIS_LOG_ERROR,
|
||||
|
||||
/**
|
||||
* "Fake" level at which no messages are logged.
|
||||
* Can be used with hybris_set_log_level().
|
||||
**/
|
||||
HYBRIS_LOG_DISABLED,
|
||||
};
|
||||
|
||||
enum hybris_log_format {
|
||||
HYBRIS_LOG_FORMAT_NORMAL,
|
||||
HYBRIS_LOG_FORMAT_SYSTRACE
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns nonzero if messages at level "level" should be logged.
|
||||
* Only used by the HYBRIS_LOG() macro, no need to call it manually.
|
||||
**/
|
||||
int
|
||||
hybris_should_log(enum hybris_log_level level);
|
||||
|
||||
|
||||
/**
|
||||
* Sets the minimum log level that is logged, for example a minimum
|
||||
* log level of HYBRIS_LOG_DEBUG would print all log messages, a
|
||||
* minimum log level of HYBRIS_LOG_WARN would only print warnings and
|
||||
* errors. The default log level is HYBRIS_LOG_WARN.
|
||||
**/
|
||||
void
|
||||
hybris_set_log_level(enum hybris_log_level level);
|
||||
|
||||
void *
|
||||
hybris_get_thread_id();
|
||||
|
||||
double
|
||||
hybris_get_thread_time();
|
||||
|
||||
enum hybris_log_format hybris_logging_format();
|
||||
|
||||
int hybris_should_trace(const char *module, const char *tracepoint);
|
||||
|
||||
extern pthread_mutex_t hybris_logging_mutex;
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
extern FILE *hybris_logging_target;
|
||||
|
||||
#if defined(DEBUG)
|
||||
# define HYBRIS_LOG_(level, module, message, ...) do { \
|
||||
if (hybris_should_log(level)) { \
|
||||
pthread_mutex_lock(&hybris_logging_mutex); \
|
||||
if (hybris_logging_format() == HYBRIS_LOG_FORMAT_NORMAL) \
|
||||
{ \
|
||||
fprintf(hybris_logging_target, "%s %s:%d (%s) %s: " message "\n", \
|
||||
module, __FILE__, __LINE__, __PRETTY_FUNCTION__, \
|
||||
#level + 11 /* + 11 = strip leading "HYBRIS_LOG_" */, \
|
||||
##__VA_ARGS__); \
|
||||
fflush(hybris_logging_target); \
|
||||
} else if (hybris_logging_format() == HYBRIS_LOG_FORMAT_SYSTRACE) { \
|
||||
fprintf(hybris_logging_target, "B|%i|%.9f|%s(%s) %s:%d (%s) " message "\n", \
|
||||
getpid(), hybris_get_thread_time(), module, __PRETTY_FUNCTION__, __FILE__, __LINE__, \
|
||||
#level + 11 /* + 11 = strip leading "HYBRIS_LOG_" */, \
|
||||
##__VA_ARGS__); \
|
||||
fflush(hybris_logging_target); \
|
||||
fprintf(hybris_logging_target, "E|%i|%.9f|%s(%s) %s:%d (%s) " message "\n", \
|
||||
getpid(), hybris_get_thread_time(), module, __PRETTY_FUNCTION__, __FILE__, __LINE__, \
|
||||
#level + 11 /* + 11 = strip leading "HYBRIS_LOG_" */, \
|
||||
##__VA_ARGS__); \
|
||||
fflush(hybris_logging_target); \
|
||||
} \
|
||||
pthread_mutex_unlock(&hybris_logging_mutex); \
|
||||
} \
|
||||
} while(0)
|
||||
|
||||
#define HYBRIS_TRACE_RECORD(module, what, tracepoint, message, ...) do { \
|
||||
if (hybris_should_trace(module, tracepoint)) { \
|
||||
pthread_mutex_lock(&hybris_logging_mutex); \
|
||||
if (hybris_logging_format() == HYBRIS_LOG_FORMAT_NORMAL) \
|
||||
{ \
|
||||
fprintf(hybris_logging_target, "PID: %i TTIME: %.9f Tracepoint-%c/%s::%s" message "\n", \
|
||||
getpid(), hybris_get_thread_time(), what, tracepoint, module, \
|
||||
##__VA_ARGS__); \
|
||||
fflush(hybris_logging_target); \
|
||||
} else if (hybris_logging_format() == HYBRIS_LOG_FORMAT_SYSTRACE) { \
|
||||
if (what == 'B') \
|
||||
fprintf(hybris_logging_target, "B|%i|%.9f|%s::%s" message "", \
|
||||
getpid(), hybris_get_thread_time(), tracepoint, module, ##__VA_ARGS__); \
|
||||
else if (what == 'E') \
|
||||
fprintf(hybris_logging_target, "E"); \
|
||||
else \
|
||||
fprintf(hybris_logging_target, "C|%i|%.9f|%s::%s-%i|" message "", \
|
||||
getpid(), hybris_get_thread_time(), tracepoint, module, getpid(), ##__VA_ARGS__); \
|
||||
fflush(hybris_logging_target); \
|
||||
} \
|
||||
pthread_mutex_unlock(&hybris_logging_mutex); \
|
||||
} \
|
||||
} while(0)
|
||||
# define HYBRIS_TRACE_BEGIN(module, tracepoint, message, ...) HYBRIS_TRACE_RECORD(module, 'B', tracepoint, message, ##__VA_ARGS__)
|
||||
# define HYBRIS_TRACE_END(module, tracepoint, message, ...) HYBRIS_TRACE_RECORD(module, 'E', tracepoint, message, ##__VA_ARGS__)
|
||||
# define HYBRIS_TRACE_COUNTER(module, tracepoint, message, ...) HYBRIS_TRACE_RECORD(module, 'C', tracepoint, message, ##__VA_ARGS__)
|
||||
#else
|
||||
# define HYBRIS_LOG_(level, module, message, ...) while (0) {}
|
||||
# define HYBRIS_TRACE_BEGIN(module, tracepoint, message, ...) while (0) {}
|
||||
# define HYBRIS_TRACE_END(module, tracepoint, message, ...) while (0) {}
|
||||
# define HYBRIS_TRACE_COUNTER(module, tracepoint, message, ...) while (0) {}
|
||||
#endif
|
||||
|
||||
|
||||
/* Generic logging functions taking the module name and a message */
|
||||
#define HYBRIS_DEBUG_LOG(module, message, ...) HYBRIS_LOG_(HYBRIS_LOG_DEBUG, #module, message, ##__VA_ARGS__)
|
||||
#define HYBRIS_WARN_LOG(module, message, ...) HYBRIS_LOG_(HYBRIS_LOG_WARN, #module, message, ##__VA_ARGS__)
|
||||
#define HYBRIS_INFO_LOG(module, message, ...) HYBRIS_LOG_(HYBRIS_LOG_INFO, #module, message, ##__VA_ARGS__)
|
||||
#define HYBRIS_ERROR_LOG(module, message, ...) HYBRIS_LOG_(HYBRIS_LOG_ERROR, #module, message, ##__VA_ARGS__)
|
||||
|
||||
|
||||
/* Module-specific logging functions can be defined like this */
|
||||
#define HYBRIS_DEBUG(message, ...) HYBRIS_DEBUG_LOG(HYBRIS, message, ##__VA_ARGS__)
|
||||
#define HYBRIS_WARN(message, ...) HYBRIS_WARN_LOG(HYBRIS, message, ##__VA_ARGS__)
|
||||
#define HYBRIS_INFO(message, ...) HYBRIS_INFO_LOG(HYBRIS, message, ##__VA_ARGS__)
|
||||
#define HYBRIS_ERROR(message, ...) HYBRIS_ERROR_LOG(HYBRIS, message, ##__VA_ARGS__)
|
||||
|
||||
/* for compatibility reasons */
|
||||
#define TRACE(message, ...) HYBRIS_DEBUG_LOG(EGL, message, ##__VA_ARGS__)
|
||||
|
||||
#endif /* HYBRIS_LOGGING_H */
|
||||
// vim: noai:ts=4:sw=4:ss=4:expandtab
|
||||
212
hybris/src/properties.c
Normal file
212
hybris/src/properties.c
Normal file
@ -0,0 +1,212 @@
|
||||
/*
|
||||
* Copyright (c) 2012 Carsten Munk <carsten.munk@gmail.com>
|
||||
* 2008 The Android Open Source Project
|
||||
* 2013 Simon Busch <morphis@gravedo.de>
|
||||
* 2013 Canonical Ltd
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#define __USE_GNU
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <sys/socket.h>
|
||||
#include <sys/un.h>
|
||||
#include <sys/select.h>
|
||||
#include <sys/types.h>
|
||||
#include <netinet/in.h>
|
||||
#include <poll.h>
|
||||
|
||||
#include "../include/hybris/properties.h"
|
||||
#include "properties_p.h"
|
||||
|
||||
|
||||
static const char property_service_socket[] = "/dev/socket/" PROP_SERVICE_NAME;
|
||||
static int send_prop_msg_no_reply = 0;
|
||||
|
||||
/* Get/Set a property from the Android Init property socket */
|
||||
static int send_prop_msg(prop_msg_t *msg,
|
||||
void (*propfn)(const char *, const char *, void *),
|
||||
void *cookie)
|
||||
{
|
||||
struct pollfd pollfds[1];
|
||||
union {
|
||||
struct sockaddr_un addr;
|
||||
struct sockaddr addr_g;
|
||||
} addr;
|
||||
socklen_t alen;
|
||||
size_t namelen;
|
||||
int s;
|
||||
int r;
|
||||
int result = -1;
|
||||
int patched_init = 0;
|
||||
|
||||
/* if we tried to talk to the server in the past and didn't get a reply,
|
||||
* it's fairly safe to say that init is not patched and this is all
|
||||
* hopeless, so we should just quit while we're ahead
|
||||
*/
|
||||
if (send_prop_msg_no_reply == 1)
|
||||
return -EIO;
|
||||
|
||||
s = socket(AF_LOCAL, SOCK_STREAM, 0);
|
||||
if (s < 0) {
|
||||
return result;
|
||||
}
|
||||
|
||||
memset(&addr, 0, sizeof(addr));
|
||||
namelen = strlen(property_service_socket);
|
||||
strncpy(addr.addr.sun_path, property_service_socket,
|
||||
sizeof(addr.addr.sun_path));
|
||||
addr.addr.sun_family = AF_LOCAL;
|
||||
alen = namelen + offsetof(struct sockaddr_un, sun_path) + 1;
|
||||
|
||||
if (TEMP_FAILURE_RETRY(connect(s, &addr.addr_g, alen) < 0)) {
|
||||
close(s);
|
||||
return result;
|
||||
}
|
||||
|
||||
r = TEMP_FAILURE_RETRY(send(s, msg, sizeof(prop_msg_t), 0));
|
||||
|
||||
if (r == sizeof(prop_msg_t)) {
|
||||
pollfds[0].fd = s;
|
||||
pollfds[0].events = 0;
|
||||
// We successfully wrote to the property server, so use recv
|
||||
// in case we need to get a property. Once the other side is
|
||||
// finished, the socket is closed.
|
||||
while ((r = recv(s, msg, sizeof(prop_msg_t), 0)) > 0) {
|
||||
if (r != sizeof(prop_msg_t)) {
|
||||
close(s);
|
||||
return result;
|
||||
}
|
||||
|
||||
/* If we got a reply, this is a patched init */
|
||||
if (!patched_init)
|
||||
patched_init = 1;
|
||||
|
||||
if (propfn)
|
||||
propfn(msg->name, msg->value, cookie);
|
||||
}
|
||||
|
||||
/* We also just get a close in case of setprop */
|
||||
if ((r >= 0) && (patched_init ||
|
||||
(msg->cmd == PROP_MSG_SETPROP))) {
|
||||
result = 0;
|
||||
} else {
|
||||
send_prop_msg_no_reply = 1;
|
||||
}
|
||||
}
|
||||
|
||||
close(s);
|
||||
return result;
|
||||
}
|
||||
|
||||
int property_list(void (*propfn)(const char *key, const char *value, void *cookie), void *cookie)
|
||||
{
|
||||
int err;
|
||||
prop_msg_t msg;
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.cmd = PROP_MSG_LISTPROP;
|
||||
|
||||
err = send_prop_msg(&msg, propfn, cookie);
|
||||
if (err < 0)
|
||||
/* fallback to property cache */
|
||||
hybris_propcache_list((hybris_propcache_list_cb) propfn, cookie);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int property_get_socket(const char *key, char *value, const char *default_value)
|
||||
{
|
||||
int err;
|
||||
prop_msg_t msg;
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.cmd = PROP_MSG_GETPROP;
|
||||
|
||||
if (key) {
|
||||
strncpy(msg.name, key, sizeof(msg.name));
|
||||
err = send_prop_msg(&msg, NULL, NULL);
|
||||
if (err < 0)
|
||||
return err;
|
||||
}
|
||||
|
||||
/* In case it's null, just use the default */
|
||||
if ((strlen(msg.value) == 0) && (default_value)) {
|
||||
if (strlen(default_value) >= PROP_VALUE_MAX -1) return -1;
|
||||
strcpy(msg.value, default_value);
|
||||
}
|
||||
|
||||
strcpy(value, msg.value);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int property_get(const char *key, char *value, const char *default_value)
|
||||
{
|
||||
char *ret = NULL;
|
||||
|
||||
if ((key) && (strlen(key) >= PROP_NAME_MAX -1)) return -1;
|
||||
if (value == NULL) return -1;
|
||||
|
||||
if (property_get_socket(key, value, default_value) == 0)
|
||||
return strlen(value);
|
||||
|
||||
/* In case the socket is not available, search the property file cache by hand */
|
||||
ret = hybris_propcache_find(key);
|
||||
|
||||
if (ret) {
|
||||
strcpy(value, ret);
|
||||
return strlen(value);
|
||||
} else if (default_value != NULL) {
|
||||
strcpy(value, default_value);
|
||||
return strlen(value);
|
||||
} else {
|
||||
value = '\0';
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int property_set(const char *key, const char *value)
|
||||
{
|
||||
int err;
|
||||
prop_msg_t msg;
|
||||
|
||||
if (key == 0) return -1;
|
||||
if (value == 0) value = "";
|
||||
if (strlen(key) >= PROP_NAME_MAX -1) return -1;
|
||||
if (strlen(value) >= PROP_VALUE_MAX -1) return -1;
|
||||
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
msg.cmd = PROP_MSG_SETPROP;
|
||||
strncpy(msg.name, key, sizeof(msg.name));
|
||||
strncpy(msg.value, value, sizeof(msg.value));
|
||||
|
||||
err = send_prop_msg(&msg, NULL, NULL);
|
||||
if (err < 0) {
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// vim:ts=4:sw=4:noexpandtab
|
||||
26
hybris/src/properties_p.h
Normal file
26
hybris/src/properties_p.h
Normal file
@ -0,0 +1,26 @@
|
||||
/*
|
||||
* Copyright (c) 2013 Jolla Ltd. <robin.burchell@jollamobile.com>
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef HYBRIS_PROPERTIES
|
||||
#define HYBRIS_PROPERTIES
|
||||
|
||||
typedef void (*hybris_propcache_list_cb)(const char *key, const char *value, void *cookie);
|
||||
|
||||
void hybris_propcache_list(hybris_propcache_list_cb cb, void *cookie);
|
||||
char *hybris_propcache_find(const char *key);
|
||||
|
||||
#endif
|
||||
51
hybris/src/strlcpy.c
Normal file
51
hybris/src/strlcpy.c
Normal file
@ -0,0 +1,51 @@
|
||||
/* $OpenBSD: strlcpy.c,v 1.11 2006/05/05 15:27:38 millert Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1998 Todd C. Miller <Todd.Miller@courtesan.com>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/types.h>
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
* Copy src to string dst of size siz. At most siz-1 characters
|
||||
* will be copied. Always NUL terminates (unless siz == 0).
|
||||
* Returns strlen(src); if retval >= siz, truncation occurred.
|
||||
*/
|
||||
size_t
|
||||
strlcpy(char *dst, const char *src, size_t siz)
|
||||
{
|
||||
char *d = dst;
|
||||
const char *s = src;
|
||||
size_t n = siz;
|
||||
|
||||
/* Copy as many bytes as will fit */
|
||||
if (n != 0) {
|
||||
while (--n != 0) {
|
||||
if ((*d++ = *s++) == '\0')
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Not enough room in dst, add NUL and traverse rest of src */
|
||||
if (n == 0) {
|
||||
if (siz != 0)
|
||||
*d = '\0'; /* NUL-terminate dst */
|
||||
while (*s++)
|
||||
;
|
||||
}
|
||||
|
||||
return(s - src - 1); /* count does not include NUL */
|
||||
}
|
||||
376
hybris/src/sysconf.c
Normal file
376
hybris/src/sysconf.c
Normal file
@ -0,0 +1,376 @@
|
||||
#include <unistd.h>
|
||||
|
||||
/*
|
||||
* bionic/libc/include/sys/sysconf.h processed with s/define _\(\w*\)\(.*\)/define \1\2\r#ifdef _\1\rMAP_TO_UNISTD(\1),\r#endif/g
|
||||
*/
|
||||
#define MAP_TO_UNISTD(a) [a]=_##a
|
||||
static int sysconf_map[]= {
|
||||
#define SC_ARG_MAX 0x0000
|
||||
#ifdef _SC_ARG_MAX
|
||||
MAP_TO_UNISTD(SC_ARG_MAX),
|
||||
#endif
|
||||
#define SC_BC_BASE_MAX 0x0001
|
||||
#ifdef _SC_BC_BASE_MAX
|
||||
MAP_TO_UNISTD(SC_BC_BASE_MAX),
|
||||
#endif
|
||||
#define SC_BC_DIM_MAX 0x0002
|
||||
#ifdef _SC_BC_DIM_MAX
|
||||
MAP_TO_UNISTD(SC_BC_DIM_MAX),
|
||||
#endif
|
||||
#define SC_BC_SCALE_MAX 0x0003
|
||||
#ifdef _SC_BC_SCALE_MAX
|
||||
MAP_TO_UNISTD(SC_BC_SCALE_MAX),
|
||||
#endif
|
||||
#define SC_BC_STRING_MAX 0x0004
|
||||
#ifdef _SC_BC_STRING_MAX
|
||||
MAP_TO_UNISTD(SC_BC_STRING_MAX),
|
||||
#endif
|
||||
#define SC_CHILD_MAX 0x0005
|
||||
#ifdef _SC_CHILD_MAX
|
||||
MAP_TO_UNISTD(SC_CHILD_MAX),
|
||||
#endif
|
||||
#define SC_CLK_TCK 0x0006
|
||||
#ifdef _SC_CLK_TCK
|
||||
MAP_TO_UNISTD(SC_CLK_TCK),
|
||||
#endif
|
||||
#define SC_COLL_WEIGHTS_MAX 0x0007
|
||||
#ifdef _SC_COLL_WEIGHTS_MAX
|
||||
MAP_TO_UNISTD(SC_COLL_WEIGHTS_MAX),
|
||||
#endif
|
||||
#define SC_EXPR_NEST_MAX 0x0008
|
||||
#ifdef _SC_EXPR_NEST_MAX
|
||||
MAP_TO_UNISTD(SC_EXPR_NEST_MAX),
|
||||
#endif
|
||||
#define SC_LINE_MAX 0x0009
|
||||
#ifdef _SC_LINE_MAX
|
||||
MAP_TO_UNISTD(SC_LINE_MAX),
|
||||
#endif
|
||||
#define SC_NGROUPS_MAX 0x000a
|
||||
#ifdef _SC_NGROUPS_MAX
|
||||
MAP_TO_UNISTD(SC_NGROUPS_MAX),
|
||||
#endif
|
||||
#define SC_OPEN_MAX 0x000b
|
||||
#ifdef _SC_OPEN_MAX
|
||||
MAP_TO_UNISTD(SC_OPEN_MAX),
|
||||
#endif
|
||||
#define SC_PASS_MAX 0x000c
|
||||
#ifdef _SC_PASS_MAX
|
||||
MAP_TO_UNISTD(SC_PASS_MAX),
|
||||
#endif
|
||||
#define SC_2_C_BIND 0x000d
|
||||
#ifdef _SC_2_C_BIND
|
||||
MAP_TO_UNISTD(SC_2_C_BIND),
|
||||
#endif
|
||||
#define SC_2_C_DEV 0x000e
|
||||
#ifdef _SC_2_C_DEV
|
||||
MAP_TO_UNISTD(SC_2_C_DEV),
|
||||
#endif
|
||||
#define SC_2_C_VERSION 0x000f
|
||||
#ifdef _SC_2_C_VERSION
|
||||
MAP_TO_UNISTD(SC_2_C_VERSION),
|
||||
#endif
|
||||
#define SC_2_CHAR_TERM 0x0010
|
||||
#ifdef _SC_2_CHAR_TERM
|
||||
MAP_TO_UNISTD(SC_2_CHAR_TERM),
|
||||
#endif
|
||||
#define SC_2_FORT_DEV 0x0011
|
||||
#ifdef _SC_2_FORT_DEV
|
||||
MAP_TO_UNISTD(SC_2_FORT_DEV),
|
||||
#endif
|
||||
#define SC_2_FORT_RUN 0x0012
|
||||
#ifdef _SC_2_FORT_RUN
|
||||
MAP_TO_UNISTD(SC_2_FORT_RUN),
|
||||
#endif
|
||||
#define SC_2_LOCALEDEF 0x0013
|
||||
#ifdef _SC_2_LOCALEDEF
|
||||
MAP_TO_UNISTD(SC_2_LOCALEDEF),
|
||||
#endif
|
||||
#define SC_2_SW_DEV 0x0014
|
||||
#ifdef _SC_2_SW_DEV
|
||||
MAP_TO_UNISTD(SC_2_SW_DEV),
|
||||
#endif
|
||||
#define SC_2_UPE 0x0015
|
||||
#ifdef _SC_2_UPE
|
||||
MAP_TO_UNISTD(SC_2_UPE),
|
||||
#endif
|
||||
#define SC_2_VERSION 0x0016
|
||||
#ifdef _SC_2_VERSION
|
||||
MAP_TO_UNISTD(SC_2_VERSION),
|
||||
#endif
|
||||
#define SC_JOB_CONTROL 0x0017
|
||||
#ifdef _SC_JOB_CONTROL
|
||||
MAP_TO_UNISTD(SC_JOB_CONTROL),
|
||||
#endif
|
||||
#define SC_SAVED_IDS 0x0018
|
||||
#ifdef _SC_SAVED_IDS
|
||||
MAP_TO_UNISTD(SC_SAVED_IDS),
|
||||
#endif
|
||||
#define SC_VERSION 0x0019
|
||||
#ifdef _SC_VERSION
|
||||
MAP_TO_UNISTD(SC_VERSION),
|
||||
#endif
|
||||
#define SC_RE_DUP_MAX 0x001a
|
||||
#ifdef _SC_RE_DUP_MAX
|
||||
MAP_TO_UNISTD(SC_RE_DUP_MAX),
|
||||
#endif
|
||||
#define SC_STREAM_MAX 0x001b
|
||||
#ifdef _SC_STREAM_MAX
|
||||
MAP_TO_UNISTD(SC_STREAM_MAX),
|
||||
#endif
|
||||
#define SC_TZNAME_MAX 0x001c
|
||||
#ifdef _SC_TZNAME_MAX
|
||||
MAP_TO_UNISTD(SC_TZNAME_MAX),
|
||||
#endif
|
||||
#define SC_XOPEN_CRYPT 0x001d
|
||||
#ifdef _SC_XOPEN_CRYPT
|
||||
MAP_TO_UNISTD(SC_XOPEN_CRYPT),
|
||||
#endif
|
||||
#define SC_XOPEN_ENH_I18N 0x001e
|
||||
#ifdef _SC_XOPEN_ENH_I18N
|
||||
MAP_TO_UNISTD(SC_XOPEN_ENH_I18N),
|
||||
#endif
|
||||
#define SC_XOPEN_SHM 0x001f
|
||||
#ifdef _SC_XOPEN_SHM
|
||||
MAP_TO_UNISTD(SC_XOPEN_SHM),
|
||||
#endif
|
||||
#define SC_XOPEN_VERSION 0x0020
|
||||
#ifdef _SC_XOPEN_VERSION
|
||||
MAP_TO_UNISTD(SC_XOPEN_VERSION),
|
||||
#endif
|
||||
#define SC_XOPEN_XCU_VERSION 0x0021
|
||||
#ifdef _SC_XOPEN_XCU_VERSION
|
||||
MAP_TO_UNISTD(SC_XOPEN_XCU_VERSION),
|
||||
#endif
|
||||
#define SC_XOPEN_REALTIME 0x0022
|
||||
#ifdef _SC_XOPEN_REALTIME
|
||||
MAP_TO_UNISTD(SC_XOPEN_REALTIME),
|
||||
#endif
|
||||
#define SC_XOPEN_REALTIME_THREADS 0x0023
|
||||
#ifdef _SC_XOPEN_REALTIME_THREADS
|
||||
MAP_TO_UNISTD(SC_XOPEN_REALTIME_THREADS),
|
||||
#endif
|
||||
#define SC_XOPEN_LEGACY 0x0024
|
||||
#ifdef _SC_XOPEN_LEGACY
|
||||
MAP_TO_UNISTD(SC_XOPEN_LEGACY),
|
||||
#endif
|
||||
#define SC_ATEXIT_MAX 0x0025
|
||||
#ifdef _SC_ATEXIT_MAX
|
||||
MAP_TO_UNISTD(SC_ATEXIT_MAX),
|
||||
#endif
|
||||
#define SC_IOV_MAX 0x0026
|
||||
#ifdef _SC_IOV_MAX
|
||||
MAP_TO_UNISTD(SC_IOV_MAX),
|
||||
#endif
|
||||
#define SC_PAGESIZE 0x0027
|
||||
#ifdef _SC_PAGESIZE
|
||||
MAP_TO_UNISTD(SC_PAGESIZE),
|
||||
#endif
|
||||
#define SC_PAGE_SIZE 0x0028
|
||||
#ifdef _SC_PAGE_SIZE
|
||||
MAP_TO_UNISTD(SC_PAGE_SIZE),
|
||||
#endif
|
||||
#define SC_XOPEN_UNIX 0x0029
|
||||
#ifdef _SC_XOPEN_UNIX
|
||||
MAP_TO_UNISTD(SC_XOPEN_UNIX),
|
||||
#endif
|
||||
#define SC_XBS5_ILP32_OFF32 0x002a
|
||||
#ifdef _SC_XBS5_ILP32_OFF32
|
||||
MAP_TO_UNISTD(SC_XBS5_ILP32_OFF32),
|
||||
#endif
|
||||
#define SC_XBS5_ILP32_OFFBIG 0x002b
|
||||
#ifdef _SC_XBS5_ILP32_OFFBIG
|
||||
MAP_TO_UNISTD(SC_XBS5_ILP32_OFFBIG),
|
||||
#endif
|
||||
#define SC_XBS5_LP64_OFF64 0x002c
|
||||
#ifdef _SC_XBS5_LP64_OFF64
|
||||
MAP_TO_UNISTD(SC_XBS5_LP64_OFF64),
|
||||
#endif
|
||||
#define SC_XBS5_LPBIG_OFFBIG 0x002d
|
||||
#ifdef _SC_XBS5_LPBIG_OFFBIG
|
||||
MAP_TO_UNISTD(SC_XBS5_LPBIG_OFFBIG),
|
||||
#endif
|
||||
#define SC_AIO_LISTIO_MAX 0x002e
|
||||
#ifdef _SC_AIO_LISTIO_MAX
|
||||
MAP_TO_UNISTD(SC_AIO_LISTIO_MAX),
|
||||
#endif
|
||||
#define SC_AIO_MAX 0x002f
|
||||
#ifdef _SC_AIO_MAX
|
||||
MAP_TO_UNISTD(SC_AIO_MAX),
|
||||
#endif
|
||||
#define SC_AIO_PRIO_DELTA_MAX 0x0030
|
||||
#ifdef _SC_AIO_PRIO_DELTA_MAX
|
||||
MAP_TO_UNISTD(SC_AIO_PRIO_DELTA_MAX),
|
||||
#endif
|
||||
#define SC_DELAYTIMER_MAX 0x0031
|
||||
#ifdef _SC_DELAYTIMER_MAX
|
||||
MAP_TO_UNISTD(SC_DELAYTIMER_MAX),
|
||||
#endif
|
||||
#define SC_MQ_OPEN_MAX 0x0032
|
||||
#ifdef _SC_MQ_OPEN_MAX
|
||||
MAP_TO_UNISTD(SC_MQ_OPEN_MAX),
|
||||
#endif
|
||||
#define SC_MQ_PRIO_MAX 0x0033
|
||||
#ifdef _SC_MQ_PRIO_MAX
|
||||
MAP_TO_UNISTD(SC_MQ_PRIO_MAX),
|
||||
#endif
|
||||
#define SC_RTSIG_MAX 0x0034
|
||||
#ifdef _SC_RTSIG_MAX
|
||||
MAP_TO_UNISTD(SC_RTSIG_MAX),
|
||||
#endif
|
||||
#define SC_SEM_NSEMS_MAX 0x0035
|
||||
#ifdef _SC_SEM_NSEMS_MAX
|
||||
MAP_TO_UNISTD(SC_SEM_NSEMS_MAX),
|
||||
#endif
|
||||
#define SC_SEM_VALUE_MAX 0x0036
|
||||
#ifdef _SC_SEM_VALUE_MAX
|
||||
MAP_TO_UNISTD(SC_SEM_VALUE_MAX),
|
||||
#endif
|
||||
#define SC_SIGQUEUE_MAX 0x0037
|
||||
#ifdef _SC_SIGQUEUE_MAX
|
||||
MAP_TO_UNISTD(SC_SIGQUEUE_MAX),
|
||||
#endif
|
||||
#define SC_TIMER_MAX 0x0038
|
||||
#ifdef _SC_TIMER_MAX
|
||||
MAP_TO_UNISTD(SC_TIMER_MAX),
|
||||
#endif
|
||||
#define SC_ASYNCHRONOUS_IO 0x0039
|
||||
#ifdef _SC_ASYNCHRONOUS_IO
|
||||
MAP_TO_UNISTD(SC_ASYNCHRONOUS_IO),
|
||||
#endif
|
||||
#define SC_FSYNC 0x003a
|
||||
#ifdef _SC_FSYNC
|
||||
MAP_TO_UNISTD(SC_FSYNC),
|
||||
#endif
|
||||
#define SC_MAPPED_FILES 0x003b
|
||||
#ifdef _SC_MAPPED_FILES
|
||||
MAP_TO_UNISTD(SC_MAPPED_FILES),
|
||||
#endif
|
||||
#define SC_MEMLOCK 0x003c
|
||||
#ifdef _SC_MEMLOCK
|
||||
MAP_TO_UNISTD(SC_MEMLOCK),
|
||||
#endif
|
||||
#define SC_MEMLOCK_RANGE 0x003d
|
||||
#ifdef _SC_MEMLOCK_RANGE
|
||||
MAP_TO_UNISTD(SC_MEMLOCK_RANGE),
|
||||
#endif
|
||||
#define SC_MEMORY_PROTECTION 0x003e
|
||||
#ifdef _SC_MEMORY_PROTECTION
|
||||
MAP_TO_UNISTD(SC_MEMORY_PROTECTION),
|
||||
#endif
|
||||
#define SC_MESSAGE_PASSING 0x003f
|
||||
#ifdef _SC_MESSAGE_PASSING
|
||||
MAP_TO_UNISTD(SC_MESSAGE_PASSING),
|
||||
#endif
|
||||
#define SC_PRIORITIZED_IO 0x0040
|
||||
#ifdef _SC_PRIORITIZED_IO
|
||||
MAP_TO_UNISTD(SC_PRIORITIZED_IO),
|
||||
#endif
|
||||
#define SC_PRIORITY_SCHEDULING 0x0041
|
||||
#ifdef _SC_PRIORITY_SCHEDULING
|
||||
MAP_TO_UNISTD(SC_PRIORITY_SCHEDULING),
|
||||
#endif
|
||||
#define SC_REALTIME_SIGNALS 0x0042
|
||||
#ifdef _SC_REALTIME_SIGNALS
|
||||
MAP_TO_UNISTD(SC_REALTIME_SIGNALS),
|
||||
#endif
|
||||
#define SC_SEMAPHORES 0x0043
|
||||
#ifdef _SC_SEMAPHORES
|
||||
MAP_TO_UNISTD(SC_SEMAPHORES),
|
||||
#endif
|
||||
#define SC_SHARED_MEMORY_OBJECTS 0x0044
|
||||
#ifdef _SC_SHARED_MEMORY_OBJECTS
|
||||
MAP_TO_UNISTD(SC_SHARED_MEMORY_OBJECTS),
|
||||
#endif
|
||||
#define SC_SYNCHRONIZED_IO 0x0045
|
||||
#ifdef _SC_SYNCHRONIZED_IO
|
||||
MAP_TO_UNISTD(SC_SYNCHRONIZED_IO),
|
||||
#endif
|
||||
#define SC_TIMERS 0x0046
|
||||
#ifdef _SC_TIMERS
|
||||
MAP_TO_UNISTD(SC_TIMERS),
|
||||
#endif
|
||||
#define SC_GETGR_R_SIZE_MAX 0x0047
|
||||
#ifdef _SC_GETGR_R_SIZE_MAX
|
||||
MAP_TO_UNISTD(SC_GETGR_R_SIZE_MAX),
|
||||
#endif
|
||||
#define SC_GETPW_R_SIZE_MAX 0x0048
|
||||
#ifdef _SC_GETPW_R_SIZE_MAX
|
||||
MAP_TO_UNISTD(SC_GETPW_R_SIZE_MAX),
|
||||
#endif
|
||||
#define SC_LOGIN_NAME_MAX 0x0049
|
||||
#ifdef _SC_LOGIN_NAME_MAX
|
||||
MAP_TO_UNISTD(SC_LOGIN_NAME_MAX),
|
||||
#endif
|
||||
#define SC_THREAD_DESTRUCTOR_ITERATIONS 0x004a
|
||||
#ifdef _SC_THREAD_DESTRUCTOR_ITERATIONS
|
||||
MAP_TO_UNISTD(SC_THREAD_DESTRUCTOR_ITERATIONS),
|
||||
#endif
|
||||
#define SC_THREAD_KEYS_MAX 0x004b
|
||||
#ifdef _SC_THREAD_KEYS_MAX
|
||||
MAP_TO_UNISTD(SC_THREAD_KEYS_MAX),
|
||||
#endif
|
||||
#define SC_THREAD_STACK_MIN 0x004c
|
||||
#ifdef _SC_THREAD_STACK_MIN
|
||||
MAP_TO_UNISTD(SC_THREAD_STACK_MIN),
|
||||
#endif
|
||||
#define SC_THREAD_THREADS_MAX 0x004d
|
||||
#ifdef _SC_THREAD_THREADS_MAX
|
||||
MAP_TO_UNISTD(SC_THREAD_THREADS_MAX),
|
||||
#endif
|
||||
#define SC_TTY_NAME_MAX 0x004e
|
||||
#ifdef _SC_TTY_NAME_MAX
|
||||
MAP_TO_UNISTD(SC_TTY_NAME_MAX),
|
||||
#endif
|
||||
|
||||
#define SC_THREADS 0x004f
|
||||
#ifdef _SC_THREADS
|
||||
MAP_TO_UNISTD(SC_THREADS),
|
||||
#endif
|
||||
#define SC_THREAD_ATTR_STACKADDR 0x0050
|
||||
#ifdef _SC_THREAD_ATTR_STACKADDR
|
||||
MAP_TO_UNISTD(SC_THREAD_ATTR_STACKADDR),
|
||||
#endif
|
||||
#define SC_THREAD_ATTR_STACKSIZE 0x0051
|
||||
#ifdef _SC_THREAD_ATTR_STACKSIZE
|
||||
MAP_TO_UNISTD(SC_THREAD_ATTR_STACKSIZE),
|
||||
#endif
|
||||
#define SC_THREAD_PRIORITY_SCHEDULING 0x0052
|
||||
#ifdef _SC_THREAD_PRIORITY_SCHEDULING
|
||||
MAP_TO_UNISTD(SC_THREAD_PRIORITY_SCHEDULING),
|
||||
#endif
|
||||
#define SC_THREAD_PRIO_INHERIT 0x0053
|
||||
#ifdef _SC_THREAD_PRIO_INHERIT
|
||||
MAP_TO_UNISTD(SC_THREAD_PRIO_INHERIT),
|
||||
#endif
|
||||
#define SC_THREAD_PRIO_PROTECT 0x0054
|
||||
#ifdef _SC_THREAD_PRIO_PROTECT
|
||||
MAP_TO_UNISTD(SC_THREAD_PRIO_PROTECT),
|
||||
#endif
|
||||
#define SC_THREAD_SAFE_FUNCTIONS 0x0055
|
||||
#ifdef _SC_THREAD_SAFE_FUNCTIONS
|
||||
MAP_TO_UNISTD(SC_THREAD_SAFE_FUNCTIONS),
|
||||
#endif
|
||||
|
||||
#define SC_NPROCESSORS_CONF 0x0060
|
||||
#ifdef _SC_NPROCESSORS_CONF
|
||||
MAP_TO_UNISTD(SC_NPROCESSORS_CONF),
|
||||
#endif
|
||||
#define SC_NPROCESSORS_ONLN 0x0061
|
||||
#ifdef _SC_NPROCESSORS_ONLN
|
||||
MAP_TO_UNISTD(SC_NPROCESSORS_ONLN),
|
||||
#endif
|
||||
#define SC_PHYS_PAGES 0x0062
|
||||
#ifdef _SC_PHYS_PAGES
|
||||
MAP_TO_UNISTD(SC_PHYS_PAGES),
|
||||
#endif
|
||||
#define SC_AVPHYS_PAGES 0x0063
|
||||
#ifdef _SC_AVPHYS_PAGES
|
||||
MAP_TO_UNISTD(SC_AVPHYS_PAGES),
|
||||
#endif
|
||||
};
|
||||
#undef MAP_TO_UNISTD
|
||||
|
||||
long my_sysconf(int name)
|
||||
{
|
||||
return sysconf(sysconf_map[name]);
|
||||
}
|
||||
29
mcpe/App.h
Normal file
29
mcpe/App.h
Normal file
@ -0,0 +1,29 @@
|
||||
#pragma once
|
||||
|
||||
class AppPlatform;
|
||||
struct AppContext {
|
||||
char filler[0x10];
|
||||
AppPlatform* platform;
|
||||
bool doRender;
|
||||
};
|
||||
|
||||
class App {
|
||||
|
||||
public:
|
||||
static void (*App_init)(App*, AppContext&);
|
||||
|
||||
void** vtable;
|
||||
|
||||
void init(AppContext& ctx) {
|
||||
App_init(this, ctx);
|
||||
}
|
||||
|
||||
void quit() {
|
||||
((void (*)(App*)) vtable[23])(this);
|
||||
}
|
||||
|
||||
bool wantToQuit() {
|
||||
return ((bool (*)(App*)) vtable[24])(this);
|
||||
}
|
||||
|
||||
};
|
||||
27
mcpe/AppPlatform.h
Normal file
27
mcpe/AppPlatform.h
Normal file
@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
class AppPlatform {
|
||||
|
||||
public:
|
||||
static void** myVtable;
|
||||
|
||||
static void (*AppPlatform_construct)(AppPlatform*);
|
||||
static void (*AppPlatform_initialize)(AppPlatform*);
|
||||
static void (*AppPlatform__fireAppFocusGained)(AppPlatform*);
|
||||
|
||||
void** vtable;
|
||||
char filler [0x1000];
|
||||
|
||||
AppPlatform() {
|
||||
AppPlatform_construct(this);
|
||||
}
|
||||
|
||||
static AppPlatform** _singleton;
|
||||
void _fireAppFocusGained() {
|
||||
AppPlatform__fireAppFocusGained(this);
|
||||
}
|
||||
void initialize() {
|
||||
AppPlatform_initialize(this);
|
||||
}
|
||||
|
||||
};
|
||||
24
mcpe/FilePickerSettings.h
Normal file
24
mcpe/FilePickerSettings.h
Normal file
@ -0,0 +1,24 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
|
||||
struct FilePickerSettings {
|
||||
|
||||
enum class PickerType {
|
||||
NONE, OPEN, SAVE
|
||||
};
|
||||
struct FileDescription {
|
||||
std::string ext, desc;
|
||||
};
|
||||
|
||||
char filler [0x20]; // 20
|
||||
std::function<void (FilePickerSettings&, std::string)> pickedCallback; // 30
|
||||
std::vector<FileDescription> fileDescriptions; // 3c
|
||||
int filler3; // 40
|
||||
PickerType type; // 44
|
||||
std::string defaultFileName; // 48
|
||||
std::string pickerTitle; // 52
|
||||
|
||||
};
|
||||
12
mcpe/ImagePickingCallback.h
Normal file
12
mcpe/ImagePickingCallback.h
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
class ImagePickingCallback {
|
||||
|
||||
public:
|
||||
virtual ~ImagePickingCallback();
|
||||
virtual void onImagePickingSuccess(const std::string&);
|
||||
virtual void onImagePickingCanceled();
|
||||
|
||||
};
|
||||
17
mcpe/Keyboard.h
Normal file
17
mcpe/Keyboard.h
Normal file
@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
struct KeyboardAction {
|
||||
int action;
|
||||
int keyCode;
|
||||
};
|
||||
|
||||
class Keyboard {
|
||||
|
||||
public:
|
||||
|
||||
static void (*Keyboard_feedText)(const std::string&, bool, unsigned char);
|
||||
|
||||
static std::vector<KeyboardAction>* inputs;
|
||||
static int* states;
|
||||
|
||||
};
|
||||
38
mcpe/MinecraftGame.h
Normal file
38
mcpe/MinecraftGame.h
Normal file
@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include "App.h"
|
||||
|
||||
class Options;
|
||||
|
||||
class MinecraftGame : public App {
|
||||
|
||||
public:
|
||||
static void (*MinecraftGame_construct)(MinecraftGame*, int, char**);
|
||||
static void (*MinecraftGame_update)(MinecraftGame*);
|
||||
static void (*MinecraftGame_setRenderingSize)(MinecraftGame*, int, int);
|
||||
static void (*MinecraftGame_setUISizeAndScale)(MinecraftGame*, int, int, float);
|
||||
static Options* (*MinecraftGame_getOptions)(MinecraftGame*);
|
||||
|
||||
char filler [0x4000-4];
|
||||
|
||||
MinecraftGame(int carg, char** args) {
|
||||
MinecraftGame_construct(this, carg, args);
|
||||
}
|
||||
|
||||
void update() {
|
||||
MinecraftGame_update(this);
|
||||
}
|
||||
|
||||
void setRenderingSize(int w, int h) {
|
||||
MinecraftGame_setRenderingSize(this, w, h);
|
||||
}
|
||||
|
||||
void setUISizeAndScale(int w, int h, float px) {
|
||||
MinecraftGame_setUISizeAndScale(this, w, h, px);
|
||||
}
|
||||
|
||||
Options* getOptions() {
|
||||
return MinecraftGame_getOptions(this);
|
||||
}
|
||||
|
||||
};
|
||||
8
mcpe/Mouse.h
Normal file
8
mcpe/Mouse.h
Normal file
@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
class Mouse {
|
||||
|
||||
public:
|
||||
static void (*feed)(char button, char type, short x, short y, short dx, short dy);
|
||||
|
||||
};
|
||||
16
mcpe/Options.h
Normal file
16
mcpe/Options.h
Normal file
@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
|
||||
class Options {
|
||||
|
||||
public:
|
||||
static bool (*Options_getFullscreen)(Options*);
|
||||
static void (*Options_setFullscreen)(Options*, bool);
|
||||
|
||||
bool getFullscreen() {
|
||||
return Options_getFullscreen(this);
|
||||
}
|
||||
void setFullscreen(bool b) {
|
||||
Options_setFullscreen(this, b);
|
||||
}
|
||||
|
||||
};
|
||||
23
mcpe/gl.h
Normal file
23
mcpe/gl.h
Normal file
@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
struct gl {
|
||||
static std::string (*getOpenGLVendor)();
|
||||
static std::string (*getOpenGLRenderer)();
|
||||
static std::string (*getOpenGLVersion)();
|
||||
static std::string (*getOpenGLExtensions)();
|
||||
};
|
||||
|
||||
namespace mce {
|
||||
|
||||
namespace Platform {
|
||||
|
||||
struct OGL {
|
||||
|
||||
static void (*OGL_initBindings)();
|
||||
static void initBindings() { OGL_initBindings(); }
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
45
mcpe/types.cpp
Normal file
45
mcpe/types.cpp
Normal file
@ -0,0 +1,45 @@
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "AppPlatform.h"
|
||||
|
||||
AppPlatform** AppPlatform::_singleton = nullptr;
|
||||
void** AppPlatform::myVtable = nullptr;
|
||||
void (*AppPlatform::AppPlatform_construct)(AppPlatform*);
|
||||
void (*AppPlatform::AppPlatform__fireAppFocusGained)(AppPlatform*);
|
||||
void (*AppPlatform::AppPlatform_initialize)(AppPlatform*);
|
||||
|
||||
#include "App.h"
|
||||
|
||||
void (*App::App_init)(App*, AppContext&);
|
||||
|
||||
#include "MinecraftGame.h"
|
||||
|
||||
void (*MinecraftGame::MinecraftGame_construct)(MinecraftGame*, int, char**);
|
||||
void (*MinecraftGame::MinecraftGame_update)(MinecraftGame*);
|
||||
void (*MinecraftGame::MinecraftGame_setRenderingSize)(MinecraftGame*, int, int);
|
||||
void (*MinecraftGame::MinecraftGame_setUISizeAndScale)(MinecraftGame*, int, int, float);
|
||||
Options* (*MinecraftGame::MinecraftGame_getOptions)(MinecraftGame*);
|
||||
|
||||
#include "Options.h"
|
||||
|
||||
bool (*Options::Options_getFullscreen)(Options*);
|
||||
void (*Options::Options_setFullscreen)(Options*, bool);
|
||||
|
||||
#include "gl.h"
|
||||
|
||||
std::string (*gl::getOpenGLVendor)();
|
||||
std::string (*gl::getOpenGLRenderer)();
|
||||
std::string (*gl::getOpenGLVersion)();
|
||||
std::string (*gl::getOpenGLExtensions)();
|
||||
void (*mce::Platform::OGL::OGL_initBindings)();
|
||||
|
||||
#include "Mouse.h"
|
||||
|
||||
void (*Mouse::feed)(char, char, short, short, short, short);
|
||||
|
||||
#include "Keyboard.h"
|
||||
|
||||
void (*Keyboard::Keyboard_feedText)(const std::string&, bool, unsigned char);
|
||||
std::vector<KeyboardAction>* Keyboard::inputs;
|
||||
int* Keyboard::states;
|
||||
4
mod_example/README.md
Normal file
4
mod_example/README.md
Normal file
@ -0,0 +1,4 @@
|
||||
Example modification
|
||||
====================
|
||||
|
||||
To compile this modification, use ndk-build in this directory. Then you should copy the output .so from libs/x86/ to the launcher's mods/ directory.
|
||||
10
mod_example/jni/Android.mk
Normal file
10
mod_example/jni/Android.mk
Normal file
@ -0,0 +1,10 @@
|
||||
LOCAL_PATH := $(call my-dir)
|
||||
CWD := $(shell pwd)
|
||||
|
||||
include $(CLEAR_VARS)
|
||||
|
||||
LOCAL_MODULE := mcpelauncher_testmod
|
||||
LOCAL_SRC_FILES := main.cpp
|
||||
LOCAL_LDLIBS := -L$(LOCAL_PATH)/../../libs/ -ldl -lmcpelauncher_mod -lminecraftpe
|
||||
|
||||
include $(BUILD_SHARED_LIBRARY)
|
||||
5
mod_example/jni/Application.mk
Normal file
5
mod_example/jni/Application.mk
Normal file
@ -0,0 +1,5 @@
|
||||
APP_ABI := x86
|
||||
APP_PLATFORM := android-21
|
||||
APP_CPPFLAGS += -std=c++11
|
||||
APP_STL := gnustl_static
|
||||
NDK_TOOLCHAIN_VERSION := 4.9
|
||||
21
mod_example/jni/main.cpp
Normal file
21
mod_example/jni/main.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
#include <iostream>
|
||||
|
||||
#include "mcpelauncher_api.h"
|
||||
|
||||
struct Common {
|
||||
static std::string getGameVersionString();
|
||||
static std::string (*$getGameVersionString)();
|
||||
static std::string $$getGameVersionString() {
|
||||
return "Hello world!";
|
||||
}
|
||||
};
|
||||
std::string (*Common::$getGameVersionString)();
|
||||
|
||||
extern "C" {
|
||||
|
||||
void mod_init() {
|
||||
std::cout << "init test mod\n";
|
||||
mcpelauncher_hook((void*) &Common::getGameVersionString, (void*) &Common::$$getGameVersionString, (void**) &Common::$getGameVersionString);
|
||||
}
|
||||
|
||||
}
|
||||
12
mod_example/jni/mcpelauncher_api.h
Normal file
12
mod_example/jni/mcpelauncher_api.h
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
void* mcpelauncher_hook(void* symbol, void* hook, void** original);
|
||||
void mcpelauncher_unhook(void* hook);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
196
src/LinuxAppPlatform.cpp
Normal file
196
src/LinuxAppPlatform.cpp
Normal file
@ -0,0 +1,196 @@
|
||||
#include "LinuxAppPlatform.h"
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
#include <sstream>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <png.h>
|
||||
#include <uuid/uuid.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include "../mcpe/ImagePickingCallback.h"
|
||||
#include "../mcpe/FilePickerSettings.h"
|
||||
#include "../hybris/src/jb/linker.h"
|
||||
|
||||
extern "C" {
|
||||
#include <eglut.h>
|
||||
#include "../hybris/include/hybris/dlfcn.h"
|
||||
}
|
||||
|
||||
void** LinuxAppPlatform::myVtable = nullptr;
|
||||
bool LinuxAppPlatform::mousePointerHidden = false;
|
||||
bool enablePocketGuis = false;
|
||||
bool serverMode = false;
|
||||
|
||||
LinuxAppPlatform::LinuxAppPlatform() : AppPlatform() {
|
||||
this->vtable = myVtable;
|
||||
internalStorage = "data/private/";
|
||||
externalStorage = "data/public/";
|
||||
currentStorage = "data/current/";
|
||||
userdata = "data/user/";
|
||||
userdataPathForLevels = "data/user/";
|
||||
region = "0xdeadbeef";
|
||||
tmpPath = "tmp/";
|
||||
}
|
||||
|
||||
#include <execinfo.h>
|
||||
#include <cxxabi.h>
|
||||
#include <dlfcn.h>
|
||||
|
||||
void LinuxAppPlatform::replaceVtableEntry(void* lib, void** vtable, const char* sym, void* nw) {
|
||||
void* sm = hybris_dlsym(lib, sym);
|
||||
for (int i = 0; ; i++) {
|
||||
if (vtable[i] == nullptr)
|
||||
break;
|
||||
if (vtable[i] == sm) {
|
||||
myVtable[i] = nw;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LinuxAppPlatform::initVtable(void* lib) {
|
||||
void** vt = AppPlatform::myVtable;
|
||||
void** vta = &((void**) hybris_dlsym(lib, "_ZTV19AppPlatform_android"))[2];
|
||||
// get vtable size
|
||||
int size;
|
||||
for (size = 2; ; size++) {
|
||||
if (vt[size] == nullptr)
|
||||
break;
|
||||
}
|
||||
printf("AppPlatform size = %i\n", size);
|
||||
|
||||
myVtable = (void**) ::operator new(size * sizeof(void*));
|
||||
memcpy(&myVtable[0], &vt[2], (size - 2) * sizeof(void*));
|
||||
|
||||
replaceVtableEntry(lib, vta, "_ZNK19AppPlatform_android10getDataUrlEv", (void*) &LinuxAppPlatform::getDataUrl);
|
||||
replaceVtableEntry(lib, vta, "_ZNK19AppPlatform_android14getUserDataUrlEv", (void*) &LinuxAppPlatform::getUserDataUrl);
|
||||
replaceVtableEntry(lib, vta, "_ZN19AppPlatform_android14getPackagePathEv", (void*) &LinuxAppPlatform::getPackagePath);
|
||||
replaceVtableEntry(lib, vta, "_ZN11AppPlatform16hideMousePointerEv", (void*) &LinuxAppPlatform::hideMousePointer);
|
||||
replaceVtableEntry(lib, vta, "_ZN11AppPlatform16showMousePointerEv", (void*) &LinuxAppPlatform::showMousePointer);
|
||||
replaceVtableEntry(lib, vta, "_ZN19AppPlatform_android11swapBuffersEv", (void*) &LinuxAppPlatform::swapBuffers);
|
||||
replaceVtableEntry(lib, vta, "_ZNK19AppPlatform_android15getSystemRegionEv", (void*) &LinuxAppPlatform::getSystemRegion);
|
||||
replaceVtableEntry(lib, vta, "_ZN19AppPlatform_android25getGraphicsTearingSupportEv", (void*) &LinuxAppPlatform::getGraphicsTearingSupport);
|
||||
replaceVtableEntry(lib, vta, "_ZN19AppPlatform_android9pickImageER20ImagePickingCallback", (void*) &LinuxAppPlatform::pickImage);
|
||||
replaceVtableEntry(lib, vta, "_ZN11AppPlatform8pickFileER18FilePickerSettings", (void*) &LinuxAppPlatform::pickFile);
|
||||
replaceVtableEntry(lib, vta, "_ZNK11AppPlatform19supportsFilePickingEv", (void*) &LinuxAppPlatform::supportsFilePicking);
|
||||
replaceVtableEntry(lib, vta, "_ZN19AppPlatform_android22getExternalStoragePathEv", (void*) &LinuxAppPlatform::getExternalStoragePath);
|
||||
replaceVtableEntry(lib, vta, "_ZN19AppPlatform_android22getInternalStoragePathEv", (void*) &LinuxAppPlatform::getInternalStoragePath);
|
||||
replaceVtableEntry(lib, vta, "_ZN19AppPlatform_android21getCurrentStoragePathEv", (void*) &LinuxAppPlatform::getCurrentStoragePath);
|
||||
replaceVtableEntry(lib, vta, "_ZN19AppPlatform_android15getUserdataPathEv", (void*) &LinuxAppPlatform::getUserdataPath);
|
||||
replaceVtableEntry(lib, vta, "_ZN19AppPlatform_android24getUserdataPathForLevelsEv", (void*) &LinuxAppPlatform::getUserdataPathForLevels);
|
||||
replaceVtableEntry(lib, vta, "_ZN11AppPlatform20getAssetFileFullPathERKSs", (void*) &LinuxAppPlatform::getAssetFileFullPath);
|
||||
replaceVtableEntry(lib, vta, "_ZNK11AppPlatform14useCenteredGUIEv", (void*) &LinuxAppPlatform::useCenteredGUI);
|
||||
replaceVtableEntry(lib, vta, "_ZN19AppPlatform_android16getApplicationIdEv", (void*) &LinuxAppPlatform::getApplicationId);
|
||||
replaceVtableEntry(lib, vta, "_ZN19AppPlatform_android18getAvailableMemoryEv", (void*) &LinuxAppPlatform::getAvailableMemory);
|
||||
replaceVtableEntry(lib, vta, "_ZN19AppPlatform_android11getDeviceIdEv", (void*) &LinuxAppPlatform::getDeviceId);
|
||||
replaceVtableEntry(lib, vta, "_ZN19AppPlatform_android10createUUIDEv", (void*) &LinuxAppPlatform::createUUID);
|
||||
replaceVtableEntry(lib, vta, "_ZN19AppPlatform_android18isFirstSnoopLaunchEv", (void*) &LinuxAppPlatform::isFirstSnoopLaunch);
|
||||
replaceVtableEntry(lib, vta, "_ZN19AppPlatform_android29hasHardwareInformationChangedEv", (void*) &LinuxAppPlatform::hasHardwareInformationChanged);
|
||||
replaceVtableEntry(lib, vta, "_ZN19AppPlatform_android8isTabletEv", (void*) &LinuxAppPlatform::isTablet);
|
||||
replaceVtableEntry(lib, vta, "_ZN11AppPlatform17setFullscreenModeE14FullscreenMode", (void*) &LinuxAppPlatform::setFullscreenMode);
|
||||
replaceVtableEntry(lib, vta, "_ZNK11AppPlatform10getEditionEv", (void*) &LinuxAppPlatform::getEdition);
|
||||
replaceVtableEntry(lib, vta, "_ZN19AppPlatform_android31calculateAvailableDiskFreeSpaceERKSs", (void*) &LinuxAppPlatform::calculateAvailableDiskFreeSpace);
|
||||
replaceVtableEntry(lib, vta, "_ZNK19AppPlatform_android25getPlatformUIScalingRulesEv", (void*) &LinuxAppPlatform::getPlatformUIScalingRules);
|
||||
replaceVtableEntry(lib, vta, "_ZN19AppPlatform_android19getPlatformTempPathEv", (void*) &LinuxAppPlatform::getPlatformTempPath);
|
||||
replaceVtableEntry(lib, vta, "_ZN19AppPlatform_android14createDeviceIDEv", (void*) &LinuxAppPlatform::createDeviceID);
|
||||
}
|
||||
|
||||
void LinuxAppPlatform::hideMousePointer() {
|
||||
mousePointerHidden = true;
|
||||
moveMouseToCenter = true;
|
||||
eglutSetMousePointerVisiblity(EGLUT_POINTER_INVISIBLE);
|
||||
}
|
||||
void LinuxAppPlatform::showMousePointer() {
|
||||
mousePointerHidden = false;
|
||||
eglutSetMousePointerVisiblity(EGLUT_POINTER_VISIBLE);
|
||||
}
|
||||
|
||||
std::string LinuxAppPlatform::_pickFile(std::string commandLine) {
|
||||
std::cout << "Launching file picker with args: " << commandLine << "\n";
|
||||
char file[1024];
|
||||
FILE *f = popen(commandLine.c_str(), "r");
|
||||
if (fgets(file, 1024, f) == nullptr) {
|
||||
std::cout << "No file selected\n";
|
||||
return "";
|
||||
}
|
||||
file[strlen(file) - 1] = '\0';
|
||||
std::cout << "Selected file: " << file << "\n";
|
||||
return std::string(file);
|
||||
}
|
||||
|
||||
void LinuxAppPlatform::pickImage(ImagePickingCallback &callback) {
|
||||
std::cout << "pickImage\n";
|
||||
std::string file = _pickFile("zenity --file-selection --title 'Select image' --file-filter *.png");
|
||||
if (file.empty()) {
|
||||
callback.onImagePickingCanceled();
|
||||
} else {
|
||||
callback.onImagePickingSuccess(file);
|
||||
}
|
||||
}
|
||||
|
||||
std::string replaceAll(std::string s, std::string a, std::string b) {
|
||||
while (true) {
|
||||
size_t p = s.find(a);
|
||||
if (p == std::string::npos)
|
||||
break;
|
||||
s.replace(p, a.length(), b);
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
||||
void LinuxAppPlatform::pickFile(FilePickerSettings &settings) {
|
||||
std::cout << "pickFile\n";
|
||||
std::cout << "- title: " << settings.pickerTitle << "\n";
|
||||
std::cout << "- type: " << (int) settings.type << "\n";
|
||||
std::cout << "- file descriptions:\n";
|
||||
for (FilePickerSettings::FileDescription &d : settings.fileDescriptions) {
|
||||
std::cout << " - " << d.ext << " " << d.desc << "\n";
|
||||
}
|
||||
std::stringstream ss;
|
||||
ss << "zenity --file-selection --title '" << replaceAll(settings.pickerTitle, "'", "\\'") << "'";
|
||||
if (settings.type == FilePickerSettings::PickerType::SAVE)
|
||||
ss << " --save";
|
||||
if (settings.fileDescriptions.size() > 0) {
|
||||
ss << " --file-filter '";
|
||||
bool first = true;
|
||||
for (FilePickerSettings::FileDescription &d : settings.fileDescriptions) {
|
||||
if (first)
|
||||
first = false;
|
||||
else
|
||||
ss << "|";
|
||||
ss << "*." << d.ext;
|
||||
}
|
||||
ss << "'";
|
||||
}
|
||||
std::string file = _pickFile(ss.str());
|
||||
settings.pickedCallback(settings, file);
|
||||
}
|
||||
|
||||
void LinuxAppPlatform::setFullscreenMode(int mode) {
|
||||
std::cout << "set fullscreen mode: " << mode << "\n";
|
||||
int newMode = mode == 1 ? EGLUT_FULLSCREEN : EGLUT_WINDOWED;
|
||||
if (eglutGet(EGLUT_FULLSCREEN_MODE) != newMode)
|
||||
eglutToggleFullscreen();
|
||||
}
|
||||
|
||||
std::string LinuxAppPlatform::createUUID() {
|
||||
srand(time(NULL));
|
||||
|
||||
uuid_t id;
|
||||
uuid_generate(id);
|
||||
char out [256];
|
||||
uuid_unparse(id, out);
|
||||
printf("uuid: %s\n", out);
|
||||
return std::string(out);
|
||||
}
|
||||
|
||||
long long LinuxAppPlatform::getAvailableMemory() {
|
||||
struct sysinfo memInfo;
|
||||
sysinfo (&memInfo);
|
||||
long long totalVirtualMem = memInfo.totalram;
|
||||
totalVirtualMem += memInfo.totalswap;
|
||||
totalVirtualMem *= memInfo.mem_unit;
|
||||
return totalVirtualMem;
|
||||
}
|
||||
145
src/LinuxAppPlatform.h
Normal file
145
src/LinuxAppPlatform.h
Normal file
@ -0,0 +1,145 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <unistd.h>
|
||||
#include <sys/param.h>
|
||||
#include "../mcpe/gl.h"
|
||||
#include "../mcpe/AppPlatform.h"
|
||||
#include "../mcpe/ImagePickingCallback.h"
|
||||
|
||||
class ImageData;
|
||||
class ImagePickingCallback;
|
||||
class FilePickerSettings;
|
||||
|
||||
extern bool enablePocketGuis;
|
||||
extern bool moveMouseToCenter;
|
||||
extern bool serverMode;
|
||||
|
||||
class LinuxAppPlatform : public AppPlatform {
|
||||
|
||||
private:
|
||||
static std::string _pickFile(std::string commandLine);
|
||||
|
||||
static void replaceVtableEntry(void* lib, void** vtable, const char* sym, void* nw);
|
||||
|
||||
public:
|
||||
static void** myVtable;
|
||||
static void initVtable(void* lib);
|
||||
|
||||
static bool mousePointerHidden;
|
||||
|
||||
std::string region;
|
||||
std::string internalStorage, externalStorage, currentStorage, userdata, userdataPathForLevels, tmpPath;
|
||||
|
||||
LinuxAppPlatform();
|
||||
|
||||
std::string getDataUrl() { // this is used only for sounds
|
||||
printf("get data url: assets/\n");
|
||||
return "assets/";
|
||||
}
|
||||
std::string getUserDataUrl() { // this is used only for sounds
|
||||
printf("get user data url: data/user/\n");
|
||||
return "data/user/";
|
||||
}
|
||||
|
||||
std::string getPackagePath() {
|
||||
return "assets/";
|
||||
}
|
||||
|
||||
void hideMousePointer();
|
||||
void showMousePointer();
|
||||
|
||||
void swapBuffers() {
|
||||
//printf("swap buffers\n");
|
||||
}
|
||||
std::string const& getSystemRegion() {
|
||||
printf("get system region: %s\n", region.c_str());
|
||||
return region;
|
||||
}
|
||||
|
||||
bool getGraphicsTearingSupport() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void pickImage(ImagePickingCallback& callback);
|
||||
void pickFile(FilePickerSettings& callback);
|
||||
bool supportsFilePicking() {
|
||||
return true;
|
||||
}
|
||||
std::string& getExternalStoragePath() {
|
||||
printf("external storage path = %s\n", externalStorage.c_str());
|
||||
return externalStorage;
|
||||
}
|
||||
std::string& getInternalStoragePath() {
|
||||
printf("internal storage path = %s\n", internalStorage.c_str());
|
||||
return internalStorage;
|
||||
}
|
||||
std::string& getCurrentStoragePath() {
|
||||
printf("current storage path = %s\n", currentStorage.c_str());
|
||||
return currentStorage;
|
||||
}
|
||||
std::string& getUserdataPath() {
|
||||
printf("userdata path = %s\n", userdata.c_str());
|
||||
return userdata;
|
||||
}
|
||||
std::string& getUserdataPathForLevels() {
|
||||
printf("userdata path for levels = %s\n", userdata.c_str());
|
||||
return userdataPathForLevels;
|
||||
}
|
||||
std::string getAssetFileFullPath(std::string const& s) {
|
||||
printf("get assert full path: %s\n", s.c_str());
|
||||
return "assets/" + s;
|
||||
}
|
||||
int getScreenType() {
|
||||
if (enablePocketGuis)
|
||||
return 1;
|
||||
return 0; // Win 10 Ed. GUIs
|
||||
}
|
||||
bool useCenteredGUI() {
|
||||
return (enablePocketGuis ? false : true);
|
||||
}
|
||||
std::string getApplicationId() {
|
||||
printf("application id = com.mojang.minecraftpe\n");
|
||||
return "com.mojang.minecraftpe";
|
||||
}
|
||||
std::string getDeviceId() {
|
||||
printf("device id = linux\n");
|
||||
return "linux";
|
||||
}
|
||||
std::string createUUID();
|
||||
bool isFirstSnoopLaunch() {
|
||||
printf("is first snoop launch = true\n");
|
||||
return true;
|
||||
}
|
||||
bool hasHardwareInformationChanged() {
|
||||
printf("has hardware information change = false\n");
|
||||
return false;
|
||||
}
|
||||
bool isTablet() {
|
||||
printf("is tablet = true\n");
|
||||
return true;
|
||||
}
|
||||
void setFullscreenMode(int mode);
|
||||
std::string getEdition() {
|
||||
if (enablePocketGuis)
|
||||
return "pocket";
|
||||
return "win10";
|
||||
}
|
||||
int getPlatformUIScalingRules() {
|
||||
return 2;
|
||||
}
|
||||
long long getAvailableMemory();
|
||||
|
||||
long long calculateAvailableDiskFreeSpace() {
|
||||
return 100000000L;
|
||||
}
|
||||
|
||||
std::string &getPlatformTempPath() {
|
||||
return tmpPath;
|
||||
}
|
||||
|
||||
std::string createDeviceID() {
|
||||
return "linux";
|
||||
}
|
||||
|
||||
};
|
||||
94
src/LinuxStore.h
Normal file
94
src/LinuxStore.h
Normal file
@ -0,0 +1,94 @@
|
||||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
|
||||
struct StoreListener;
|
||||
struct PurchaseInfo;
|
||||
struct LinuxStore {
|
||||
virtual ~LinuxStore() {
|
||||
std::cout << "destroying store\n";
|
||||
}
|
||||
virtual bool requiresRestorePurchasesButton() {
|
||||
std::cout << "requires restore purchases button: false\n";
|
||||
return false;
|
||||
}
|
||||
virtual bool allowsSubscriptions() {
|
||||
std::cout << "allows subscriptions: false\n";
|
||||
return false;
|
||||
}
|
||||
virtual std::string getStoreId() {
|
||||
std::cout << "get store id: LinuxStore\n";
|
||||
return "LinuxStore";
|
||||
}
|
||||
virtual std::string getSubPlatformStoreId() {
|
||||
std::cout << "get sub platform store id: LinuxStore\n";
|
||||
return "LinuxStore";
|
||||
}
|
||||
virtual std::string getProductSkuPrefix() {
|
||||
std::cout << "get product sku prefix: linux";
|
||||
return "linux";
|
||||
}
|
||||
virtual std::string getRealmsSkuPrefix() {
|
||||
std::cout << "get product sku prefix: realms";
|
||||
return "realms";
|
||||
}
|
||||
virtual void queryProducts(std::vector<std::string> const& arr) {
|
||||
std::cout << "query products\n";
|
||||
}
|
||||
virtual void purchase(std::string const& name) {
|
||||
std::cout << "purchase: " << name << "\n";
|
||||
}
|
||||
virtual void acknowledgePurchase(PurchaseInfo const& info, int type) {
|
||||
std::cout << "acknowledge purchase: type=" << type << "\n";
|
||||
}
|
||||
virtual void queryPurchases() {
|
||||
std::cout << "query purchases\n";
|
||||
}
|
||||
virtual void restorePurchases() {
|
||||
std::cout << "restore purchases\n";
|
||||
}
|
||||
virtual bool isTrial() {
|
||||
//std::cout << "is trial: false\n";
|
||||
return false;
|
||||
}
|
||||
virtual void purchaseGame() {
|
||||
std::cout << "purchase game\n";
|
||||
}
|
||||
virtual bool isGameLicensed() {
|
||||
std::cout << "is game purchased: true\n";
|
||||
return true;
|
||||
}
|
||||
virtual void getAppReceipt() {
|
||||
std::cout << "get app receipt\n";
|
||||
}
|
||||
virtual void registerLicenseChangeCallback() {
|
||||
std::cout << "register license change callback\n";
|
||||
}
|
||||
virtual void handleLicenseChange() {
|
||||
std::cout << "handle license changed\n";
|
||||
}
|
||||
virtual void restoreFromCache() {
|
||||
std::cout << "restore from cache\n";
|
||||
}
|
||||
virtual void getUserAccessTokenAsync() {
|
||||
std::cout << "get user access token async\n";
|
||||
}
|
||||
virtual void getFullSKUWithMetadataFromProductSku() {
|
||||
std::cout << "get full sku with metadata from product sku\n";
|
||||
}
|
||||
virtual std::string getFullGameProductSku() {
|
||||
std::cout << "get full game product sku\n";
|
||||
return "idk";
|
||||
}
|
||||
virtual std::string getLanguageCode() {
|
||||
std::cout << "get language code\n";
|
||||
return "idk";
|
||||
}
|
||||
virtual std::string getRegionCode() {
|
||||
std::cout << "get region code\n";
|
||||
return "idk";
|
||||
}
|
||||
virtual void refreshLicenses() {
|
||||
std::cout << "refresh licenses\n";
|
||||
}
|
||||
};
|
||||
23
src/amdfix.s
Normal file
23
src/amdfix.s
Normal file
@ -0,0 +1,23 @@
|
||||
.section .text
|
||||
.global pshufb_xmm4_xmm0
|
||||
.type pshufb_xmm4_xmm0, @function
|
||||
|
||||
pshufb_xmm4_xmm0:
|
||||
push %eax
|
||||
push %ebx
|
||||
subl $32, %esp
|
||||
movl %esp, %eax
|
||||
movdqu %xmm4, (%esp)
|
||||
movdqu %xmm0, 16(%esp)
|
||||
movl %esp, %ebx
|
||||
addl $16, %ebx
|
||||
push %ebx
|
||||
push %eax
|
||||
call pshufb
|
||||
pop %eax
|
||||
pop %ebx
|
||||
movdqu (%esp), %xmm4
|
||||
addl $32, %esp
|
||||
pop %eax
|
||||
pop %ebx
|
||||
ret
|
||||
46
src/android_symbols.h
Normal file
46
src/android_symbols.h
Normal file
@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
const char* android_symbols[] = {
|
||||
"ANativeWindow_setBuffersGeometry",
|
||||
"AAssetManager_open",
|
||||
"AAsset_getLength",
|
||||
"AAsset_getBuffer",
|
||||
"AAsset_close",
|
||||
"AAsset_read",
|
||||
"AAsset_seek64",
|
||||
"AAsset_getLength64",
|
||||
"AAsset_getRemainingLength64",
|
||||
"ALooper_pollAll",
|
||||
"ANativeActivity_finish",
|
||||
"AInputQueue_getEvent",
|
||||
"AKeyEvent_getKeyCode",
|
||||
"AInputQueue_preDispatchEvent",
|
||||
"AInputQueue_finishEvent",
|
||||
"AKeyEvent_getAction",
|
||||
"AMotionEvent_getAxisValue",
|
||||
"AKeyEvent_getRepeatCount",
|
||||
"AKeyEvent_getMetaState",
|
||||
"AInputEvent_getDeviceId",
|
||||
"AInputEvent_getType",
|
||||
"AInputEvent_getSource",
|
||||
"AMotionEvent_getAction",
|
||||
"AMotionEvent_getPointerId",
|
||||
"AMotionEvent_getX",
|
||||
"AMotionEvent_getRawX",
|
||||
"AMotionEvent_getY",
|
||||
"AMotionEvent_getRawY",
|
||||
"AMotionEvent_getPointerCount",
|
||||
"AConfiguration_new",
|
||||
"AConfiguration_fromAssetManager",
|
||||
"AConfiguration_getLanguage",
|
||||
"AConfiguration_getCountry",
|
||||
"ALooper_prepare",
|
||||
"ALooper_addFd",
|
||||
"AInputQueue_detachLooper",
|
||||
"AConfiguration_delete",
|
||||
"AInputQueue_attachLooper",
|
||||
"AAssetManager_openDir",
|
||||
"AAssetDir_getNextFileName",
|
||||
"AAssetDir_close",
|
||||
nullptr
|
||||
};
|
||||
160
src/common.cpp
Normal file
160
src/common.cpp
Normal file
@ -0,0 +1,160 @@
|
||||
#include "common.h"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstdarg>
|
||||
#include <cstring>
|
||||
#include <sys/param.h>
|
||||
#include <unistd.h>
|
||||
#include <cxxabi.h>
|
||||
#include <execinfo.h>
|
||||
#include <malloc.h>
|
||||
|
||||
extern "C" {
|
||||
#include "../hybris/include/hybris/hook.h"
|
||||
#include "../hybris/include/hybris/dlfcn.h"
|
||||
}
|
||||
|
||||
std::string getCWD() {
|
||||
char _cwd[MAXPATHLEN];
|
||||
getcwd(_cwd, MAXPATHLEN);
|
||||
return std::string(_cwd) + "/";
|
||||
}
|
||||
|
||||
bool loadLibrary(std::string path) {
|
||||
void* handle = hybris_dlopen((getCWD() + "libs/" + path).c_str(), RTLD_LAZY);
|
||||
if (handle == nullptr) {
|
||||
printf("failed to load library %s: %s\n", path.c_str(), hybris_dlerror());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void* loadLibraryOS(std::string path, const char** symbols) {
|
||||
void* handle = dlopen(path.c_str(), RTLD_LAZY);
|
||||
if (handle == nullptr) {
|
||||
printf("failed to load library %s: %s\n", path.c_str(), dlerror());
|
||||
return nullptr;
|
||||
}
|
||||
printf("oslib: %s: %i\n", path.c_str(), (int) handle);
|
||||
int i = 0;
|
||||
while (true) {
|
||||
const char* sym = symbols[i];
|
||||
if (sym == nullptr)
|
||||
break;
|
||||
void* ptr = dlsym(handle, sym);
|
||||
hybris_hook(sym, ptr);
|
||||
i++;
|
||||
}
|
||||
return handle;
|
||||
}
|
||||
|
||||
void* loadMod(std::string path) {
|
||||
void* handle = hybris_dlopen((getCWD() + "mods/" + path).c_str(), RTLD_LAZY);
|
||||
if (handle == nullptr) {
|
||||
printf("failed to load mod: %s\n", path.c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void (*initFunc)();
|
||||
initFunc = (void (*)()) hybris_dlsym(handle, "mod_init");
|
||||
if (((void*) initFunc) == nullptr) {
|
||||
printf("warn: mod %s doesn't have a init function\n", path.c_str());
|
||||
return handle;
|
||||
}
|
||||
initFunc();
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
void stubSymbols(const char** symbols, void* stubfunc) {
|
||||
int i = 0;
|
||||
while (true) {
|
||||
const char* sym = symbols[i];
|
||||
if (sym == nullptr)
|
||||
break;
|
||||
hybris_hook(sym, stubfunc);
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
void __android_log_vprint(int prio, const char *tag, const char *fmt, va_list args) {
|
||||
printf("[%s] ", tag);
|
||||
vprintf(fmt, args);
|
||||
printf("\n");
|
||||
}
|
||||
void __android_log_print(int prio, const char *tag, const char *fmt, ...) {
|
||||
va_list args;
|
||||
va_start(args, fmt);
|
||||
__android_log_vprint(prio, tag, fmt, args);
|
||||
va_end(args);
|
||||
}
|
||||
void __android_log_write(int prio, const char *tag, const char *text) {
|
||||
printf("[%s] %s\n", tag, text);
|
||||
}
|
||||
|
||||
void hookAndroidLog() {
|
||||
hybris_hook("__android_log_print", (void*) __android_log_print);
|
||||
hybris_hook("__android_log_vprint", (void*) __android_log_vprint);
|
||||
hybris_hook("__android_log_write", (void*) __android_log_write);
|
||||
}
|
||||
|
||||
void patchCallInstruction(void* patchOff, void* func, bool jump) {
|
||||
unsigned char* data = (unsigned char*) patchOff;
|
||||
printf("original: %i %i %i %i %i\n", data[0], data[1], data[2], data[3], data[4]);
|
||||
data[0] = (unsigned char) (jump ? 0xe9 : 0xe8);
|
||||
int ptr = ((int) func) - (int) patchOff - 5;
|
||||
memcpy(&data[1], &ptr, sizeof(int));
|
||||
printf("post patch: %i %i %i %i %i\n", data[0], data[1], data[2], data[3], data[4]);
|
||||
}
|
||||
|
||||
bool hasCrashed = false;
|
||||
void handleSignal(int signal, void* aptr) {
|
||||
printf("Signal %i received\n", signal);
|
||||
if (hasCrashed)
|
||||
return;
|
||||
hasCrashed = true;
|
||||
void** ptr = &aptr;
|
||||
void *array[25];
|
||||
int count = backtrace(array, 25);
|
||||
char **symbols = backtrace_symbols(array, count);
|
||||
char *nameBuf = (char*) malloc(256);
|
||||
size_t nameBufLen = 256;
|
||||
printf("Backtrace elements: %i\n", count);
|
||||
for (int i = 0; i < count; i++) {
|
||||
if (symbols[i] == nullptr) {
|
||||
printf("#%i unk [0x%04x]\n", i, (int)array[i]);
|
||||
continue;
|
||||
}
|
||||
if (symbols[i][0] == '[') { // unknown symbol
|
||||
Dl_info symInfo;
|
||||
if (hybris_dladdr(array[i], &symInfo)) {
|
||||
int status = 0;
|
||||
nameBuf = abi::__cxa_demangle(symInfo.dli_sname, nameBuf, &nameBufLen, &status);
|
||||
printf("#%i HYBRIS %s+%i in %s+0x%04x [0x%04x]\n", i, nameBuf, (unsigned int) array[i] - (unsigned int) symInfo.dli_saddr, symInfo.dli_fname, (unsigned int) array[i] - (unsigned int) symInfo.dli_fbase, (int)array[i]);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
printf("#%i %s\n", i, symbols[i]);
|
||||
}
|
||||
printf("Dumping stack...\n");
|
||||
for (int i = 0; i < 1000; i++) {
|
||||
void* pptr = *ptr;
|
||||
Dl_info symInfo;
|
||||
if (hybris_dladdr(pptr, &symInfo) && symInfo.dli_sname != nullptr && strlen(symInfo.dli_sname) > 0) {
|
||||
int status = 0;
|
||||
nameBuf = abi::__cxa_demangle(symInfo.dli_sname, nameBuf, &nameBufLen, &status);
|
||||
printf("#%i HYBRIS %s+%i in %s+0x%04x [0x%04x]\n", i, nameBuf, (unsigned int) pptr - (unsigned int) symInfo.dli_saddr, symInfo.dli_fname, (unsigned int) pptr - (unsigned int) symInfo.dli_fbase, (int)pptr);
|
||||
}
|
||||
ptr++;
|
||||
}
|
||||
abort();
|
||||
}
|
||||
|
||||
void registerCrashHandler() {
|
||||
struct sigaction act;
|
||||
act.sa_handler = (void (*)(int)) handleSignal;
|
||||
sigemptyset(&act.sa_mask);
|
||||
act.sa_flags = 0;
|
||||
sigaction(SIGSEGV, &act, 0);
|
||||
sigaction(SIGABRT, &act, 0);
|
||||
}
|
||||
12
src/common.h
Normal file
12
src/common.h
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
std::string getCWD();
|
||||
bool loadLibrary(std::string path);
|
||||
void* loadLibraryOS(std::string path, const char** symbols);
|
||||
void* loadMod(std::string path);
|
||||
void stubSymbols(const char** symbols, void* stubfunc);
|
||||
void hookAndroidLog();
|
||||
void patchCallInstruction(void* patchOff, void* func, bool jump);
|
||||
void registerCrashHandler();
|
||||
20
src/egl_symbols.h
Normal file
20
src/egl_symbols.h
Normal file
@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
const char* egl_symbols[] = {
|
||||
"eglChooseConfig",
|
||||
"eglGetError",
|
||||
"eglCreateWindowSurface",
|
||||
"eglGetConfigAttrib",
|
||||
"eglCreateContext",
|
||||
"eglDestroySurface",
|
||||
"eglSwapBuffers",
|
||||
"eglMakeCurrent",
|
||||
"eglDestroyContext",
|
||||
"eglTerminate",
|
||||
"eglGetDisplay",
|
||||
"eglInitialize",
|
||||
"eglQuerySurface",
|
||||
"eglSwapInterval",
|
||||
"eglQueryString",
|
||||
nullptr
|
||||
};
|
||||
42
src/fmod_symbols.h
Normal file
42
src/fmod_symbols.h
Normal file
@ -0,0 +1,42 @@
|
||||
#pragma once
|
||||
|
||||
const char* fmod_symbols[] = {
|
||||
"_ZN4FMOD6System12mixerSuspendEv",
|
||||
"_ZN4FMOD6System11mixerResumeEv",
|
||||
"_ZN4FMOD14ChannelControl7setMuteEb",
|
||||
"_ZN4FMOD14ChannelControl9setVolumeEf",
|
||||
"_ZN4FMOD14ChannelControl9isPlayingEPb",
|
||||
"_ZN4FMOD14ChannelControl4stopEv",
|
||||
"_ZN4FMOD6System9playSoundEPNS_5SoundEPNS_12ChannelGroupEbPPNS_7ChannelE",
|
||||
"_ZN4FMOD5Sound15getNumSubSoundsEPi",
|
||||
"_ZN4FMOD5Sound11getSubSoundEiPPS0_",
|
||||
"_ZN4FMOD14ChannelControl15set3DAttributesEPK11FMOD_VECTORS3_S3_",
|
||||
"_ZN4FMOD14ChannelControl8setPitchEf",
|
||||
"_ZN4FMOD14ChannelControl9setPausedEb",
|
||||
"_ZN4FMOD5Sound7releaseEv",
|
||||
"_ZN4FMOD6System5closeEv",
|
||||
"_ZN4FMOD6System7releaseEv",
|
||||
"FMOD_System_Create",
|
||||
"_ZN4FMOD6System10getVersionEPj",
|
||||
"_ZN4FMOD6System9setOutputE15FMOD_OUTPUTTYPE",
|
||||
"_ZN4FMOD6System4initEijPv",
|
||||
"_ZN4FMOD6System13set3DSettingsEfff",
|
||||
"_ZN4FMOD6System18createChannelGroupEPKcPPNS_12ChannelGroupE",
|
||||
"_ZN4FMOD6System21getMasterChannelGroupEPPNS_12ChannelGroupE",
|
||||
"_ZN4FMOD12ChannelGroup8addGroupEPS0_bPPNS_13DSPConnectionE",
|
||||
"_ZN4FMOD6System23set3DListenerAttributesEiPK11FMOD_VECTORS3_S3_S3_",
|
||||
"_ZN4FMOD6System6updateEv",
|
||||
"_ZN4FMOD6System12createStreamEPKcjP22FMOD_CREATESOUNDEXINFOPPNS_5SoundE",
|
||||
"_ZN4FMOD6System11createSoundEPKcjP22FMOD_CREATESOUNDEXINFOPPNS_5SoundE",
|
||||
"_ZN4FMOD5Sound19set3DMinMaxDistanceEff",
|
||||
"_ZN4FMOD6System13getNumDriversEPi",
|
||||
"_ZN4FMOD6System13getDriverInfoEiPciP9FMOD_GUIDPiP16FMOD_SPEAKERMODES4_",
|
||||
"_ZN4FMOD6System9setDriverEi",
|
||||
"_ZN4FMOD5Sound7setModeEj",
|
||||
"_ZN4FMOD5Sound9getFormatEP15FMOD_SOUND_TYPEP17FMOD_SOUND_FORMATPiS5_",
|
||||
"_ZN4FMOD6System17getSoftwareFormatEPiP16FMOD_SPEAKERMODES1_",
|
||||
"_ZN4FMOD14ChannelControl11getDSPClockEPyS1_",
|
||||
"_ZN4FMOD14ChannelControl12addFadePointEyf",
|
||||
"_ZN4FMOD14ChannelControl8setDelayEyyb",
|
||||
nullptr
|
||||
};
|
||||
540
src/gles_symbols.h
Normal file
540
src/gles_symbols.h
Normal file
@ -0,0 +1,540 @@
|
||||
#pragma once
|
||||
|
||||
const char* gles_symbols[] = {
|
||||
"glActiveTexture",
|
||||
"glAttachShader",
|
||||
"glBindAttribLocation",
|
||||
"glBindBuffer",
|
||||
"glBindFramebuffer",
|
||||
"glBindRenderbuffer",
|
||||
"glBindTexture",
|
||||
"glBlendColor",
|
||||
"glBlendEquation",
|
||||
"glBlendEquationSeparate",
|
||||
"glBlendFunc",
|
||||
"glBlendFuncSeparate",
|
||||
"glBufferData",
|
||||
"glBufferSubData",
|
||||
"glCheckFramebufferStatus",
|
||||
"glClear",
|
||||
"glClearColor",
|
||||
"glClearDepthf",
|
||||
"glClearStencil",
|
||||
"glColorMask",
|
||||
"glCompileShader",
|
||||
"glCompressedTexImage2D",
|
||||
"glCompressedTexSubImage2D",
|
||||
"glCopyTexImage2D",
|
||||
"glCopyTexSubImage2D",
|
||||
"glCreateProgram",
|
||||
"glCreateShader",
|
||||
"glCullFace",
|
||||
"glDeleteBuffers",
|
||||
"glDeleteFramebuffers",
|
||||
"glDeleteProgram",
|
||||
"glDeleteRenderbuffers",
|
||||
"glDeleteShader",
|
||||
"glDeleteTextures",
|
||||
"glDepthFunc",
|
||||
"glDepthMask",
|
||||
"glDepthRangef",
|
||||
"glDetachShader",
|
||||
"glDisable",
|
||||
"glDisableVertexAttribArray",
|
||||
"glDrawArrays",
|
||||
"glDrawElements",
|
||||
"glEnable",
|
||||
"glEnableVertexAttribArray",
|
||||
"glFinish",
|
||||
"glFlush",
|
||||
"glFramebufferRenderbuffer",
|
||||
"glFramebufferTexture2D",
|
||||
"glFrontFace",
|
||||
"glGenBuffers",
|
||||
"glGenerateMipmap",
|
||||
"glGenFramebuffers",
|
||||
"glGenRenderbuffers",
|
||||
"glGenTextures",
|
||||
"glGetActiveAttrib",
|
||||
"glGetActiveUniform",
|
||||
"glGetAttachedShaders",
|
||||
"glGetAttribLocation",
|
||||
"glGetBooleanv",
|
||||
"glGetBufferParameteriv",
|
||||
"glGetError",
|
||||
"glGetFloatv",
|
||||
"glGetFramebufferAttachmen",
|
||||
"glGetIntegerv",
|
||||
"glGetProgramiv",
|
||||
"glGetProgramInfoLog",
|
||||
"glGetRenderbufferParamete",
|
||||
"glGetShaderiv",
|
||||
"glGetShaderInfoLog",
|
||||
"glGetShaderPrecisionFormat",
|
||||
"glGetShaderSource",
|
||||
"glGetTexParameterfv",
|
||||
"glGetTexParameteriv",
|
||||
"glGetUniformfv",
|
||||
"glGetUniformiv",
|
||||
"glGetUniformLocation",
|
||||
"glGetVertexAttribfv",
|
||||
"glGetVertexAttribiv",
|
||||
"glGetVertexAttribPointerv",
|
||||
"glHint",
|
||||
"glIsBuffer",
|
||||
"glIsEnabled",
|
||||
"glIsFramebuffer",
|
||||
"glIsProgram",
|
||||
"glIsRenderbuffer",
|
||||
"glIsShader",
|
||||
"glIsTexture",
|
||||
"glLineWidth",
|
||||
"glLinkProgram",
|
||||
"glPixelStorei",
|
||||
"glPolygonOffset",
|
||||
"glReadPixels",
|
||||
"glReleaseShaderCompiler",
|
||||
"glRenderbufferStorage",
|
||||
"glSampleCoverage",
|
||||
"glScissor",
|
||||
"glShaderBinary",
|
||||
"glShaderSource",
|
||||
"glStencilFunc",
|
||||
"glStencilFuncSeparate",
|
||||
"glStencilMask",
|
||||
"glStencilMaskSeparate",
|
||||
"glStencilOp",
|
||||
"glStencilOpSeparate",
|
||||
"glTexImage2D",
|
||||
"glTexParameterf",
|
||||
"glTexParameterfv",
|
||||
"glTexParameteri",
|
||||
"glTexParameteriv",
|
||||
"glTexSubImage2D",
|
||||
"glUniform1f",
|
||||
"glUniform1fv",
|
||||
"glUniform1i",
|
||||
"glUniform1iv",
|
||||
"glUniform2f",
|
||||
"glUniform2fv",
|
||||
"glUniform2i",
|
||||
"glUniform2iv",
|
||||
"glUniform3f",
|
||||
"glUniform3fv",
|
||||
"glUniform3i",
|
||||
"glUniform3iv",
|
||||
"glUniform4f",
|
||||
"glUniform4fv",
|
||||
"glUniform4i",
|
||||
"glUniform4iv",
|
||||
"glUniformMatrix2fv",
|
||||
"glUniformMatrix3fv",
|
||||
"glUniformMatrix4fv",
|
||||
"glUseProgram",
|
||||
"glValidateProgram",
|
||||
"glVertexAttrib1f",
|
||||
"glVertexAttrib1fv",
|
||||
"glVertexAttrib2f",
|
||||
"glVertexAttrib2fv",
|
||||
"glVertexAttrib3f",
|
||||
"glVertexAttrib3fv",
|
||||
"glVertexAttrib4f",
|
||||
"glVertexAttrib4fv",
|
||||
"glVertexAttribPointer",
|
||||
"glViewport",
|
||||
"glReadBuffer",
|
||||
"glDrawRangeElements",
|
||||
"glTexImage3D",
|
||||
"glTexSubImage3D",
|
||||
"glCopyTexSubImage3D",
|
||||
"glCompressedTexImage3D",
|
||||
"glCompressedTexSubImage3D",
|
||||
"glGenQueries",
|
||||
"glDeleteQueries",
|
||||
"glIsQuery",
|
||||
"glBeginQuery",
|
||||
"glEndQuery",
|
||||
"glGetQueryiv",
|
||||
"glGetQueryObjectuiv",
|
||||
"glUnmapBuffer",
|
||||
"glGetBufferPointerv",
|
||||
"glDrawBuffers",
|
||||
"glUniformMatrix2x3fv",
|
||||
"glUniformMatrix3x2fv",
|
||||
"glUniformMatrix2x4fv",
|
||||
"glUniformMatrix4x2fv",
|
||||
"glUniformMatrix3x4fv",
|
||||
"glUniformMatrix4x3fv",
|
||||
"glBlitFramebuffer",
|
||||
"glRenderbufferStorageMult",
|
||||
"glFramebufferTextureLayer",
|
||||
"glMapBufferRange",
|
||||
"glFlushMappedBufferRange",
|
||||
"glBindVertexArray",
|
||||
"glDeleteVertexArrays",
|
||||
"glGenVertexArrays",
|
||||
"glIsVertexArray",
|
||||
"glGetIntegeri_v",
|
||||
"glBeginTransformFeedback",
|
||||
"glEndTransformFeedback",
|
||||
"glBindBufferRange",
|
||||
"glBindBufferBase",
|
||||
"glTransformFeedbackVaryin",
|
||||
"glGetTransformFeedbackVar",
|
||||
"glVertexAttribIPointer",
|
||||
"glGetVertexAttribIiv",
|
||||
"glGetVertexAttribIuiv",
|
||||
"glVertexAttribI4i",
|
||||
"glVertexAttribI4ui",
|
||||
"glVertexAttribI4iv",
|
||||
"glVertexAttribI4uiv",
|
||||
"glGetUniformuiv",
|
||||
"glGetFragDataLocation",
|
||||
"glUniform1ui",
|
||||
"glUniform2ui",
|
||||
"glUniform3ui",
|
||||
"glUniform4ui",
|
||||
"glUniform1uiv",
|
||||
"glUniform2uiv",
|
||||
"glUniform3uiv",
|
||||
"glUniform4uiv",
|
||||
"glClearBufferiv",
|
||||
"glClearBufferuiv",
|
||||
"glClearBufferfv",
|
||||
"glClearBufferfi",
|
||||
"glGetStringi",
|
||||
"glCopyBufferSubData",
|
||||
"glGetUniformIndices",
|
||||
"glGetActiveUniformsiv",
|
||||
"glGetUniformBlockIndex",
|
||||
"glGetActiveUniformBlockiv",
|
||||
"glGetActiveUniformBlockNa",
|
||||
"glUniformBlockBinding",
|
||||
"glDrawArraysInstanced",
|
||||
"glDrawElementsInstanced",
|
||||
"glFenceSync",
|
||||
"glIsSync",
|
||||
"glDeleteSync",
|
||||
"glClientWaitSync",
|
||||
"glWaitSync",
|
||||
"glGetInteger64v",
|
||||
"glGetSynciv",
|
||||
"glGetInteger64i_v",
|
||||
"glGetBufferParameteri64v",
|
||||
"glGenSamplers",
|
||||
"glDeleteSamplers",
|
||||
"glIsSampler",
|
||||
"glBindSampler",
|
||||
"glSamplerParameteri",
|
||||
"glSamplerParameteriv",
|
||||
"glSamplerParameterf",
|
||||
"glSamplerParameterfv",
|
||||
"glGetSamplerParameteriv",
|
||||
"glGetSamplerParameterfv",
|
||||
"glVertexAttribDivisor",
|
||||
"glBindTransformFeedback",
|
||||
"glDeleteTransformFeedback",
|
||||
"glGenTransformFeedbacks",
|
||||
"glIsTransformFeedback",
|
||||
"glPauseTransformFeedback",
|
||||
"glResumeTransformFeedback",
|
||||
"glGetProgramBinary",
|
||||
"glProgramBinary",
|
||||
"glProgramParameteri",
|
||||
"glInvalidateFramebuffer",
|
||||
"glInvalidateSubFramebuffe",
|
||||
"glTexStorage2D",
|
||||
"glTexStorage3D",
|
||||
"glGetInternalformativ",
|
||||
"glDispatchCompute",
|
||||
"glDispatchComputeIndirect",
|
||||
"glDrawArraysIndirect",
|
||||
"glDrawElementsIndirect",
|
||||
"glFramebufferParameteri",
|
||||
"glGetFramebufferParameter",
|
||||
"glGetProgramInterfaceiv",
|
||||
"glGetProgramResourceIndex",
|
||||
"glGetProgramResourceName",
|
||||
"glGetProgramResourceiv",
|
||||
"glGetProgramResourceLocat",
|
||||
"glUseProgramStages",
|
||||
"glActiveShaderProgram",
|
||||
"glCreateShaderProgramv",
|
||||
"glBindProgramPipeline",
|
||||
"glDeleteProgramPipelines",
|
||||
"glGenProgramPipelines",
|
||||
"glIsProgramPipeline",
|
||||
"glGetProgramPipelineiv",
|
||||
"glProgramUniform1i",
|
||||
"glProgramUniform2i",
|
||||
"glProgramUniform3i",
|
||||
"glProgramUniform4i",
|
||||
"glProgramUniform1ui",
|
||||
"glProgramUniform2ui",
|
||||
"glProgramUniform3ui",
|
||||
"glProgramUniform4ui",
|
||||
"glProgramUniform1f",
|
||||
"glProgramUniform2f",
|
||||
"glProgramUniform3f",
|
||||
"glProgramUniform4f",
|
||||
"glProgramUniform1iv",
|
||||
"glProgramUniform2iv",
|
||||
"glProgramUniform3iv",
|
||||
"glProgramUniform4iv",
|
||||
"glProgramUniform1uiv",
|
||||
"glProgramUniform2uiv",
|
||||
"glProgramUniform3uiv",
|
||||
"glProgramUniform4uiv",
|
||||
"glProgramUniform1fv",
|
||||
"glProgramUniform2fv",
|
||||
"glProgramUniform3fv",
|
||||
"glProgramUniform4fv",
|
||||
"glProgramUniformMatrix2fv",
|
||||
"glProgramUniformMatrix3fv",
|
||||
"glProgramUniformMatrix4fv",
|
||||
"glProgramUniformMatrix2x3",
|
||||
"glProgramUniformMatrix3x2",
|
||||
"glProgramUniformMatrix2x4",
|
||||
"glProgramUniformMatrix4x2",
|
||||
"glProgramUniformMatrix3x4",
|
||||
"glProgramUniformMatrix4x3",
|
||||
"glValidateProgramPipeline",
|
||||
"glGetProgramPipelineInfoL",
|
||||
"glBindImageTexture",
|
||||
"glGetBooleani_v",
|
||||
"glMemoryBarrier",
|
||||
"glMemoryBarrierByRegion",
|
||||
"glTexStorage2DMultisample",
|
||||
"glGetMultisamplefv",
|
||||
"glSampleMaski",
|
||||
"glGetTexLevelParameteriv",
|
||||
"glGetTexLevelParameterfv",
|
||||
"glBindVertexBuffer",
|
||||
"glVertexAttribFormat",
|
||||
"glVertexAttribIFormat",
|
||||
"glVertexAttribBinding",
|
||||
"glVertexBindingDivisor",
|
||||
"glBlendBarrierKHR",
|
||||
"glDebugMessageControlKHR",
|
||||
"glDebugMessageInsertKHR",
|
||||
"glDebugMessageCallbackKHR",
|
||||
"glGetDebugMessageLogKHR",
|
||||
"glPushDebugGroupKHR",
|
||||
"glPopDebugGroupKHR",
|
||||
"glObjectLabelKHR",
|
||||
"glGetObjectLabelKHR",
|
||||
"glObjectPtrLabelKHR",
|
||||
"glGetObjectPtrLabelKHR",
|
||||
"glGetPointervKHR",
|
||||
"glEGLImageTargetTexture2D",
|
||||
"glEGLImageTargetRenderbuf",
|
||||
"glGetProgramBinaryOES",
|
||||
"glProgramBinaryOES",
|
||||
"glMapBufferOES",
|
||||
"glUnmapBufferOES",
|
||||
"glGetBufferPointervOES",
|
||||
"glMinSampleShadingOES",
|
||||
"glTexImage3DOES",
|
||||
"glTexSubImage3DOES",
|
||||
"glCopyTexSubImage3DOES",
|
||||
"glCompressedTexImage3DOES",
|
||||
"glCompressedTexSubImage3D",
|
||||
"glFramebufferTexture3DOES",
|
||||
"glTexStorage3DMultisample",
|
||||
"glBindVertexArrayOES",
|
||||
"glDeleteVertexArraysOES",
|
||||
"glGenVertexArraysOES",
|
||||
"glIsVertexArrayOES",
|
||||
"glGetPerfMonitorGroupsAMD",
|
||||
"glGetPerfMonitorCountersA",
|
||||
"glGetPerfMonitorGroupStri",
|
||||
"glGetPerfMonitorCounterSt",
|
||||
"glGetPerfMonitorCounterIn",
|
||||
"glGenPerfMonitorsAMD",
|
||||
"glDeletePerfMonitorsAMD",
|
||||
"glSelectPerfMonitorCounte",
|
||||
"glBeginPerfMonitorAMD",
|
||||
"glEndPerfMonitorAMD",
|
||||
"glGetPerfMonitorCounterDa",
|
||||
"glBlitFramebufferANGLE",
|
||||
"glRenderbufferStorageMult",
|
||||
"glDrawArraysInstancedANGL",
|
||||
"glDrawElementsInstancedAN",
|
||||
"glVertexAttribDivisorANGL",
|
||||
"glGetTranslatedShaderSour",
|
||||
"glCopyTextureLevelsAPPLE",
|
||||
"glRenderbufferStorageMult",
|
||||
"glResolveMultisampleFrame",
|
||||
"glFenceSyncAPPLE",
|
||||
"glIsSyncAPPLE",
|
||||
"glDeleteSyncAPPLE",
|
||||
"glClientWaitSyncAPPLE",
|
||||
"glWaitSyncAPPLE",
|
||||
"glGetInteger64vAPPLE",
|
||||
"glGetSyncivAPPLE",
|
||||
"glCopyImageSubDataEXT",
|
||||
"glLabelObjectEXT",
|
||||
"glGetObjectLabelEXT",
|
||||
"glInsertEventMarkerEXT",
|
||||
"glPushGroupMarkerEXT",
|
||||
"glPopGroupMarkerEXT",
|
||||
"glDiscardFramebufferEXT",
|
||||
"glGenQueriesEXT",
|
||||
"glDeleteQueriesEXT",
|
||||
"glIsQueryEXT",
|
||||
"glBeginQueryEXT",
|
||||
"glEndQueryEXT",
|
||||
"glQueryCounterEXT",
|
||||
"glGetQueryivEXT",
|
||||
"glGetQueryObjectivEXT",
|
||||
"glGetQueryObjectuivEXT",
|
||||
"glGetQueryObjecti64vEXT",
|
||||
"glGetQueryObjectui64vEXT",
|
||||
"glDrawBuffersEXT",
|
||||
"glEnableiEXT",
|
||||
"glDisableiEXT",
|
||||
"glBlendEquationiEXT",
|
||||
"glBlendEquationSeparateiE",
|
||||
"glBlendFunciEXT",
|
||||
"glBlendFuncSeparateiEXT",
|
||||
"glColorMaskiEXT",
|
||||
"glIsEnablediEXT",
|
||||
"glDrawArraysInstancedEXT",
|
||||
"glDrawElementsInstancedEX",
|
||||
"glFramebufferTextureEXT",
|
||||
"glVertexAttribDivisorEXT",
|
||||
"glMapBufferRangeEXT",
|
||||
"glFlushMappedBufferRangeE",
|
||||
"glMultiDrawArraysEXT",
|
||||
"glMultiDrawElementsEXT",
|
||||
"glRenderbufferStorageMult",
|
||||
"glFramebufferTexture2DMul",
|
||||
"glReadBufferIndexedEXT",
|
||||
"glDrawBuffersIndexedEXT",
|
||||
"glGetIntegeri_vEXT",
|
||||
"glPrimitiveBoundingBoxEXT",
|
||||
"glGetGraphicsResetStatusE",
|
||||
"glReadnPixelsEXT",
|
||||
"glGetnUniformfvEXT",
|
||||
"glGetnUniformivEXT",
|
||||
"glActiveShaderProgramEXT",
|
||||
"glBindProgramPipelineEXT",
|
||||
"glCreateShaderProgramvEXT",
|
||||
"glDeleteProgramPipelinesE",
|
||||
"glGenProgramPipelinesEXT",
|
||||
"glGetProgramPipelineInfoL",
|
||||
"glGetProgramPipelineivEXT",
|
||||
"glIsProgramPipelineEXT",
|
||||
"glProgramParameteriEXT",
|
||||
"glProgramUniform1fEXT",
|
||||
"glProgramUniform1fvEXT",
|
||||
"glProgramUniform1iEXT",
|
||||
"glProgramUniform1ivEXT",
|
||||
"glProgramUniform2fEXT",
|
||||
"glProgramUniform2fvEXT",
|
||||
"glProgramUniform2iEXT",
|
||||
"glProgramUniform2ivEXT",
|
||||
"glProgramUniform3fEXT",
|
||||
"glProgramUniform3fvEXT",
|
||||
"glProgramUniform3iEXT",
|
||||
"glProgramUniform3ivEXT",
|
||||
"glProgramUniform4fEXT",
|
||||
"glProgramUniform4fvEXT",
|
||||
"glProgramUniform4iEXT",
|
||||
"glProgramUniform4ivEXT",
|
||||
"glProgramUniformMatrix2fv",
|
||||
"glProgramUniformMatrix3fv",
|
||||
"glProgramUniformMatrix4fv",
|
||||
"glUseProgramStagesEXT",
|
||||
"glValidateProgramPipeline",
|
||||
"glProgramUniform1uiEXT",
|
||||
"glProgramUniform2uiEXT",
|
||||
"glProgramUniform3uiEXT",
|
||||
"glProgramUniform4uiEXT",
|
||||
"glProgramUniform1uivEXT",
|
||||
"glProgramUniform2uivEXT",
|
||||
"glProgramUniform3uivEXT",
|
||||
"glProgramUniform4uivEXT",
|
||||
"glProgramUniformMatrix2x3",
|
||||
"glProgramUniformMatrix3x2",
|
||||
"glProgramUniformMatrix2x4",
|
||||
"glProgramUniformMatrix4x2",
|
||||
"glProgramUniformMatrix3x4",
|
||||
"glProgramUniformMatrix4x3",
|
||||
"glPatchParameteriEXT",
|
||||
"glTexParameterIivEXT",
|
||||
"glTexParameterIuivEXT",
|
||||
"glGetTexParameterIivEXT",
|
||||
"glGetTexParameterIuivEXT",
|
||||
"glSamplerParameterIivEXT",
|
||||
"glSamplerParameterIuivEXT",
|
||||
"glGetSamplerParameterIivE",
|
||||
"glGetSamplerParameterIuiv",
|
||||
"glTexBufferEXT",
|
||||
"glTexBufferRangeEXT",
|
||||
"glTexStorage1DEXT",
|
||||
"glTexStorage2DEXT",
|
||||
"glTexStorage3DEXT",
|
||||
"glTextureStorage1DEXT",
|
||||
"glTextureStorage2DEXT",
|
||||
"glTextureStorage3DEXT",
|
||||
"glTextureViewEXT",
|
||||
"glRenderbufferStorageMult",
|
||||
"glFramebufferTexture2DMul",
|
||||
"glBeginPerfQueryINTEL",
|
||||
"glCreatePerfQueryINTEL",
|
||||
"glDeletePerfQueryINTEL",
|
||||
"glEndPerfQueryINTEL",
|
||||
"glGetFirstPerfQueryIdINTE",
|
||||
"glGetNextPerfQueryIdINTEL",
|
||||
"glGetPerfCounterInfoINTEL",
|
||||
"glGetPerfQueryDataINTEL",
|
||||
"glGetPerfQueryIdByNameINT",
|
||||
"glGetPerfQueryInfoINTEL",
|
||||
"glBlendParameteriNV",
|
||||
"glBlendBarrierNV",
|
||||
"glCopyBufferSubDataNV",
|
||||
"glCoverageMaskNV",
|
||||
"glCoverageOperationNV",
|
||||
"glDrawBuffersNV",
|
||||
"glDrawArraysInstancedNV",
|
||||
"glDrawElementsInstancedNV",
|
||||
"glDeleteFencesNV",
|
||||
"glGenFencesNV",
|
||||
"glIsFenceNV",
|
||||
"glTestFenceNV",
|
||||
"glGetFenceivNV",
|
||||
"glFinishFenceNV",
|
||||
"glSetFenceNV",
|
||||
"glBlitFramebufferNV",
|
||||
"glRenderbufferStorageMult",
|
||||
"glVertexAttribDivisorNV",
|
||||
"glUniformMatrix2x3fvNV",
|
||||
"glUniformMatrix3x2fvNV",
|
||||
"glUniformMatrix2x4fvNV",
|
||||
"glUniformMatrix4x2fvNV",
|
||||
"glUniformMatrix3x4fvNV",
|
||||
"glUniformMatrix4x3fvNV",
|
||||
"glReadBufferNV",
|
||||
"glAlphaFuncQCOM",
|
||||
"glGetDriverControlsQCOM",
|
||||
"glGetDriverControlStringQ",
|
||||
"glEnableDriverControlQCOM",
|
||||
"glDisableDriverControlQCO",
|
||||
"glExtGetTexturesQCOM",
|
||||
"glExtGetBuffersQCOM",
|
||||
"glExtGetRenderbuffersQCOM",
|
||||
"glExtGetFramebuffersQCOM",
|
||||
"glExtGetTexLevelParameter",
|
||||
"glExtTexObjectStateOverri",
|
||||
"glExtGetTexSubImageQCOM",
|
||||
"glExtGetBufferPointervQCO",
|
||||
"glExtGetShadersQCOM",
|
||||
"glExtGetProgramsQCOM",
|
||||
"glExtIsProgramBinaryQCOM",
|
||||
"glExtGetProgramBinarySour",
|
||||
"glStartTilingQCOM",
|
||||
"glEndTilingQCOM",
|
||||
"glGetString",
|
||||
nullptr
|
||||
};
|
||||
117
src/hook.cpp
Normal file
117
src/hook.cpp
Normal file
@ -0,0 +1,117 @@
|
||||
#include "hook.h"
|
||||
|
||||
#include <elf.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <vector>
|
||||
#include <sys/mman.h>
|
||||
#include <map>
|
||||
|
||||
extern "C" {
|
||||
#include "../hybris/include/hybris/dlfcn.h"
|
||||
#include "../hybris/src/jb/linker.h"
|
||||
}
|
||||
|
||||
struct soinfo_hookinfo {
|
||||
struct hook_section {
|
||||
Elf32_Off addr, size;
|
||||
};
|
||||
std::vector<hook_section> hookSections;
|
||||
};
|
||||
std::map<soinfo*, soinfo_hookinfo> hookLibraries;
|
||||
|
||||
void addHookLibrary(void* ptr, std::string const& fileName) {
|
||||
soinfo* lib = (soinfo*) ptr;
|
||||
|
||||
if (hookLibraries.count(lib) > 0)
|
||||
return;
|
||||
|
||||
Elf32_Ehdr header;
|
||||
FILE* file = fopen(fileName.c_str(), "r");
|
||||
if (file == nullptr) {
|
||||
printf("addHookLibrary: failed to open file\n");
|
||||
return;
|
||||
}
|
||||
if (fread(&header, sizeof(Elf32_Ehdr), 1, file) != 1) {
|
||||
printf("addHookLibrary: failed to read header\n");
|
||||
fclose(file);
|
||||
return;
|
||||
}
|
||||
|
||||
fseek(file, (long) header.e_shoff, SEEK_SET);
|
||||
|
||||
char shdr[header.e_shentsize * header.e_shnum];
|
||||
if (fread(&shdr, header.e_shentsize, header.e_shnum, file) != header.e_shnum) {
|
||||
printf("addHookLibrary: failed to read shdr\n");
|
||||
fclose(file);
|
||||
return;
|
||||
}
|
||||
|
||||
// find strtab
|
||||
char* strtab = nullptr;
|
||||
for (int i = 0; i < header.e_shnum; i++) {
|
||||
Elf32_Shdr& entry = *((Elf32_Shdr*) &shdr[header.e_shentsize * i]);
|
||||
if (entry.sh_type == SHT_STRTAB) {
|
||||
strtab = new char[entry.sh_size];
|
||||
fseek(file, (long) entry.sh_offset, SEEK_SET);
|
||||
if (fread(strtab, 1, entry.sh_size, file) != entry.sh_size) {
|
||||
printf("addHookLibrary: failed to read strtab\n");
|
||||
fclose(file);
|
||||
delete[] strtab;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (strtab == nullptr) {
|
||||
printf("addHookLibrary: couldn't find strtab\n");
|
||||
fclose(file);
|
||||
return;
|
||||
}
|
||||
soinfo_hookinfo hi;
|
||||
for (int i = 0; i < header.e_shnum; i++) {
|
||||
Elf32_Shdr& entry = *((Elf32_Shdr*) &shdr[header.e_shentsize * i]);
|
||||
char* entryName = &strtab[entry.sh_name];
|
||||
if (strcmp(entryName, ".got") == 0 || strcmp(entryName, ".got.plt") == 0 ||
|
||||
strcmp(entryName, ".data.rel.ro") == 0) {
|
||||
hi.hookSections.push_back({entry.sh_addr, entry.sh_size});
|
||||
}
|
||||
}
|
||||
hookLibraries[lib] = hi;
|
||||
fclose(file);
|
||||
delete[] strtab;
|
||||
}
|
||||
|
||||
inline bool patchSection(Elf32_Addr base, Elf32_Word off, Elf32_Word size, void* sym, void* override) {
|
||||
bool foundEntry = false;
|
||||
unsigned long addr = base + off + 4;
|
||||
while (addr < base + off + size) {
|
||||
if (*((void**) addr) == sym) {
|
||||
*((void**) addr) = override;
|
||||
foundEntry = true;
|
||||
}
|
||||
addr += sizeof(void*);
|
||||
}
|
||||
return foundEntry;
|
||||
}
|
||||
bool patchLibrary(void* lib, void* sym, void* override) {
|
||||
soinfo* si = (soinfo*) lib;
|
||||
if (si == nullptr || hookLibraries.count(si) <= 0)
|
||||
return false;
|
||||
soinfo_hookinfo& hi = hookLibraries.at(si);
|
||||
bool foundEntry = false;
|
||||
for (auto& se : hi.hookSections) {
|
||||
if (patchSection(si->base, se.addr, se.size, sym, override))
|
||||
foundEntry = true;
|
||||
}
|
||||
return foundEntry;
|
||||
}
|
||||
|
||||
void hookFunction(void* symbol, void* hook, void** original) {
|
||||
*original = symbol;
|
||||
bool foundEntry = false;
|
||||
for (auto& handle : hookLibraries)
|
||||
if (patchLibrary(handle.first, symbol, hook))
|
||||
foundEntry = true;
|
||||
if (!foundEntry)
|
||||
printf("Failed to hook a symbol (%llu)\n", (long long int) symbol);
|
||||
}
|
||||
6
src/hook.h
Normal file
6
src/hook.h
Normal file
@ -0,0 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
void addHookLibrary(void* ptr, const std::string& path);
|
||||
void hookFunction(void* symbol, void* hook, void** original);
|
||||
461
src/main.cpp
Normal file
461
src/main.cpp
Normal file
@ -0,0 +1,461 @@
|
||||
#include <iostream>
|
||||
#include <dlfcn.h>
|
||||
#include <stdarg.h>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <codecvt>
|
||||
#include <locale>
|
||||
#include <dirent.h>
|
||||
#include "gles_symbols.h"
|
||||
#include "android_symbols.h"
|
||||
#include "egl_symbols.h"
|
||||
#include "fmod_symbols.h"
|
||||
#include "../mcpe/gl.h"
|
||||
#include "../mcpe/AppPlatform.h"
|
||||
#include "../mcpe/MinecraftGame.h"
|
||||
#include "LinuxAppPlatform.h"
|
||||
#include "LinuxStore.h"
|
||||
#include "../mcpe/Mouse.h"
|
||||
#include "../mcpe/Keyboard.h"
|
||||
#include "../mcpe/Options.h"
|
||||
#include "common.h"
|
||||
#include "hook.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
#include <eglut.h>
|
||||
#include "../hybris/include/hybris/dlfcn.h"
|
||||
#include "../hybris/include/hybris/hook.h"
|
||||
#include "../hybris/src/jb/linker.h"
|
||||
|
||||
}
|
||||
|
||||
void commonStub() {}
|
||||
|
||||
void androidStub() {
|
||||
std::cout << "warn: android call\n";
|
||||
}
|
||||
|
||||
void eglStub() {
|
||||
std::cout << "warn: egl call\n";
|
||||
}
|
||||
|
||||
std::unique_ptr<LinuxStore> createStoreHookFunc(const std::string& idk, StoreListener& listener) {
|
||||
std::cout << "creating fake store <" << idk << ">\n";
|
||||
return std::unique_ptr<LinuxStore>(new LinuxStore());
|
||||
}
|
||||
|
||||
class HTTPRequest;
|
||||
|
||||
class LinuxHttpRequestInternal {
|
||||
public:
|
||||
void* vtable;
|
||||
int filler1;
|
||||
HTTPRequest* request;
|
||||
|
||||
void destroy() {
|
||||
std::cout << "destroying http request\n";
|
||||
}
|
||||
};
|
||||
void** linuxHttpRequestInternalVtable;
|
||||
|
||||
void constructLinuxHttpRequestInternal(LinuxHttpRequestInternal* requestInternal, HTTPRequest* request) {
|
||||
requestInternal->vtable = linuxHttpRequestInternalVtable;
|
||||
requestInternal->request = request;
|
||||
}
|
||||
|
||||
void sendLinuxHttpRequestInternal(LinuxHttpRequestInternal* requestInternal) {
|
||||
std::cout << "send http request\n";
|
||||
// TODO: Implement it
|
||||
}
|
||||
|
||||
void abortLinuxHttpRequestInternal(LinuxHttpRequestInternal* requestInternal) {
|
||||
std::cout << "abort http request\n";
|
||||
// TODO: Implement it
|
||||
}
|
||||
|
||||
|
||||
static MinecraftGame* client;
|
||||
|
||||
int winId = 0;
|
||||
bool moveMouseToCenter = false;
|
||||
|
||||
static void minecraft_idle() {
|
||||
if (client->wantToQuit()) {
|
||||
eglutDestroyWindow(winId);
|
||||
eglutFini();
|
||||
return;
|
||||
}
|
||||
int cx = eglutGetWindowWidth() / 2;
|
||||
int cy = eglutGetWindowHeight() / 2;
|
||||
if (moveMouseToCenter) {
|
||||
eglutWarpMousePointer(cx, cy);
|
||||
moveMouseToCenter = false;
|
||||
}
|
||||
eglutPostRedisplay();
|
||||
}
|
||||
static void minecraft_draw() {
|
||||
client->update();
|
||||
}
|
||||
float pixelSize = 2.f;
|
||||
static void minecraft_reshape(int w, int h) {
|
||||
client->setRenderingSize(w, h);
|
||||
client->setUISizeAndScale(w, h, pixelSize);
|
||||
}
|
||||
static void minecraft_mouse(int x, int y) {
|
||||
if (LinuxAppPlatform::mousePointerHidden) {
|
||||
int cx = eglutGetWindowWidth() / 2;
|
||||
int cy = eglutGetWindowHeight() / 2;
|
||||
if (x != cy || y != cy) {
|
||||
Mouse::feed(0, 0, x, y, x - cx, y - cy);
|
||||
moveMouseToCenter = true;
|
||||
}
|
||||
} else {
|
||||
Mouse::feed(0, 0, x, y, 0, 0);
|
||||
}
|
||||
}
|
||||
static void minecraft_mouse_button(int x, int y, int btn, int action) {
|
||||
int mcBtn = (btn == 1 ? 1 : (btn == 2 ? 3 : (btn == 3 ? 2 : (btn == 5 ? 4 : btn))));
|
||||
Mouse::feed((char) mcBtn, (char) (action == EGLUT_MOUSE_PRESS ? (btn == 5 ? -120 : (btn == 4 ? 120 : 1)) : 0), x, y, 0, 0);
|
||||
}
|
||||
|
||||
int getKeyMinecraft(int keyCode) {
|
||||
if (keyCode == 65505)
|
||||
return 16;
|
||||
if (keyCode >= 97 && keyCode <= 122)
|
||||
return (keyCode + 65 - 97);
|
||||
if (keyCode >= 65470 && keyCode <= 65481)
|
||||
return (keyCode + 112 - 65470);
|
||||
|
||||
return keyCode;
|
||||
}
|
||||
static void minecraft_keyboard(char str[5], int action) {
|
||||
if (strcmp(str, "\t") == 0)
|
||||
return;
|
||||
if (action == EGLUT_KEY_PRESS || action == EGLUT_KEY_REPEAT) {
|
||||
if (str[0] == 13) {
|
||||
str[0] = 10;
|
||||
str[1] = 0;
|
||||
}
|
||||
std::stringstream ss;
|
||||
ss << str;
|
||||
Keyboard::Keyboard_feedText(ss.str(), false, 0);
|
||||
}
|
||||
}
|
||||
static void minecraft_keyboard_special(int key, int action) {
|
||||
if (key == 65480) {
|
||||
if (action == EGLUT_KEY_PRESS) {
|
||||
client->getOptions()->setFullscreen(!client->getOptions()->getFullscreen());
|
||||
}
|
||||
return;
|
||||
}
|
||||
int mKey = getKeyMinecraft(key);
|
||||
if (action == EGLUT_KEY_PRESS) {
|
||||
Keyboard::inputs->push_back({1, mKey});
|
||||
Keyboard::states[mKey] = 1;
|
||||
} else if (action == EGLUT_KEY_RELEASE) {
|
||||
Keyboard::inputs->push_back({0, mKey});
|
||||
Keyboard::states[mKey] = 0;
|
||||
}
|
||||
}
|
||||
static void minecraft_close() {
|
||||
client->quit();
|
||||
}
|
||||
|
||||
void detachFromJavaStub() {
|
||||
std::cout << "detach from java\n";
|
||||
}
|
||||
void* getJVMEnvStub() {
|
||||
std::cout << "getjvmenv\n";
|
||||
return nullptr;
|
||||
}
|
||||
bool verifyCertChainStub() {
|
||||
std::cout << "verifycertchain\n";
|
||||
return true;
|
||||
}
|
||||
struct xboxSingleton {
|
||||
char filler[8];
|
||||
};
|
||||
xboxSingleton xboxGetAppConfigSingleton() {
|
||||
std::cout << "xbox get app config singleton\n";
|
||||
return xboxSingleton();
|
||||
}
|
||||
void xboxConfigSetSandboxStub() {
|
||||
std::cout << "xbox config: set sandbox (stub)\n";
|
||||
}
|
||||
void patchNotesModelStub() {
|
||||
std::cout << "fetch patch notes\n";
|
||||
}
|
||||
|
||||
extern "C"
|
||||
void pshufb(char* dest, char* src) {
|
||||
char new_dest[16];
|
||||
for (int i = 0; i < 16; i++)
|
||||
new_dest[i] = (src[i] & 0x80) ? 0 : dest[src[i] & 15];
|
||||
memcpy(dest, new_dest, 16);
|
||||
}
|
||||
extern "C"
|
||||
void pshufb_xmm4_xmm0();
|
||||
#include <functional>
|
||||
#include <sys/mman.h>
|
||||
#include <EGL/egl.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
using namespace std;
|
||||
int main(int argc, char *argv[]) {
|
||||
bool enableStackTracePrinting = true;
|
||||
bool workaroundAMD = false;
|
||||
|
||||
int windowWidth = 720;
|
||||
int windowHeight = 480;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "-s") == 0 || strcmp(argv[i], "--scale") == 0) {
|
||||
i++;
|
||||
pixelSize = std::stof(argv[i]);
|
||||
} else if (strcmp(argv[i], "-sw") == 0 || strcmp(argv[i], "--width") == 0) {
|
||||
i++;
|
||||
windowWidth = std::stoi(argv[i]);
|
||||
} else if (strcmp(argv[i], "-sh") == 0 || strcmp(argv[i], "--height") == 0) {
|
||||
i++;
|
||||
windowHeight = std::stoi(argv[i]);
|
||||
} else if (strcmp(argv[i], "-ns") == 0 || strcmp(argv[i], "--no-stacktrace") == 0) {
|
||||
enableStackTracePrinting = false;
|
||||
} else if (strcmp(argv[i], "--pocket-guis") == 0) {
|
||||
enablePocketGuis = true;
|
||||
} else if (strcmp(argv[i], "--server") == 0) {
|
||||
serverMode = true;
|
||||
} else if (strcmp(argv[i], "--amd-fix") == 0) {
|
||||
std::cout << "--amd-fix: Enabling AMD Workaround.\n";
|
||||
workaroundAMD = true;
|
||||
} else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
|
||||
std::cout << "Help\n";
|
||||
std::cout << "--help Shows this help information\n";
|
||||
std::cout << "--scale <scale> Sets the pixel scale\n";
|
||||
std::cout << "--width <width> Sets the window width\n";
|
||||
std::cout << "--height <height> Sets the window height\n";
|
||||
std::cout << "--pocket-guis Switches to Pocket Edition GUIs\n";
|
||||
std::cout << "--no-stacktrace Disables stack trace printing\n";
|
||||
std::cout << "--amd-workaround Fixes crashes on pre-i686 and AMD CPUs\n\n";
|
||||
std::cout << "--server Enable dedicated server mode\n\n";
|
||||
std::cout << "EGL Options\n";
|
||||
std::cout << "-display <display> Sets the display\n";
|
||||
std::cout << "-info Shows info about the display\n\n";
|
||||
std::cout << "MCPE arguments:\n";
|
||||
std::cout << "edu <true|false>\n";
|
||||
std::cout << "mcworld <world>\n";
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (enableStackTracePrinting) {
|
||||
registerCrashHandler();
|
||||
}
|
||||
|
||||
setenv("LC_ALL", "C", 1); // HACK: Force set locale to one recognized by MCPE so that the outdated C++ standard library MCPE uses doesn't fail to find one
|
||||
|
||||
std::cout << "loading native libraries\n";
|
||||
void* glesLib = loadLibraryOS("libGLESv2.so", gles_symbols);
|
||||
void* fmodLib = loadLibraryOS((getCWD() + "libs/native/libfmod.so.8.2").c_str(), fmod_symbols);
|
||||
if (glesLib == nullptr || fmodLib == nullptr)
|
||||
return -1;
|
||||
|
||||
std::cout << "loading hybris libraries\n";
|
||||
stubSymbols(android_symbols, (void*) androidStub);
|
||||
stubSymbols(egl_symbols, (void*) eglStub);
|
||||
hybris_hook("eglGetProcAddress", (void*) eglGetProcAddress);
|
||||
hybris_hook("mcpelauncher_hook", (void*) hookFunction);
|
||||
hookAndroidLog();
|
||||
|
||||
if (!loadLibrary("libc.so") || !loadLibrary("libstdc++.so") || !loadLibrary("libm.so") || !loadLibrary("libz.so"))
|
||||
return -1;
|
||||
// load stub libraries
|
||||
if (!loadLibrary("libandroid.so") || !loadLibrary("liblog.so") || !loadLibrary("libEGL.so") || !loadLibrary("libGLESv2.so") || !loadLibrary("libOpenSLES.so") || !loadLibrary("libfmod.so") || !loadLibrary("libGLESv1_CM.so"))
|
||||
return -1;
|
||||
if (!loadLibrary("libmcpelauncher_mod.so"))
|
||||
return -1;
|
||||
std::cout << "loading MCPE\n";
|
||||
std::string mcpePath = getCWD() + "libs/libminecraftpe.so";
|
||||
void* handle = hybris_dlopen(mcpePath.c_str(), RTLD_LAZY);
|
||||
if (handle == nullptr) {
|
||||
std::cout << "failed to load MCPE: " << hybris_dlerror() << "\n";
|
||||
return -1;
|
||||
}
|
||||
addHookLibrary(handle, mcpePath);
|
||||
|
||||
unsigned int libBase = ((soinfo*) handle)->base;
|
||||
std::cout << "loaded MCPE (at " << libBase << ")\n";
|
||||
|
||||
DIR *dir;
|
||||
struct dirent *ent;
|
||||
std::vector<void*> mods;
|
||||
if ((dir = opendir ("mods/")) != NULL) {
|
||||
std::cout << "loading mods\n";
|
||||
while ((ent = readdir (dir)) != NULL) {
|
||||
if (ent->d_name[0] == '.')
|
||||
continue;
|
||||
std::string fileName (ent->d_name);
|
||||
int len = fileName.length();
|
||||
if (len < 4 || fileName[len - 3] != '.' || fileName[len - 2] != 's' || fileName[len - 1] != 'o')
|
||||
continue;
|
||||
std::cout << "loading: " << fileName << "\n";
|
||||
void* mod = loadMod(fileName);
|
||||
if (mod != nullptr)
|
||||
mods.push_back(mod);
|
||||
}
|
||||
closedir(dir);
|
||||
std::cout << "loaded " << mods.size() << " mods\n";
|
||||
}
|
||||
|
||||
std::cout << "apply patches\n";
|
||||
|
||||
/*
|
||||
unsigned int patchOff = (unsigned int) hybris_dlsym(handle, "_ZN12StoreFactory11createStoreER13StoreListener") + 66;
|
||||
patchCallInstruction((void*) patchOff, (void*) &createStoreHookFunc, false);
|
||||
|
||||
patchOff = (unsigned int) hybris_dlsym(handle, "_ZN11HTTPRequestC2ERKSs") + 154;
|
||||
patchCallInstruction((void*) patchOff, (void*) &constructLinuxHttpRequestInternal, false);
|
||||
|
||||
patchOff = (unsigned int) hybris_dlsym(handle, "_ZN11HTTPRequest4sendEv") + 26;
|
||||
patchCallInstruction((void*) patchOff, (void*) &sendLinuxHttpRequestInternal, false);
|
||||
|
||||
patchOff = (unsigned int) hybris_dlsym(handle, "_ZN11HTTPRequest5abortEv") + 26;
|
||||
patchCallInstruction((void*) patchOff, (void*) &abortLinuxHttpRequestInternal, false);
|
||||
*/
|
||||
unsigned int patchOff = (unsigned int) hybris_dlsym(handle, "_ZN12AndroidStore21createGooglePlayStoreERKSsR13StoreListener");
|
||||
patchCallInstruction((void*) patchOff, (void*) &createStoreHookFunc, true);
|
||||
|
||||
patchOff = (unsigned int) hybris_dlsym(handle, "_ZN26HTTPRequestInternalAndroidC2ER11HTTPRequest");
|
||||
patchCallInstruction((void*) patchOff, (void*) &constructLinuxHttpRequestInternal, true);
|
||||
|
||||
patchOff = (unsigned int) hybris_dlsym(handle, "_ZN26HTTPRequestInternalAndroid4sendEv");
|
||||
patchCallInstruction((void*) patchOff, (void*) &sendLinuxHttpRequestInternal, true);
|
||||
|
||||
patchOff = (unsigned int) hybris_dlsym(handle, "_ZN26HTTPRequestInternalAndroid5abortEv");
|
||||
patchCallInstruction((void*) patchOff, (void*) &abortLinuxHttpRequestInternal, true);
|
||||
|
||||
patchOff = (unsigned int) hybris_dlsym(handle, "_ZN9crossplat10threadpool16detach_from_javaEPv");
|
||||
patchCallInstruction((void*) patchOff, (void*) &detachFromJavaStub, true);
|
||||
|
||||
patchOff = (unsigned int) hybris_dlsym(handle, "_ZN9crossplat11get_jvm_envEv");
|
||||
patchCallInstruction((void*) patchOff, (void*) &getJVMEnvStub, true);
|
||||
|
||||
patchOff = (unsigned int) hybris_dlsym(handle, "_ZN3web4http6client7details22verify_X509_cert_chainERKSt6vectorISsSaISsEERKSs");
|
||||
patchCallInstruction((void*) patchOff, (void*) &verifyCertChainStub, true);
|
||||
|
||||
patchOff = (unsigned int) hybris_dlsym(handle, "_ZN4xbox8services20xbox_live_app_config24get_app_config_singletonEv");
|
||||
patchCallInstruction((void*) patchOff, (void*) &xboxGetAppConfigSingleton, true);
|
||||
|
||||
patchOff = (unsigned int) hybris_dlsym(handle, "_ZN4xbox8services20xbox_live_app_config11set_sandboxESs");
|
||||
patchCallInstruction((void*) patchOff, (void*) &xboxConfigSetSandboxStub, true);
|
||||
|
||||
patchOff = (unsigned int) hybris_dlsym(handle, "_ZN4xbox8services20xbox_live_app_config29set_title_telemetry_device_idERKSs");
|
||||
patchCallInstruction((void*) patchOff, (void*) &xboxConfigSetSandboxStub, true);
|
||||
|
||||
patchOff = (unsigned int) hybris_dlsym(handle, "_ZN15PatchNotesModel17preloadPatchNotesEv");
|
||||
patchCallInstruction((void*) patchOff, (void*) &patchNotesModelStub, true);
|
||||
|
||||
linuxHttpRequestInternalVtable = (void**) ::operator new(8);
|
||||
linuxHttpRequestInternalVtable[0] = (void*) &LinuxHttpRequestInternal::destroy;
|
||||
linuxHttpRequestInternalVtable[1] = (void*) &LinuxHttpRequestInternal::destroy;
|
||||
|
||||
if (workaroundAMD) {/*
|
||||
patchOff = (unsigned int) hybris_dlsym(handle, "_ZN21BlockTessallatorCache5resetER11BlockSourceRK8BlockPos") +
|
||||
(0x40AD97 - 0x40ACD0);
|
||||
for (unsigned int i = 0; i < 0x40ADA0 - 0x40AD97; i++)
|
||||
((char *) (void *) patchOff)[i] = 0x90;*/
|
||||
patchOff = (unsigned int) hybris_dlsym(handle, "_ZN21BlockTessallatorCache5resetER11BlockSourceRK8BlockPos") + (0x40AD9B - 0x40ACD0);
|
||||
patchCallInstruction((void*) patchOff, (void*) &pshufb_xmm4_xmm0, false);
|
||||
}
|
||||
|
||||
std::cout << "patches applied!\n";
|
||||
|
||||
// load symbols for gl
|
||||
gl::getOpenGLVendor = (std::string (*)()) hybris_dlsym(handle, "_ZN2gl15getOpenGLVendorEv");
|
||||
gl::getOpenGLRenderer = (std::string (*)()) hybris_dlsym(handle, "_ZN2gl17getOpenGLRendererEv");
|
||||
gl::getOpenGLVersion = (std::string (*)()) hybris_dlsym(handle, "_ZN2gl16getOpenGLVersionEv");
|
||||
gl::getOpenGLExtensions = (std::string (*)()) hybris_dlsym(handle, "_ZN2gl19getOpenGLExtensionsEv");
|
||||
mce::Platform::OGL::OGL_initBindings = (void (*)()) hybris_dlsym(handle, "_ZN3mce8Platform3OGL12InitBindingsEv");
|
||||
|
||||
// init linux app platform
|
||||
AppPlatform::myVtable = (void**) hybris_dlsym(handle, "_ZTV11AppPlatform");
|
||||
AppPlatform::_singleton = (AppPlatform**) hybris_dlsym(handle, "_ZN11AppPlatform10mSingletonE");
|
||||
AppPlatform::AppPlatform_construct = (void (*)(AppPlatform*)) hybris_dlsym(handle, "_ZN11AppPlatformC2Ev");
|
||||
AppPlatform::AppPlatform_initialize = (void (*)(AppPlatform*)) hybris_dlsym(handle, "_ZN11AppPlatform10initializeEv");
|
||||
AppPlatform::AppPlatform__fireAppFocusGained = (void (*)(AppPlatform*)) hybris_dlsym(handle, "_ZN11AppPlatform19_fireAppFocusGainedEv");
|
||||
|
||||
void** ptr = (void**) hybris_dlsym(handle, "_ZN9crossplat3JVME");
|
||||
*ptr = (void*) 1; // this just needs not to be null
|
||||
|
||||
std::cout << "init app platform vtable\n";
|
||||
LinuxAppPlatform::initVtable(handle);
|
||||
std::cout << "init app platform\n";
|
||||
LinuxAppPlatform* platform = new LinuxAppPlatform();
|
||||
std::cout << "app platform initialized\n";
|
||||
|
||||
Mouse::feed = (void (*)(char, char, short, short, short, short)) hybris_dlsym(handle, "_ZN5Mouse4feedEccssss");
|
||||
|
||||
Keyboard::inputs = (std::vector<KeyboardAction>*) hybris_dlsym(handle, "_ZN8Keyboard7_inputsE");
|
||||
Keyboard::states = (int*) hybris_dlsym(handle, "_ZN8Keyboard7_statesE");
|
||||
Keyboard::Keyboard_feedText = (void (*)(const std::string&, bool, unsigned char)) hybris_dlsym(handle, "_ZN8Keyboard8feedTextERKSsbh");
|
||||
|
||||
Options::Options_getFullscreen = (bool (*)(Options*)) hybris_dlsym(handle, "_ZNK7Options13getFullscreenEv");
|
||||
Options::Options_setFullscreen = (void (*)(Options*, bool)) hybris_dlsym(handle, "_ZN7Options13setFullscreenEb");
|
||||
|
||||
std::cout << "init window\n";
|
||||
eglutInitWindowSize(windowWidth, windowHeight);
|
||||
eglutInitAPIMask(EGLUT_OPENGL_ES2_BIT);
|
||||
eglutInit(argc, argv);
|
||||
|
||||
winId = eglutCreateWindow("Minecraft");
|
||||
|
||||
// init MinecraftGame
|
||||
App::App_init = (void (*)(App*, AppContext&)) hybris_dlsym(handle, "_ZN3App4initER10AppContext");
|
||||
MinecraftGame::MinecraftGame_construct = (void (*)(MinecraftGame*, int, char**)) hybris_dlsym(handle, "_ZN13MinecraftGameC2EiPPc");
|
||||
MinecraftGame::MinecraftGame_update = (void (*)(MinecraftGame*)) hybris_dlsym(handle, "_ZN13MinecraftGame6updateEv");
|
||||
MinecraftGame::MinecraftGame_setRenderingSize = (void (*)(MinecraftGame*, int, int)) hybris_dlsym(handle, "_ZN13MinecraftGame16setRenderingSizeEii");
|
||||
MinecraftGame::MinecraftGame_setUISizeAndScale = (void (*)(MinecraftGame*, int, int, float)) hybris_dlsym(handle, "_ZN13MinecraftGame17setUISizeAndScaleEiif");
|
||||
MinecraftGame::MinecraftGame_getOptions = (Options* (*)(MinecraftGame*)) hybris_dlsym(handle, "_ZN13MinecraftGame10getOptionsEv");
|
||||
AppContext ctx;
|
||||
ctx.platform = platform;
|
||||
ctx.doRender = true;
|
||||
|
||||
platform->initialize();
|
||||
|
||||
mce::Platform::OGL::initBindings();
|
||||
|
||||
std::cout << "create minecraft client\n";
|
||||
client = new MinecraftGame(argc, argv);
|
||||
std::cout << "init minecraft client\n";
|
||||
client->init(ctx);
|
||||
std::cout << "initialized lib\n";
|
||||
|
||||
if (client->getOptions()->getFullscreen())
|
||||
eglutToggleFullscreen();
|
||||
|
||||
for (void* mod : mods) {
|
||||
void (*initFunc)(MinecraftGame*) = (void (*)(MinecraftGame*)) hybris_dlsym(mod, "mod_set_minecraft");
|
||||
if ((void*) initFunc != nullptr)
|
||||
initFunc(client);
|
||||
}
|
||||
|
||||
eglutIdleFunc(minecraft_idle);
|
||||
eglutReshapeFunc(minecraft_reshape);
|
||||
eglutDisplayFunc(minecraft_draw);
|
||||
eglutMouseFunc(minecraft_mouse);
|
||||
eglutMouseButtonFunc(minecraft_mouse_button);
|
||||
eglutKeyboardFunc(minecraft_keyboard);
|
||||
eglutSpecialFunc(minecraft_keyboard_special);
|
||||
eglutCloseWindowFunc(minecraft_close);
|
||||
std::cout << "initialized display\n";
|
||||
|
||||
// init
|
||||
//(*AppPlatform::_singleton)->_fireAppFocusGained();
|
||||
client->setRenderingSize(windowWidth, windowHeight);
|
||||
client->setUISizeAndScale(windowWidth, windowHeight, pixelSize);
|
||||
eglutMainLoop();
|
||||
|
||||
return 0;
|
||||
}
|
||||
0
src/server.cpp
Normal file
0
src/server.cpp
Normal file
Loading…
x
Reference in New Issue
Block a user