mirror of
git://f0xx.org/android_cast
synced 2026-07-29 04:57:40 +03:00
crash handler snapshot, unverified
This commit is contained in:
122
ndk/jni/crash_hook.c
Normal file
122
ndk/jni/crash_hook.c
Normal file
@@ -0,0 +1,122 @@
|
||||
#include <jni.h>
|
||||
#include <android/log.h>
|
||||
#include <dlfcn.h>
|
||||
#include <signal.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <time.h>
|
||||
#include <unistd.h>
|
||||
#include <unwind.h>
|
||||
|
||||
#define LOG_TAG "androidcast_crash"
|
||||
#define REPORT_DIR_MAX 512
|
||||
#define MAX_FRAMES 64
|
||||
|
||||
static char g_report_dir[REPORT_DIR_MAX];
|
||||
static volatile sig_atomic_t g_handling;
|
||||
|
||||
typedef struct {
|
||||
void **frames;
|
||||
int max;
|
||||
int count;
|
||||
} backtrace_state_t;
|
||||
|
||||
static _Unwind_Reason_Code unwind_callback(struct _Unwind_Context *context, void *arg) {
|
||||
backtrace_state_t *state = (backtrace_state_t *) arg;
|
||||
uintptr_t pc = _Unwind_GetIP(context);
|
||||
if (pc == 0) {
|
||||
return _URC_NO_REASON;
|
||||
}
|
||||
if (state->count < state->max) {
|
||||
state->frames[state->count++] = (void *) pc;
|
||||
}
|
||||
return _URC_NO_REASON;
|
||||
}
|
||||
|
||||
static int capture_backtrace(void **frames, int max) {
|
||||
backtrace_state_t state = {frames, max, 0};
|
||||
_Unwind_Backtrace(unwind_callback, &state);
|
||||
return state.count;
|
||||
}
|
||||
|
||||
static void write_native_report(const char *signal_name) {
|
||||
if (g_report_dir[0] == '\0') {
|
||||
return;
|
||||
}
|
||||
char path[REPORT_DIR_MAX + 64];
|
||||
snprintf(path, sizeof(path), "%s/native_%d_%ld.txt",
|
||||
g_report_dir, (int) getpid(), (long) time(NULL));
|
||||
FILE *f = fopen(path, "w");
|
||||
if (!f) {
|
||||
return;
|
||||
}
|
||||
fprintf(f, "signal=%s\n", signal_name);
|
||||
fprintf(f, "pid=%d\n", (int) getpid());
|
||||
void *frames[MAX_FRAMES];
|
||||
int n = capture_backtrace(frames, MAX_FRAMES);
|
||||
for (int i = 0; i < n; i++) {
|
||||
Dl_info info;
|
||||
memset(&info, 0, sizeof(info));
|
||||
if (dladdr(frames[i], &info) && info.dli_fname) {
|
||||
uintptr_t offset = (uintptr_t) frames[i] - (uintptr_t) info.dli_fbase;
|
||||
fprintf(f, "#%02d %p %s", i, frames[i], info.dli_fname);
|
||||
if (info.dli_sname) {
|
||||
fprintf(f, " %s+0x%lx", info.dli_sname,
|
||||
(unsigned long) ((uintptr_t) frames[i] - (uintptr_t) info.dli_saddr));
|
||||
} else {
|
||||
fprintf(f, "+0x%lx", (unsigned long) offset);
|
||||
}
|
||||
fprintf(f, "\n");
|
||||
} else {
|
||||
fprintf(f, "#%02d %p\n", i, frames[i]);
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
static void crash_signal_handler(int sig) {
|
||||
if (g_handling) {
|
||||
_exit(128 + sig);
|
||||
}
|
||||
g_handling = 1;
|
||||
const char *name = "UNKNOWN";
|
||||
switch (sig) {
|
||||
case SIGSEGV: name = "SIGSEGV"; break;
|
||||
case SIGABRT: name = "SIGABRT"; break;
|
||||
case SIGBUS: name = "SIGBUS"; break;
|
||||
case SIGFPE: name = "SIGFPE"; break;
|
||||
case SIGILL: name = "SIGILL"; break;
|
||||
}
|
||||
write_native_report(name);
|
||||
signal(sig, SIG_DFL);
|
||||
raise(sig);
|
||||
}
|
||||
|
||||
static void install_handlers(void) {
|
||||
struct sigaction sa;
|
||||
memset(&sa, 0, sizeof(sa));
|
||||
sa.sa_handler = crash_signal_handler;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
sa.sa_flags = SA_RESETHAND;
|
||||
sigaction(SIGSEGV, &sa, NULL);
|
||||
sigaction(SIGABRT, &sa, NULL);
|
||||
sigaction(SIGBUS, &sa, NULL);
|
||||
sigaction(SIGFPE, &sa, NULL);
|
||||
sigaction(SIGILL, &sa, NULL);
|
||||
}
|
||||
|
||||
JNIEXPORT void JNICALL
|
||||
Java_com_foxx_androidcast_crash_CrashNativeBridge_nativeInstallCrashHook(
|
||||
JNIEnv *env, jclass clazz, jstring reportDir) {
|
||||
(void) clazz;
|
||||
const char *dir = (*env)->GetStringUTFChars(env, reportDir, NULL);
|
||||
if (!dir) {
|
||||
return;
|
||||
}
|
||||
strncpy(g_report_dir, dir, REPORT_DIR_MAX - 1);
|
||||
g_report_dir[REPORT_DIR_MAX - 1] = '\0';
|
||||
(*env)->ReleaseStringUTFChars(env, reportDir, dir);
|
||||
install_handlers();
|
||||
__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "native crash hook installed: %s", g_report_dir);
|
||||
}
|
||||
Reference in New Issue
Block a user