Skip to content

Commit

Permalink
Only enable Safe Mode after two consecutive crashes; added stack trac…
Browse files Browse the repository at this point in the history
…e dumper
  • Loading branch information
zhuowei committed Jan 6, 2015
1 parent 2eee0aa commit 954a753
Show file tree
Hide file tree
Showing 12 changed files with 345 additions and 21 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "jni/libcorkscrew"]
path = jni/libcorkscrew
url = https://github.com/zhuowei/libcorkscrew-ndk.git
38 changes: 37 additions & 1 deletion jni/Android.mk
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,48 @@ LOCAL_PATH := $(call my-dir)
include $(CLEAR_VARS)
LOCAL_LDLIBS := -llog
LOCAL_MODULE := mcpelauncher

#corkscrew
corkscrew_generic_src_files := \
libcorkscrew/backtrace.c \
libcorkscrew/backtrace-helper.c \
libcorkscrew/demangle.c \
libcorkscrew/map_info.c \
libcorkscrew/ptrace.c \
libcorkscrew/symbol_table.c

corkscrew_arm_src_files := \
libcorkscrew/arch-arm/backtrace-arm.c \
libcorkscrew/arch-arm/ptrace-arm.c

corkscrew_x86_src_files := \
libcorkscrew/arch-x86/backtrace-x86.c \
libcorkscrew/arch-x86/ptrace-x86.c

LOCAL_SRC_FILES := nativepatch.c modscript.c modscript_nextgen.cpp modscript_ScriptLevelListener.cpp utf8proc_slim.c dobby.cpp marauders_map.c \
modscript_renderer.cpp simpleuuid.c
modscript_renderer.cpp simpleuuid.c signalhandler.cpp $(corkscrew_generic_src_files)

ifneq (,$(wildcard $(LOCAL_PATH)/scriptscramble.c))
LOCAL_SRC_FILES += scriptscramble.c
endif
ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
LOCAL_SRC_FILES += signalhandler_arm.cpp
else
LOCAL_SRC_FILES += signalhandler_x86.cpp
endif

ifeq ($(TARGET_ARCH_ABI),armeabi-v7a)
LOCAL_SRC_FILES += $(corkscrew_arm_src_files)
LOCAL_CFLAGS += -DCORKSCREW_HAVE_ARCH
endif

ifeq ($(TARGET_ARCH_ABI),x86)
LOCAL_SRC_FILES += $(corkscrew_x86_src_files)
LOCAL_CFLAGS += -DCORKSCREW_HAVE_ARCH
endif


LOCAL_C_INCLUDES += $(LOCAL_PATH)/libcorkscrew

LOCAL_SHARED_LIBRARIES := tinysubstrate-bin

Expand Down
1 change: 1 addition & 0 deletions jni/libcorkscrew
Submodule libcorkscrew added at ed4ab1
6 changes: 5 additions & 1 deletion jni/modscript.c
Original file line number Diff line number Diff line change
Expand Up @@ -1112,10 +1112,14 @@ void bl_dumpVtable(void** vtable, size_t size) {
}
}

extern void bl_signalhandler_init();

