Release Symbolication & De-obfuscation for KMP
When Kotlin Multiplatform applications are compiled for production release, code is minified, obfuscated, and stripped of debug symbols:
- Android: R8/ProGuard shrinks and obfuscates bytecode, renaming classes, fields, and methods to short non-descriptive tokens (e.g.
a.b.c()). - iOS (Kotlin/Native): The Kotlin compiler compiles shared Kotlin code into native Mach-O binaries (
ComposeApp.frameworkorshared.framework). Debug symbols are stripped into separate.dSYMbundles.
Without the matching symbol files (mapping.txt for Android and .dSYM bundles for iOS), stack traces captured in Appxiom cannot be resolved to original source files and line numbers.
Part 1: Android ProGuard / R8 De-obfuscation
Every Release Build Produces a Unique mapping.txt
If mapping.txt is not archived before running ./gradlew clean or building a new version, production crashes from that version can never be de-obfuscated.
Step 1: Ensure Minification & Line Numbers are Preserved
In composeApp/proguard-rules.pro:
-keepattributes SourceFile,LineNumberTable
-renamesourcefileattribute SourceFile
Step 2: Automated Gradle Backup Task
Add an automated task to your Android module's build.gradle.kts (e.g. composeApp/build.gradle.kts) to copy mapping.txt to a timestamped backup directory after every release build:
tasks.register<Copy>("backupReleaseMapping") {
val mappingDir = layout.buildDirectory.dir("outputs/mapping/release")
from(mappingDir)
into(rootProject.layout.projectDirectory.dir("symbol-backups/android"))
include("mapping.txt")
rename { "mapping-${android.defaultConfig.versionName ?: "release"}-${System.currentTimeMillis()}.txt" }
doLast {
println("Appxiom: Archived release mapping.txt successfully.")
}
}
tasks.named("assembleRelease") {
finalizedBy("backupReleaseMapping")
}
Step 3: De-obfuscate Using Android retrace CLI
To translate an obfuscated stack trace locally using the Android SDK's retrace tool:
# Syntax: retrace <mapping-file> <obfuscated-stack-trace>
$ANDROID_HOME/cmdline-tools/latest/bin/retrace mapping.txt obfuscated_stack.txt
Part 2: iOS Kotlin/Native Framework Symbolication
Step 1: Enable Kotlin/Native Debug Info in Release
In your shared module's build.gradle.kts (e.g. composeApp/build.gradle.kts), enable light debug symbols for native release binaries:
kotlin {
targets.withType<org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget> {
binaries.withType<org.jetbrains.kotlin.gradle.plugin.mpp.Framework> {
freeCompilerArgs += listOf("-Xadd-light-debug=enable")
}
}
}
Step 2: Configure Xcode Release Build Settings
In Xcode (iosApp.xcodeproj):
- Select your target → Build Settings.
- Debug Information Format: Set
Releaseto DWARF with dSYM File (DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"). - Strip Debug Symbols During Copy: Set
Releaseto YES. - Strip Linked Product: Set
Releaseto YES.
Step 3: Archive & Locate .dSYM Bundles
When you create an Xcode Archive (Product → Archive):
- Open Xcode Organizer (Window → Organizer).
- Right-click the archive → Show in Finder.
- Right-click the
.xcarchive→ Show Package Contents. - Navigate to the
dSYMs/folder:ComposeApp.framework.dSYM(Shared Kotlin/Native code)iosApp.app.dSYM(Native Swift/UIKit code)
- Copy the
.dSYMfolders into your project's permanentsymbol-backups/ios/directory.
Step 4: Verify Slice UUID with dwarfdump
Check the UUID of your archived .dSYM:
dwarfdump --uuid symbol-backups/ios/ComposeApp.framework.dSYM/Contents/Resources/DWARF/ComposeApp
Verify that the output UUID matches the Binary Images UUID reported in the Appxiom crash occurrence.
Step 5: Symbolicate Memory Addresses with atos
Translate raw memory addresses back to Kotlin/Native source files and lines:
# Syntax: atos -o <dwarf-binary> -arch arm64 -l <load-address> <crash-address>
atos -o ComposeApp.framework.dSYM/Contents/Resources/DWARF/ComposeApp \
-arch arm64 \
-l 0x104500000 0x104523a10
Output:
kfun:tech.appxiom.kmp.example.CheckoutViewModel.submitPayment(kotlin.String) (CheckoutViewModel.kt:42)
Next Steps
Connect your AI coding assistants to the Appxiom diagnostic engine with MCP Server Integration.