KSCrashType kscrashsentry_installWithContext(KSCrash_SentryContext* context, KSCrashType crashTypes, void (*onCrash)(void)) { KSLOG_DEBUG("Installing handlers with context %p, crash types 0x%x.", context, crashTypes); g_context = context; kscrashsentry_clearContext(g_context); g_context->onCrash = onCrash; KSCrashType installed = 0; for(size_t i = 0; i < g_sentriesCount; i++) { CrashSentry* sentry = &g_sentries[i]; if(sentry->crashType & crashTypes) { if(sentry->install == NULL || sentry->install(context)) { installed |= sentry->crashType; } } } KSLOG_DEBUG("Installation complete. Installed types 0x%x.", installed); return installed; }
void kscrashsentry_reportUserException(const char* name, const char* reason, const char* language, const char* lineOfCode, const char* stackTrace, bool terminateProgram) { if(g_context == NULL) { KSLOG_WARN("User-reported exception sentry is not installed. Exception has not been recorded."); } else { kscrashsentry_beginHandlingCrash(g_context); KSLOG_DEBUG("Suspending all threads"); kscrashsentry_suspendThreads(); KSLOG_DEBUG("Fetching call stack."); int callstackCount = 100; uintptr_t callstack[callstackCount]; callstackCount = backtrace((void**)callstack, callstackCount); if(callstackCount <= 0) { KSLOG_ERROR("backtrace() returned call stack length of %d", callstackCount); callstackCount = 0; } KSLOG_DEBUG("Filling out context."); g_context->crashType = KSCrashTypeUserReported; g_context->offendingThread = ksmach_thread_self(); g_context->registersAreValid = false; g_context->crashReason = reason; g_context->stackTrace = callstack; g_context->stackTraceLength = callstackCount; g_context->userException.name = name; g_context->userException.language = language; g_context->userException.lineOfCode = lineOfCode; g_context->userException.customStackTrace = stackTrace; KSLOG_DEBUG("Calling main crash handler."); g_context->onCrash(); if(terminateProgram) { kscrashsentry_uninstall(KSCrashTypeAll); kscrashsentry_resumeThreads(); abort(); } else { kscrashsentry_clearContext(g_context); kscrashsentry_resumeThreads(); } } }
void kscrashsentry_beginHandlingCrash(KSCrash_SentryContext* context) { kscrashsentry_clearContext(context); context->handlingCrash = true; }