vm->GetEnv(reinterpret_cast<void **>(&env), JNI_VERSION_1_6); if (env == nullptr) { return0;
}
jclass klass = env->FindClass("Main"); if (klass != nullptr) { int i, count1, count2;
count1 = gNativeBridgeArtCallbacks->getNativeMethodCount(env, klass);
std::unique_ptr<JNINativeMethod[]> methods(new JNINativeMethod[count1]); if (methods == nullptr) { return0;
}
count2 = gNativeBridgeArtCallbacks->getNativeMethods(env, klass, methods.get(), count1); if (count1 == count2) {
printf("Test ART callbacks: all JNI function number is %d.\n", count1);
}
for (i = 0; i < count1; i++) {
NativeBridgeMethod* nb_method = find_native_bridge_method(methods[i].name); if (nb_method != nullptr) {
jmethodID mid = nullptr; if (nb_method->static_method) {
mid = env->GetStaticMethodID(klass, methods[i].name, nb_method->signature);
} else {
mid = env->GetMethodID(klass, methods[i].name, nb_method->signature);
} if (mid != nullptr) { constchar* shorty = gNativeBridgeArtCallbacks->getMethodShorty(env, mid); if (strcmp(shorty, methods[i].signature) == 0) {
printf(" name:%s, signature:%s, shorty:%s.\n",
methods[i].name, nb_method->signature, shorty);
}
}
}
}
methods.release();
}
// This code is adapted from 004-SignalTest and causes a segfault. char *go_away_compiler = nullptr;
[[ noreturn ]] staticvoid test_sigaction_handler([[maybe_unused]] int sig,
[[maybe_unused]] siginfo_t* info,
[[maybe_unused]] void* context) {
printf("Should not reach the test sigaction handler.");
abort();
}
staticvoid raise_sigsegv() { #ifdefined(__arm__) || defined(__i386__) || defined(__aarch64__)
*go_away_compiler = 'a'; #elifdefined(__riscv) // Cause a SEGV using an instruction known to be 4 bytes long to account for hardcoded jump // in the signal handler asmvolatile("ld zero, (zero);" : : :); #elifdefined(__x86_64__) // Cause a SEGV using an instruction known to be 2 bytes long to account for hardcoded jump // in the signal handler asmvolatile("movl $0, %%eax;""movb %%ah, (%%rax);" : : : "%eax"); #else // On other architectures we simulate SEGV.
kill(getpid(), SIGSEGV); #endif
}
static jint trampoline_Java_Main_testSignal(JNIEnv*, jclass) { // Install the sigaction handler above, which should *not* be reached as the native-bridge // handler should be called first. Note: we won't chain at all, if we ever get here, we'll die. struct sigaction tmp;
sigemptyset(&tmp.sa_mask);
tmp.sa_sigaction = test_sigaction_handler; #if !defined(__APPLE__)
tmp.sa_restorer = nullptr; #endif
// Test segv
sigaction(SIGSEGV, &tmp, nullptr);
raise_sigsegv();
// Test sigill
sigaction(SIGILL, &tmp, nullptr);
kill(getpid(), SIGILL);
#ifdefined(__BIONIC__) // Do the same again, but with sigaction64. struct sigaction64 tmp2;
sigemptyset64(&tmp2.sa_mask);
tmp2.sa_sigaction = test_sigaction_handler; #ifdefined(SA_RESTORER)
tmp2.sa_restorer = nullptr; #endif
// Reraise SIGSEGV/SIGILL even on non-bionic, so that the expected output is // the same.
raise_sigsegv();
kill(getpid(), SIGILL);
return1234;
}
// Status of the tricky control path of testSignalHandlerNotReturn. // // "kNone" is the default status except testSignalHandlerNotReturn, // others are used by testSignalHandlerNotReturn. enumclass TestStatus {
kNone,
kRaiseFirst,
kHandleFirst,
kRaiseSecond,
kHandleSecond,
};
// State transition helper for testSignalHandlerNotReturn. class SignalHandlerTestStatus { public:
SignalHandlerTestStatus() : state_(TestStatus::kNone) {
}
static SignalHandlerTestStatus gSignalTestStatus; // The context is used to jump out from signal handler. static sigjmp_buf gSignalTestJmpBuf;
// Test whether NativeBridge can receive future signal when its handler doesn't return. // // Control path: // 1. Raise first SIGSEGV in test function. // 2. Raise another SIGSEGV in NativeBridge's signal handler which is handling // the first SIGSEGV. // 3. Expect that NativeBridge's signal handler invokes again. And jump back // to test function in when handling second SIGSEGV. // 4. Exit test. // // NOTE: sigchain should be aware that "special signal handler" may not return. // Pay attention if this case fails. staticvoid trampoline_Java_Main_testSignalHandlerNotReturn(JNIEnv*, jclass) { if (gSignalTestStatus.Get() != TestStatus::kNone) {
printf("ERROR: test already started?\n"); return;
}
printf("start testSignalHandlerNotReturn\n");
if (sigsetjmp(gSignalTestJmpBuf, 1) == 0) {
gSignalTestStatus.Set(TestStatus::kRaiseFirst);
printf("raising first SIGSEGV\n");
raise_sigsegv();
} else { // jump to here from signal handler when handling second SIGSEGV. if (gSignalTestStatus.Get() != TestStatus::kHandleSecond) {
printf("ERROR: not jump from second SIGSEGV?\n"); return;
}
gSignalTestStatus.Reset();
printf("back to test from signal handler via siglongjmp(), and done!\n");
}
}
// Signal handler for testSignalHandlerNotReturn. // This handler won't return. staticbool NotReturnSignalHandler() { if (gSignalTestStatus.Get() == TestStatus::kRaiseFirst) { // handling first SIGSEGV
gSignalTestStatus.Set(TestStatus::kHandleFirst);
printf("handling first SIGSEGV, will raise another\n");
sigset_t set;
sigemptyset(&set);
sigaddset(&set, SIGSEGV);
printf("unblock SIGSEGV in handler\n");
sigprocmask(SIG_UNBLOCK, &set, nullptr);
gSignalTestStatus.Set(TestStatus::kRaiseSecond);
printf("raising second SIGSEGV\n");
raise_sigsegv(); // raise second SIGSEGV
} elseif (gSignalTestStatus.Get() == TestStatus::kRaiseSecond) { // handling second SIGSEGV
gSignalTestStatus.Set(TestStatus::kHandleSecond);
printf("handling second SIGSEGV, will jump back to test function\n");
siglongjmp(gSignalTestJmpBuf, 1);
}
printf("ERROR: should not reach here!\n"); returnfalse;
}
if (handle == nullptr) {
printf("Handle = nullptr!\n");
printf("Was looking for %s.\n", libpath);
printf("Error = %s.\n", dlerror()); char cwd[1024] = {'\0'}; if (getcwd(cwd, sizeof(cwd)) != nullptr) {
printf("Current working dir: %s\n", cwd);
}
} return handle;
}
extern"C"void* native_bridge_getTrampoline(void* handle, constchar* name, constchar* shorty,
[[maybe_unused]] uint32_t len) {
printf("Getting trampoline for %s with shorty %s.\n", name, shorty);
// The name here is actually the JNI name, so we can directly do the lookup. void* sym = dlsym(handle, name);
NativeBridgeMethod* method = find_native_bridge_method(name); if (method == nullptr) return nullptr;
method->fnPtr = sym;
return method->trampoline;
}
extern"C"bool native_bridge_isSupported(constchar* libpath) {
printf("Checking for support.\n");
if (libpath == nullptr) { returnfalse;
} // We don't want to hijack javacore. So we should get libarttest... return strcmp(libpath, "libjavacore.so") != 0;
}
namespace android {
// Environment values required by the apps running with native bridge. struct NativeBridgeRuntimeValues { constchar* os_arch; constchar* cpu_abi; constchar* cpu_abi2; constchar* *supported_abis;
int32_t abi_count;
};
#ifdefined(__x86_64__) // 64 bit mac build. #define CTX_EIP uc_mcontext->__ss.__rip #else // 32 bit mac build. #define CTX_EIP uc_mcontext->__ss.__eip #endif
#elifdefined(__x86_64__) // 64 bit linux build. #define CTX_EIP uc_mcontext.gregs[REG_RIP] #else // 32 bit linux build. #define CTX_EIP uc_mcontext.gregs[REG_EIP] #endif #endif
// A placeholder special handler, continueing after the faulting location. This code comes from // 004-SignalTest. staticbool nb_signalhandler(int sig, siginfo_t* info, void* context) {
printf("NB signal handler with signal %d.\n", sig);
if (gSignalTestStatus.Get() == TestStatus::kNone) { return StandardSignalHandler(sig, info, context);
} elseif (sig == SIGSEGV) { return NotReturnSignalHandler();
} else {
printf("ERROR: should not reach here!\n"); returnfalse;
}
}
static ::android::NativeBridgeSignalHandlerFn native_bridge_getSignalHandler(int signal) { // Test segv for already claimed signal, and sigill for not claimed signal if ((signal == SIGSEGV) || (signal == SIGILL)) { return &nb_signalhandler;
} return nullptr;
}
extern"C"constchar* native_bridge_getError() {
printf("getError() in native bridge.\n"); return"";
}
extern"C"bool native_bridge_isPathSupported([[maybe_unused]] constchar* library_path) {
printf("Checking for path support in native bridge.\n"); returnfalse;
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.