summaryrefslogtreecommitdiff
path: root/sal
diff options
context:
space:
mode:
authorTor Lillqvist <tlillqvist@suse.com>2011-11-24 18:59:47 +0200
committerTor Lillqvist <tlillqvist@suse.com>2011-11-24 19:20:14 +0200
commit5df86787093a8c9c73557fb8d01581a15bad5d86 (patch)
tree5f2e456ddb3a4dc504132daaae24a40f1e81b365 /sal
parent0cc0df05888a4cacf4e654d4728c77822fd124a5 (diff)
Binary patch the mmapped libgnustl_shared.so from NDK r7
Poke in a jump to our replacement for std::type_info::operator==. See http://code.google.com/p/android/issues/detail?id=22165 .
Diffstat (limited to 'sal')
-rw-r--r--sal/osl/android/Makefile2
-rw-r--r--sal/osl/android/jni/lo-bootstrap.c122
2 files changed, 121 insertions, 3 deletions
diff --git a/sal/osl/android/Makefile b/sal/osl/android/Makefile
index a22ddfca3ef9..29dedef7e41d 100644
--- a/sal/osl/android/Makefile
+++ b/sal/osl/android/Makefile
@@ -107,12 +107,10 @@ install: ndk-build
run: install
# Note: these are just examples.
#
-# The first two ones should work
adb shell am start -n org.libreoffice.android/.Bootstrap -e lo-main-library libcppunittester -e lo-main-cmdline "$(APP_DATA_PATH)/lib/libqa_sal_types.so"
#
adb shell am start -n org.libreoffice.android/.Bootstrap -e lo-main-library libcppunittester -e lo-main-cmdline "$(APP_DATA_PATH)/lib/libtest_i18npool_test_breakiterator.so --protector libunoexceptionprotector.so unoexceptionprotector '-env:UNO_TYPES=file:///assets/bin/udkapi.rdb file:///assets/bin/types.rdb' '-env:UNO_SERVICES=file:///assets/xml/ure/services.rdb file:///assets/ComponentTarget/i18npool/util/i18npool.component' -env:LO_LIB_DIR=file://$(APP_DATA_PATH)/lib"
#
-# This doesn't work yet
adb shell am start -n org.libreoffice.android/.Bootstrap -e lo-main-library libunoexe -e lo-main-cmdline "-ro /assets/lib/uno_services.rdb -ro /assets/lib/uno_types.rdb -s com.sun.star.test.bridge.BridgeTest -- com.sun.star.test.bridge.CppTestObject" -e lo-main-delay 2
clean:
diff --git a/sal/osl/android/jni/lo-bootstrap.c b/sal/osl/android/jni/lo-bootstrap.c
index 0ddbe3f87974..1c2971d39864 100644
--- a/sal/osl/android/jni/lo-bootstrap.c
+++ b/sal/osl/android/jni/lo-bootstrap.c
@@ -56,6 +56,8 @@
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "lo-bootstrap", __VA_ARGS__))
#define LOGW(...) ((void)__android_log_print(ANDROID_LOG_WARN, "lo-bootstrap", __VA_ARGS__))
+#define ROUND_DOWN(ptr,multiple) (void *)(((unsigned) (ptr)) & ~((multiple)-1))
+
struct engine {
int dummy;
};
@@ -69,6 +71,8 @@ static int lo_main_argc;
static const char **lo_main_argv;
static int sleep_time = 0;
+/* Zip data structures */
+
/* compression methods */
#define STORE 0
#define DEFLATE 8
@@ -124,6 +128,8 @@ struct cdir_end {
char comment[0];
} __attribute__((__packed__));
+/* End of Zip data structures */
+
static void
engine_handle_cmd(struct android_app* app,
int32_t cmd)
@@ -818,7 +824,119 @@ lo_dlcall_argc_argv(void *function,
return result;
}
-void android_main(struct android_app* state)
+/* Replacement std::type_info::operator== */
+
+static void
+dummy_patched_operator_equals_arm(void)
+{
+ __asm(" .arm\n"
+ " .global patched_operator_equals_arm\n"
+ "patched_operator_equals_arm:\n"
+ " push {lr}\n"
+
+ /* Load name pointers into r0 and r1 */
+ " ldr r0, [r0, #4]\n"
+ " ldr r1, [r1, #4]\n"
+
+ /* First compare pointers */
+ " cmp r0, r1\n"
+
+ /* If equal, return true */
+ " beq .Lx1\n"
+
+ /* Otherwise call strcmp */
+ " bl strcmp\n"
+
+ /* And return true or false */
+ " cmp r0, #0\n"
+ " moveq r0, #1\n"
+ " movne r0, #0\n"
+ " b .Lx9\n"
+
+ ".Lx1:\n"
+ " mov r0, #1\n"
+
+ ".Lx9:\n"
+ " pop {pc}\n"
+ );
+}
+
+extern unsigned int patched_operator_equals_arm;
+
+static void
+patch_type_info_operator_equals(void)
+{
+ /* There is a bug in std::type_info::operator== in
+ * libgnustl_shared.so in NDK r7 at least. It compares the type
+ * name pointers instead of comparing the type name strings. See
+ * http://code.google.com/p/android/issues/detail?id=22165 . So
+ * patch it, poke in a jump to our own code above instead.
+ */
+
+ void *libgnustl_shared;
+ void *operator_equals;
+
+ void *base;
+ size_t size;
+
+ /* ARM (not Thumb) code of the operator as in NDK r7 */
+ static unsigned int expected_r7_code[] = {
+ 0xe5903004, /* ldr r3, [r0, #4] */
+ 0xe5910004, /* ldr r0, [r1, #4] */
+ 0xe1530000, /* cmp r3, r0 */
+ 0x13a00000, /* movne, #0 */
+ 0x03a00001, /* moveq r0, #1 */
+ 0xe12fff1e /* bx lr */
+ };
+
+ /* libgnustl_shared.so should be already loaded as we build
+ * all LO code against it, so as we have loaded the .so
+ * containing lo_main() already, libgnustl_shared.so will have
+ * been brought in, too.
+ */
+ libgnustl_shared = dlopen("libgnustl_shared.so", RTLD_LOCAL);
+ if (libgnustl_shared == NULL) {
+ LOGI("android_main: libgnustl_shared.so not mapped??");
+ exit(0);
+ }
+
+ operator_equals = dlsym(libgnustl_shared, "_ZNKSt9type_infoeqERKS_");
+ if (operator_equals == NULL) {
+ LOGI("android_main: std::type_info::operator== not found!?");
+ exit(0);
+ }
+ LOGI("std::type_info::operator== is at %p", operator_equals);
+
+ if (memcmp(operator_equals, expected_r7_code, sizeof(expected_r7_code)) != 0) {
+ LOGI("android_main: Code for std::type_info::operator== does not match that in NDK r7; not patching it");
+ return;
+ }
+
+ base = ROUND_DOWN(operator_equals, getpagesize());
+ size = operator_equals + sizeof(expected_r7_code) - ROUND_DOWN(operator_equals, getpagesize());
+ if (mprotect(base, size, PROT_READ|PROT_WRITE|PROT_EXEC) == -1) {
+ LOGI("android_main: mprotect() failed: %s", strerror(errno));
+ return;
+ }
+
+ if ((((unsigned) operator_equals) & 0x03) != 0) {
+ LOGI("android_main: Address of operator== is not at word boundary, huh?");
+ return;
+ }
+
+ if ((((unsigned) &patched_operator_equals_arm) & 0x03) != 0) {
+ LOGI("android_main: Address of patched_operator_equals_arm is not at word boundary, huh?");
+ return;
+ }
+
+ /* Poke a "b patched_operator_equals_arm" into it instead */
+ *((unsigned *) operator_equals) =
+ (0xEA000000 |
+ ((((int) &patched_operator_equals_arm - ((int) operator_equals + 8)) / 4) & 0x00FFFFFF));
+}
+
+void
+android_main(struct android_app* state)
{
struct engine engine;
Dl_info lo_main_info;
@@ -836,6 +954,8 @@ void android_main(struct android_app* state)
if (sleep_time != 0)
sleep(sleep_time);
+ patch_type_info_operator_equals();
+
lo_main(lo_main_argc, lo_main_argv);
exit(0);