JNIEXPORT void JNICALL Java_net_zhuoweizhang_mcpelauncher_ScriptManager_nativeSetupHooks
(JNIEnv *env, jclass clazz, jint versionCode) {
if (bl_hasinit_script) return;

bl_signalhandler_init();

dlerror();

if (!mcpelibhandle) {
Expand Down Expand Up @@ -1222,7 +1226,7 @@ JNIEXPORT void JNICALL Java_net_zhuoweizhang_mcpelauncher_ScriptManager_nativeSe

//replace the getTexture method for zombie pigmen
void** pigZombieVtable = (void**) dobby_dlsym(mcpelibhandle, "_ZTV9PigZombie");
pigZombieVtable[MOB_VTABLE_OFFSET_GET_TEXTURE] = (void*) bl_Mob_getTexture;
//pigZombieVtable[MOB_VTABLE_OFFSET_GET_TEXTURE] = (void*) bl_Mob_getTexture;

bl_AgebleMob_setAge = dlsym(RTLD_DEFAULT, "_ZN9AgableMob6setAgeEi");
bl_Minecraft_setIsCreativeMode = dlsym(RTLD_DEFAULT, "_ZN9Minecraft17setIsCreativeModeEb");
Expand Down
5 changes: 5 additions & 0 deletions jni/modscript_nextgen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1569,6 +1569,11 @@ JNIEXPORT jstring JNICALL Java_net_zhuoweizhang_mcpelauncher_ScriptManager_nativ
return retval;
}

JNIEXPORT jstring JNICALL Java_net_zhuoweizhang_mcpelauncher_ScriptManager_nativeForceCrash
(JNIEnv *env, jclass clazz) {
*((int*) 0xdeadfa11) = 0xd15ea5e;
};

static void generateBl(uint16_t* buffer, uintptr_t curpc, uintptr_t newpc) {
unsigned int diff = newpc - curpc;
unsigned int shiftdiff = (diff >> 1);
Expand Down
230 changes: 230 additions & 0 deletions jni/signalhandler.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,230 @@
/*
* Copyright (C) 2008 The Android Open Source Project
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/

#include <errno.h>
#include <inttypes.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/mman.h>
#include <sys/prctl.h>
#include <sys/un.h>
#include <unistd.h>

#include <time.h>
#include "signalhandler_machine.h"

struct sigaction orig_sig_handler[32];

#define DO_BACKTRACE

#ifdef DO_BACKTRACE
// from debuggerd/backtrace.cpp

#include <corkscrew/backtrace.h>

#define STACK_DEPTH 32

extern "C" ssize_t unwind_backtrace_signal(siginfo_t* siginfo, void* sigcontext, backtrace_frame_t* backtrace, size_t ignore_depth, size_t max_depth);

static void dump_thread(FILE* file, pid_t tid, siginfo_t* info, ucontext_t* context) {
backtrace_frame_t backtrace[STACK_DEPTH];
ssize_t frames = unwind_backtrace_signal(info, context, backtrace, 0, STACK_DEPTH);
if (frames <= 0) {
fprintf(file, "Could not obtain stack trace for thread.\n");
} else {
backtrace_symbol_t backtrace_symbols[STACK_DEPTH];
get_backtrace_symbols(backtrace, frames, backtrace_symbols);
for (size_t i = 0; i < (size_t)frames; i++) {
char line[MAX_BACKTRACE_LINE_LENGTH];
format_backtrace_line(i, &backtrace[i], &backtrace_symbols[i],
line, MAX_BACKTRACE_LINE_LENGTH);
fprintf(file, " %s\n", line);
}
free_backtrace_symbols(backtrace_symbols, frames);
}

}
#endif


// From linker/debugger.cpp

#define MAX_TASK_NAME_LEN (16)

/*
* Writes a summary of the signal to the log file. We do this so that, if
* for some reason we're not able to contact debuggerd, there is still some
* indication of the failure in the log.
*
* We could be here as a result of native heap corruption, or while a
* mutex is being held, so we don't want to use any libc functions that
* could allocate memory or hold a lock.
*/

// not anymore, lol
static void log_signal_summary(int signum, const siginfo_t* info, FILE* file) {
const char* signal_name = "???";
bool has_address = false;
switch (signum) {
case SIGABRT:
signal_name = "SIGABRT";
break;
case SIGBUS:
signal_name = "SIGBUS";
has_address = true;
break;
case SIGFPE:
signal_name = "SIGFPE";
has_address = true;
break;
case SIGILL:
signal_name = "SIGILL";
has_address = true;
break;
case SIGPIPE:
signal_name = "SIGPIPE";
break;
case SIGSEGV:
signal_name = "SIGSEGV";
has_address = true;
break;
#if defined(SIGSTKFLT)
case SIGSTKFLT:
signal_name = "SIGSTKFLT";
break;
#endif
case SIGTRAP:
signal_name = "SIGTRAP";
break;
}

char thread_name[MAX_TASK_NAME_LEN + 1]; // one more for termination
if (prctl(PR_GET_NAME, (unsigned long)thread_name, 0, 0, 0) != 0) {
strcpy(thread_name, "<name unknown>");
} else {
// short names are null terminated by prctl, but the man page
// implies that 16 byte names are not.
thread_name[MAX_TASK_NAME_LEN] = 0;
}

// "info" will be null if the siginfo_t information was not available.
// Many signals don't have an address or a code.
char code_desc[32]; // ", code -6"
char addr_desc[32]; // ", fault addr 0x1234"
addr_desc[0] = code_desc[0] = 0;
if (info != nullptr) {
// For a rethrown signal, this si_code will be right and the one debuggerd shows will
// always be SI_TKILL.
snprintf(code_desc, sizeof(code_desc), ", code %d", info->si_code);
if (has_address) {
snprintf(addr_desc, sizeof(addr_desc), ", fault addr %p", info->si_addr);
}
}
fprintf(file,
"Fatal signal %d (%s)%s%s in tid %d (%s)",
signum, signal_name, code_desc, addr_desc, gettid(), thread_name);
}

/*
* Returns true if the handler for signal "signum" has SA_SIGINFO set.
*/
static bool have_siginfo(int signum) {
struct sigaction old_action, new_action;

memset(&new_action, 0, sizeof(new_action));
new_action.sa_handler = SIG_DFL;
new_action.sa_flags = SA_RESTART;
sigemptyset(&new_action.sa_mask);

if (sigaction(signum, &new_action, &old_action) < 0) {
//__libc_format_log(ANDROID_LOG_WARN, "libc", "Failed testing for SA_SIGINFO: %s",
// strerror(errno));
return false;
}
bool result = (old_action.sa_flags & SA_SIGINFO) != 0;

if (sigaction(signum, &old_action, nullptr) == -1) {
//__libc_format_log(ANDROID_LOG_WARN, "libc", "Restore failed in test for SA_SIGINFO: %s",
// strerror(errno));
}
return result;
}

/*
* Catches fatal signals so we can ask debuggerd to ptrace us before
* we crash.
*/
static void debuggerd_signal_handler(int signal_number, siginfo_t* info, void* context) {
// It's possible somebody cleared the SA_SIGINFO flag, which would mean
// our "info" arg holds an undefined value.
if (!have_siginfo(signal_number)) {
info = nullptr;
}

signal(signal_number, SIG_DFL);

char filepath[1000];
snprintf(filepath, sizeof(filepath), "/sdcard/blocklauncher_crash_%ld.txt", time(NULL));

FILE* file = fopen(filepath, "w");

log_signal_summary(signal_number, info, file);
fprintf(file, "\n");
dump_registers(file, (ucontext_t*) context);
#ifdef DO_BACKTRACE
dump_thread(file, gettid(), info, (ucontext_t*) context);
#endif

fclose(file);

// call through to the next signal handler
orig_sig_handler[signal_number].sa_sigaction(signal_number, info, context);
}

extern "C" void bl_signalhandler_init() {
struct sigaction action;
memset(&action, 0, sizeof(action));
sigemptyset(&action.sa_mask);
action.sa_sigaction = debuggerd_signal_handler;
action.sa_flags = SA_RESTART | SA_SIGINFO;

// Use the alternate signal stack if available so we can catch stack overflows.
action.sa_flags |= SA_ONSTACK;

sigaction(SIGABRT, &action, &orig_sig_handler[SIGABRT]);
sigaction(SIGBUS, &action, &orig_sig_handler[SIGBUS]);
sigaction(SIGFPE, &action, &orig_sig_handler[SIGFPE]);
sigaction(SIGILL, &action, &orig_sig_handler[SIGILL]);
sigaction(SIGPIPE, &action, &orig_sig_handler[SIGPIPE]);
sigaction(SIGSEGV, &action, &orig_sig_handler[SIGSEGV]);
#if defined(SIGSTKFLT)
sigaction(SIGSTKFLT, &action, &orig_sig_handler[SIGSTKFLT]);
#endif
sigaction(SIGTRAP, &action, &orig_sig_handler[SIGTRAP]);
}
18 changes: 18 additions & 0 deletions jni/signalhandler_arm.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
#include "signalhandler_machine.h"
void dump_registers(FILE* file, ucontext_t* context) {
mcontext_t* m = &context->uc_mcontext;

fprintf(file, " r0 %08x r1 %08x r2 %08x r3 %08x\n",
static_cast<uint32_t>(m->arm_r0), static_cast<uint32_t>(m->arm_r1),
static_cast<uint32_t>(m->arm_r2), static_cast<uint32_t>(m->arm_r3));
fprintf(file, " r4 %08x r5 %08x r6 %08x r7 %08x\n",
static_cast<uint32_t>(m->arm_r4), static_cast<uint32_t>(m->arm_r5),
static_cast<uint32_t>(m->arm_r6), static_cast<uint32_t>(m->arm_r7));
fprintf(file, " r8 %08x r9 %08x sl %08x fp %08x\n",
static_cast<uint32_t>(m->arm_r8), static_cast<uint32_t>(m->arm_r9),
static_cast<uint32_t>(m->arm_r10), static_cast<uint32_t>(m->arm_fp));
fprintf(file, " ip %08x sp %08x lr %08x pc %08x cpsr %08x\n",
static_cast<uint32_t>(m->arm_ip), static_cast<uint32_t>(m->arm_sp),
static_cast<uint32_t>(m->arm_lr), static_cast<uint32_t>(m->arm_pc),
static_cast<uint32_t>(m->arm_cpsr));
}
3 changes: 3 additions & 0 deletions jni/signalhandler_machine.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#include <cstdio>
#include <signal.h>
void dump_registers(FILE* log, ucontext_t* context);
3 changes: 3 additions & 0 deletions jni/signalhandler_x86.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
#include "signalhandler_machine.h"
void dump_registers(FILE* log, ucontext_t* context) {
}
Loading

0 comments on commit 954a753

Please sign in to comment.