How to catch JNI Crashes as exceptions using Signal handling based mechanism in Java [duplicate]
Asked Answered
L

1

0

I developed a Java tool and it has many JNI functions, I am getting JNI crashes often. Is there any possibility to avoid those crashes or to catch these crashes as exceptions. I surfed internet and found it is possible through signal processing, signal chanining, sigaction(), etc. But I could not get a reliable source to direct me. Please do guide me on this.

Lengthen answered 7/5, 2015 at 15:37 Comment(0)
S
1

JNI exceptions are considered as signals. You could set up your signal handlers by sigaction and then you could try to unwind the crash stack, for example by libcorkscrew, to save it on the disk. After that you could invoke a Java method via JNI interfaces to process the info you saved.

Sample:

int watched_signals[] = { SIGABRT, SIGILL, SIGSEGV, SIGINT, SIGKILL };

void sighandler_func(int sig, siginfo_t* sig_info, void* ptr)
{
    // Dump the callstack by libcorkscrew
    ...
    // Call a JNI interface to process the stack info
    ...
}

struct sigaction sighandler;
sighandler.sa_sigaction = &sighandler_func;
sighandler.sa_mask = 0;
sighandler.sa_flags = SA_SIGINFO | SA_ONSTACK;

for(int signal : watched_signals)
{
    sigaction(signal, &sighandler, nullptr);
}

Suppose you have involved libcorkscrew into you ndk project then you could get the crash stack:

#include <dlfcn.h>
#include <ucontext.h>
#include <corkscrew/backtrace.h>
#include <backtrace-arch.h>

void dump_stack(int sig, siginfo_t* sig_info, void* ptr)
{
    const size_t BACKTRACE_FRAMES_MAX = 0xFF;

    static backtrace_frame_t frames[BACKTRACE_FRAMES_MAX];
    static backtrace_symbol_t symbols[BACKTRACE_FRAMES_MAX];

    map_info_t* const info = acquire_my_map_info_list();
    const ssize_t size = unwind_backtrace_signal_arch(sig_info, ptr, info, frames, 0, BACKTRACE_FRAMES_MAX);
    get_backtrace_symbols(frames, size, symbols);

    for (int i = 0; i < size; i++)
    {
        backtrace_symbol_t& symbol = symbols[i];
        // You could change the printf to fwrite if you want to save the info on disk
        printf("#%02d pc %08X  %s (%s+%d)",
                    i,
                    symbol.relative_pc,
                    symbol.map_name ? symbol.map_name : "<unknown>",
                    symbol.demangled_name ? symbol.demangled_name : symbol.symbol_name,
                    symbol.relative_pc - symbol.relative_symbol_addr);
    }
    free_backtrace_symbols(symbols, size);
    release_my_map_info_list(info);
}

Even through you could continue the program after you handled the signal but I strongly suggest you to save the info on disk and process it in the next app launch. Because most of the time you program would fail when a signal raised.

Sanasanabria answered 7/5, 2015 at 15:44 Comment(6)
Can you give a simple example code or link to understand the concept better?Lengthen
Since you mentioned the JNI I supposed you have the NDK project been involved in your project. And then you could add the snippet into any of you c/cpp source code. For most cases you'd better put it in the JNI_OnLoad which is the entry point of your native code.Sanasanabria
Thank you for your update, I am new to JNI implementations. I could not understand it. Where the code snippet need to be append in my code? Sample.java ` Sample{` ` native void callJavatoC();` } Sample.C JNIEXPORT void Java_Class_callJavatoC(JNIEnv* env, jobject obj) { "place where crashes occur" }`Lengthen
If you just want to debug your native code please refer to the ndk-gdb: #10534867 If you want to make you app to catch the unexpected native crashes try to add the snippet at the beginning of your JNI_OnLoad. Then when the crash happens you code get the info from adb logcat or the file on disk, which depends on your choice.Sanasanabria
Is there any way to find the reason for the crash using the hs_err* report?Lengthen
Let us continue this discussion in chat.Lengthen

© 2022 - 2024 — McMap. All rights reserved.