Skip to main content
Glama
crash-report.ts13.2 kB
/** * Crash Report Types * Structured types for iOS crash log parsing and symbolication */ import { Platform } from './constants.js'; /** * Single stack frame in a crash thread */ export interface StackFrame { /** Frame index (0 = crash point) */ index: number; /** Binary/library name */ binary: string; /** Memory address */ address: string; /** Symbol name (after symbolication, or raw address) */ symbol: string; /** Offset from symbol base */ offset?: number; /** Source file path (if symbolicated) */ file?: string; /** Line number (if symbolicated) */ line?: number; /** Whether this frame is from app code vs system */ isAppCode: boolean; } /** * Thread information from crash report */ export interface ThreadInfo { /** Thread index */ index: number; /** Thread name (if available) */ name?: string; /** Whether this thread crashed */ crashed: boolean; /** Stack frames for this thread */ frames: StackFrame[]; /** Thread state (if available) */ state?: string; } /** * Exception/signal information */ export interface CrashException { /** Exception type (e.g., "EXC_BAD_ACCESS", "SIGABRT") */ type: string; /** Exception code/subcode */ codes?: string; /** Signal number (if signal-based) */ signal?: string; /** Signal code */ signalCode?: string; /** Faulting address (for memory access crashes) */ faultAddress?: string; } /** * Binary image for symbolication */ export interface BinaryImage { /** Binary name */ name: string; /** Architecture (e.g., "arm64") */ arch: string; /** UUID for dSYM matching */ uuid: string; /** Load address */ loadAddress: string; /** End address */ endAddress?: string; /** Path to binary */ path: string; } /** * Detected crash pattern with suggested cause */ export interface CrashPattern { /** Pattern identifier */ id: string; /** Human-readable pattern name */ name: string; /** Severity level */ severity: 'critical' | 'high' | 'medium' | 'low'; /** Description of what this pattern indicates */ description: string; /** Likely root cause */ likelyCause: string; /** Suggested fix or investigation steps */ suggestion: string; /** Confidence score (0-1) */ confidence: number; /** Related stack frames that matched */ matchedFrames?: StackFrame[]; } /** * Complete crash report */ export interface CrashReport { /** Report identifier (from crash file) */ reportId?: string; /** Crash timestamp */ timestamp: Date; /** Target platform */ platform: Platform; /** Device model */ deviceModel?: string; /** OS version */ osVersion?: string; /** Process name */ processName: string; /** Bundle identifier */ bundleId?: string; /** App version */ appVersion?: string; /** Exception/signal information */ exception: CrashException; /** All threads in the crash */ threads: ThreadInfo[]; /** Crashed thread (convenience accessor) */ crashedThread: ThreadInfo; /** Binary images for symbolication */ binaryImages: BinaryImage[]; /** Whether the crash has been symbolicated */ isSymbolicated: boolean; /** Detected patterns (after analysis) */ patterns: CrashPattern[]; /** Raw crash log text (for reference) */ rawLog?: string; } /** * Crash analysis result from analyze_crash tool */ export interface CrashAnalysisResult { /** Whether analysis was successful */ success: boolean; /** Parsed crash report */ report?: CrashReport; /** AI-friendly summary of the crash */ summary: string; /** Detected patterns ordered by severity/confidence */ patterns: CrashPattern[]; /** Suggested next steps */ suggestions: string[]; /** Error if analysis failed */ error?: string; /** Analysis duration */ durationMs: number; } /** * Known crash patterns for iOS */ export const CRASH_PATTERNS: Array<{ id: string; name: string; severity: 'critical' | 'high' | 'medium' | 'low'; matcher: (report: CrashReport) => boolean; description: string; likelyCause: string; suggestion: string; }> = [ { id: 'exc_bad_access_null', name: 'Null Pointer Dereference', severity: 'critical', matcher: (r) => r.exception.type === 'EXC_BAD_ACCESS' && (r.exception.faultAddress === '0x0' || r.exception.faultAddress?.startsWith('0x0000') === true), description: 'Attempted to access memory at a null pointer address', likelyCause: 'Force-unwrapping nil optional or accessing deallocated object', suggestion: 'Check for optional binding before accessing. Use guard let or if let.', }, { id: 'exc_bad_access_kern_invalid', name: 'Invalid Memory Access', severity: 'critical', matcher: (r) => r.exception.type === 'EXC_BAD_ACCESS' && (r.exception.codes?.includes('KERN_INVALID_ADDRESS') ?? false), description: 'Attempted to access invalid memory region', likelyCause: 'Use-after-free, dangling pointer, or buffer overflow', suggestion: 'Enable Address Sanitizer in Xcode to catch memory issues at development time.', }, { id: 'sigabrt_assertion', name: 'Assertion Failure', severity: 'high', matcher: (r) => r.exception.type === 'SIGABRT' && r.crashedThread.frames.some((f) => f.symbol.includes('assert') || f.symbol.includes('fatalError') ), description: 'Application terminated due to assertion or fatalError', likelyCause: 'Precondition failed or explicit abort in code', suggestion: 'Check the assertion message in crash log for specific failure condition.', }, { id: 'sigabrt_uncaught_exception', name: 'Uncaught Exception', severity: 'high', matcher: (r) => r.exception.type === 'SIGABRT' && r.crashedThread.frames.some((f) => f.symbol.includes('objc_exception_throw') || f.symbol.includes('NSException') ), description: 'Uncaught Objective-C exception caused crash', likelyCause: 'NSException thrown but not caught (array bounds, invalid selector, etc.)', suggestion: 'Check Last Exception Backtrace in crash log for exception type and message.', }, { id: 'watchdog_timeout', name: 'Watchdog Timeout', severity: 'critical', matcher: (r) => r.exception.type === 'EXC_CRASH' && ((r.rawLog?.includes('8badf00d') ?? false) || (r.rawLog?.toLowerCase().includes('watchdog') ?? false)), description: 'App was terminated by iOS watchdog for taking too long', likelyCause: 'Main thread blocked for too long (network, heavy computation, deadlock)', suggestion: 'Move long-running operations to background threads. Use async/await.', }, { id: 'oom_jetsam', name: 'Out of Memory (Jetsam)', severity: 'high', matcher: (r) => r.exception.type === 'EXC_RESOURCE' || (r.rawLog?.includes('jetsam') ?? false) || (r.rawLog?.includes('EXC_RESOURCE') ?? false), description: 'App was terminated due to excessive memory usage', likelyCause: 'Memory leak, loading large assets, or insufficient memory management', suggestion: 'Profile with Instruments. Check for retain cycles and large allocations.', }, { id: 'sigbus_alignment', name: 'Bus Error (Alignment)', severity: 'critical', matcher: (r) => r.exception.type === 'SIGBUS', description: 'Memory alignment or hardware access error', likelyCause: 'Misaligned memory access or corrupted memory', suggestion: 'Check for pointer casting issues or corrupted data structures.', }, { id: 'stack_overflow', name: 'Stack Overflow', severity: 'high', matcher: (r) => { const crashedFrames = r.crashedThread.frames; if (crashedFrames.length < 50) return false; // Check for repeating function pattern const funcCounts = new Map<string, number>(); for (const f of crashedFrames) { funcCounts.set(f.symbol, (funcCounts.get(f.symbol) || 0) + 1); } return Array.from(funcCounts.values()).some((count) => count > 10); }, description: 'Stack exhausted due to deep or infinite recursion', likelyCause: 'Recursive function without proper base case', suggestion: 'Check for infinite recursion. Consider using iterative approach.', }, { id: 'swift_runtime_failure', name: 'Swift Runtime Error', severity: 'high', matcher: (r) => r.crashedThread.frames.some((f) => f.symbol.includes('swift_fatalError') || f.symbol.includes('swift_unexpectedError') || f.symbol.includes('_swift_stdlib_') ), description: 'Swift runtime detected an unrecoverable error', likelyCause: 'Force unwrap of nil, array index out of bounds, or precondition failure', suggestion: 'Look for force unwrap (!) or subscript access in the code path.', }, { id: 'dispatch_queue_crash', name: 'GCD/Dispatch Crash', severity: 'medium', matcher: (r) => r.crashedThread.frames.some((f) => f.symbol.includes('dispatch_') || f.binary.includes('libdispatch') ), description: 'Crash in Grand Central Dispatch', likelyCause: 'Thread safety issue, accessing UI from background, or dispatch_sync deadlock', suggestion: 'Ensure UI updates on main thread. Check for dispatch_sync from same queue.', }, ]; /** * Detect crash patterns from a crash report */ export function detectCrashPatterns(report: CrashReport): CrashPattern[] { const detected: CrashPattern[] = []; for (const pattern of CRASH_PATTERNS) { try { if (pattern.matcher(report)) { detected.push({ id: pattern.id, name: pattern.name, severity: pattern.severity, description: pattern.description, likelyCause: pattern.likelyCause, suggestion: pattern.suggestion, confidence: calculateConfidence(pattern, report), }); } } catch { // Pattern matcher failed, skip } } // Sort by severity then confidence const severityOrder = { critical: 0, high: 1, medium: 2, low: 3 }; detected.sort((a, b) => { const sevDiff = severityOrder[a.severity] - severityOrder[b.severity]; return sevDiff !== 0 ? sevDiff : b.confidence - a.confidence; }); return detected; } /** * Calculate confidence score for a pattern match */ function calculateConfidence( pattern: (typeof CRASH_PATTERNS)[0], report: CrashReport ): number { let confidence = 0.7; // Base confidence // Higher confidence if symbolicated if (report.isSymbolicated) { confidence += 0.1; } // Higher confidence for critical patterns with clear indicators if (pattern.severity === 'critical') { confidence += 0.1; } // Cap at 1.0 return Math.min(confidence, 1.0); } /** * Generate AI-friendly crash summary */ export function generateCrashSummary(report: CrashReport): string { const lines: string[] = []; lines.push(`## Crash Summary`); lines.push(``); lines.push(`**Process**: ${report.processName} (${report.bundleId || 'unknown'})`); lines.push(`**Exception**: ${report.exception.type}${report.exception.codes ? ` (${report.exception.codes})` : ''}`); lines.push(`**Device**: ${report.deviceModel || 'Unknown'} - ${report.osVersion || 'Unknown'}`); lines.push(`**Time**: ${report.timestamp.toISOString()}`); lines.push(``); // Crashed thread summary const crashed = report.crashedThread; lines.push(`### Crashed Thread (${crashed.index})`); lines.push(``); // Show top frames (first few app frames) const appFrames = crashed.frames.filter((f) => f.isAppCode).slice(0, 5); if (appFrames.length > 0) { lines.push(`**App Code:**`); for (const frame of appFrames) { const location = frame.file && frame.line ? ` (${frame.file}:${frame.line})` : ''; lines.push(` ${frame.index}: ${frame.symbol}${location}`); } lines.push(``); } // Show top system frames if no app frames if (appFrames.length === 0) { const topFrames = crashed.frames.slice(0, 5); lines.push(`**Stack:**`); for (const frame of topFrames) { lines.push(` ${frame.index}: ${frame.binary} - ${frame.symbol}`); } lines.push(``); } // Detected patterns if (report.patterns.length > 0) { lines.push(`### Detected Patterns`); lines.push(``); for (const pattern of report.patterns) { lines.push(`- **${pattern.name}** (${pattern.severity}): ${pattern.description}`); lines.push(` *Likely cause*: ${pattern.likelyCause}`); } lines.push(``); } return lines.join('\n'); } /** * Generate suggestions from crash patterns */ export function generateCrashSuggestions(patterns: CrashPattern[]): string[] { const suggestions: string[] = []; for (const pattern of patterns) { suggestions.push(pattern.suggestion); } // Add general suggestions if (patterns.length === 0) { suggestions.push('Enable symbolication to get detailed stack traces'); suggestions.push('Check application logs around crash time for context'); } if (patterns.some((p) => p.severity === 'critical')) { suggestions.push('This is a critical crash - prioritize investigation'); } return [...new Set(suggestions)]; // Deduplicate }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/abd3lraouf/specter-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server