diff options
author | Tor Lillqvist <tlillqvist@suse.com> | 2011-11-24 22:53:01 +0200 |
---|---|---|
committer | Tor Lillqvist <tlillqvist@suse.com> | 2011-11-24 23:12:22 +0200 |
commit | 1c08f9066ca235018f69bc0999f7c61391de27a6 (patch) | |
tree | b92cb8fc55ce70d19413c95f6fb6eb3bfde52f81 /sal | |
parent | b6e5f5da292f89782f3084753de4c0c172dd4517 (diff) |
Replace also the std::type_info::before() in libgnustl_shared.so
It too suffers from the same problem as operator==: Compares name
pointers, not name strings. Thus with two things to patch, had to
refactor it.
(before() doesn't seem to get called when running the bridgetest at
least, though.)
Noticed that there is no need to wrap the replacement asm snippets
with dummy C functions. Just having them at the outermost level in the
source file works as expected.
Diffstat (limited to 'sal')
-rw-r--r-- | sal/osl/android/jni/lo-bootstrap.c | 185 |
1 files changed, 121 insertions, 64 deletions
diff --git a/sal/osl/android/jni/lo-bootstrap.c b/sal/osl/android/jni/lo-bootstrap.c index 5dba3fd94f21..2e1715509d3e 100644 --- a/sal/osl/android/jni/lo-bootstrap.c +++ b/sal/osl/android/jni/lo-bootstrap.c @@ -826,71 +826,117 @@ lo_dlcall_argc_argv(void *function, return result; } +/* There is a bug in std::type_info::operator== and + * std::type_info::before() in libgnustl_shared.so in NDK r7 at + * least. They compare the type name pointers instead of comparing the + * type name strings. See + * http://code.google.com/p/android/issues/detail?id=22165 . So patch + * that, poke in jumps to our own code snippets below instead. + */ + /* 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" +__asm(" .arm\n" + " .global replacement_operator_equals_arm\n" + "replacement_operator_equals_arm:\n" + " push {lr}\n" - /* Load name pointers into r0 and r1 */ - " ldr r0, [r0, #4]\n" - " ldr r1, [r1, #4]\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" + /* First compare pointers */ + " cmp r0, r1\n" - /* If equal, return true */ - " beq .Lx1\n" + /* If equal, return true */ + " beq .L.equals.1\n" - /* Otherwise call strcmp */ - " bl strcmp\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" + /* And return true or false */ + " cmp r0, #0\n" + " moveq r0, #1\n" + " movne r0, #0\n" + " b .L.equals.9\n" - ".Lx1:\n" - " mov r0, #1\n" + ".L.equals.1:\n" + " mov r0, #1\n" - ".Lx9:\n" - " pop {pc}\n" - ); -} + ".L.equals.9:\n" + " pop {pc}\n" + ); + +extern unsigned int replacement_operator_equals_arm; + +/* The ARM (not Thumb) code of the operator== in NDK r7 */ +static unsigned int expected_operator_equals_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 */ +}; + +/* Ditto for std::type_info::before() */ + +__asm(" .arm\n" + " .global replacement_method_before_arm\n" + "replacement_method_before_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 false */ + " beq .L.before.1\n" -extern unsigned int patched_operator_equals_arm; + /* Otherwise call strcmp */ + " bl strcmp\n" + + /* And return true or false */ + " cmp r0, #0\n" + " movlt r0, #1\n" + " movge r0, #0\n" + " b .L.before.9\n" + + ".L.before.1:\n" + " mov r0, #0\n" + + ".L.before.9:\n" + " pop {pc}\n" + ); + +extern unsigned int replacement_method_before_arm; + +static unsigned int expected_method_before_r7_code[] = { + 0xe5903004, /* ldr r3, [r0, #4] */ + 0xe5910004, /* ldr r0, [r1, #4] */ + 0xe1530000, /* cmp r3, r0 */ + 0x23a00000, /* movcs r0, #0 */ + 0x33a00001, /* movcc r0, #1 */ + 0xe12fff1e /* bx lr */ +}; static void -patch_type_info_operator_equals(void) +patch(const char *symbol, + const char *plaintext, + unsigned *expected_code, + size_t expected_code_size, + unsigned *replacement_code) { - /* 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 *code; 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 @@ -902,41 +948,42 @@ patch_type_info_operator_equals(void) exit(0); } - operator_equals = dlsym(libgnustl_shared, "_ZNKSt9type_infoeqERKS_"); - if (operator_equals == NULL) { - LOGF("android_main: std::type_info::operator== not found!?"); + code = dlsym(libgnustl_shared, symbol); + if (code == NULL) { + LOGF("android_main: %s not found!?", plaintext); exit(0); } - /* LOGI("std::type_info::operator== is at %p", operator_equals); */ + /* LOGI("%s is at %p", plaintext, operator_equals); */ - if (memcmp(operator_equals, expected_r7_code, sizeof(expected_r7_code)) != 0) { - LOGE("android_main: Code for std::type_info::operator== does not match that in NDK r7; not patching it"); + if ((((unsigned) code) & 0x03) != 0) { + LOGE("android_main: Address of %s is not at word boundary, huh?", plaintext); 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) { - LOGE("android_main: mprotect() failed: %s", strerror(errno)); + if ((((unsigned) &replacement_code) & 0x03) != 0) { + LOGE("android_main: Address of replacement %s is not at word boundary, huh?", plaintext); return; } - if ((((unsigned) operator_equals) & 0x03) != 0) { - LOGE("android_main: Address of operator== is not at word boundary, huh?"); + if (memcmp(code, expected_code, expected_code_size) != 0) { + LOGI("android_main: Code for %s does not match that in NDK r7; not patching it", plaintext); return; } - if ((((unsigned) &patched_operator_equals_arm) & 0x03) != 0) { - LOGE("android_main: Address of patched_operator_equals_arm is not at word boundary, huh?"); + base = ROUND_DOWN(code, getpagesize()); + size = code + sizeof(expected_code_size) - ROUND_DOWN(code, getpagesize()); + if (mprotect(base, size, PROT_READ|PROT_WRITE|PROT_EXEC) == -1) { + LOGE("android_main: mprotect() failed: %s", strerror(errno)); return; } - /* Poke a "b patched_operator_equals_arm" into it instead */ - *((unsigned *) operator_equals) = + /* Poke a "b replacement_code" into it instead */ + *((unsigned *) code) = (0xEA000000 | - ((((int) &patched_operator_equals_arm - ((int) operator_equals + 8)) / 4) & 0x00FFFFFF)); + ((((int) replacement_code - ((int) code + 8)) / 4) & 0x00FFFFFF)); } + void android_main(struct android_app* state) { @@ -956,7 +1003,17 @@ android_main(struct android_app* state) if (sleep_time != 0) sleep(sleep_time); - patch_type_info_operator_equals(); + patch("_ZNKSt9type_infoeqERKS_", + "std::type_info::operator==", + expected_operator_equals_r7_code, + sizeof(expected_operator_equals_r7_code), + &replacement_operator_equals_arm); + + patch("_ZNKSt9type_info6beforeERKS_", + "std::type_info::before()", + expected_method_before_r7_code, + sizeof(expected_method_before_r7_code), + &replacement_method_before_arm); lo_main(lo_main_argc, lo_main_argv); |