Skip to main content

Debug Symbols and Obfuscation

By default, the tk-ota-push CLI compiles all Releases and Patches with Dart obfuscation enabled (--obfuscate) and generates split DWARF symbol tables (--split-debug-info). These .symbols files are automatically uploaded and sealed per architecture inside the OTA server's Artifact signing engine so you can deobfuscate production crash stack traces at any time using tk-ota-push symbols.

1. Automatic Generation and Archiving During Builds (release & patch)​

Option / FlagDefaultBehavior in Publisher
--obfuscatetruePasses --obfuscate and --split-debug-info=<symDir> to flutter build.
--no-obfuscate—Disables obfuscation (unless --split-debug-info is explicitly provided).
--split-debug-info <dir>build/ota_symbols/<version>Customizes the local directory where Flutter writes .symbols files.

Per-Platform and Per-Architecture Resolution (Publisher.resolveSymbolsFile)​

Inside build/ota_symbols/<version> (or the custom --split-debug-info directory), the CLI searches in order for:

  • Android 64-bit (aarch64): app.android-arm64.symbols
  • Android 32-bit (arm): app.android-arm.symbols
  • iOS (aarch64): app.ios-arm64.symbols
  • Generic pattern: app.<platform>-<arch>.symbols (falling back to the first *.symbols file found).

iOS Linker Specifics (patchIos)​

When building an iOS patch, flutter build ios --release --no-codesign produces the app.dill kernel, and then gen_snapshot_arm64 and aot-tools.dill link assemble the final snapshot. When obfuscation is active, the CLI explicitly passes the following 4 DWARF flags to both gen_snapshot_arm64 and aot_tools link (after --):

--dwarf-stack-traces
--resolve-dwarf-paths
--save-debugging-info=<symDir>/patch_<version>.symbols
--strip

This guarantees that the patch artifact snapshot and the base binary share identical DWARF stack conventions and prevents dwarf_stack_traces vs no-dwarf_stack_traces linker errors.

Multipart Upload to the Server​

In OtaApiClient._multipart, if symbolsFile exists on disk, it is attached under the symbols_file multipart field during POST /api/admin/v1/releases and POST /api/admin/v1/patches. The server computes its symbolsSha256Hash digest and prints it in the CLI receipt:

  │ Symboles (.symbols) : Archivés (app.android-arm64.symbols • SHA-256 : 998877665544...)

2. Downloading Patch Symbols (tk-ota-push symbols)​

When an obfuscated stack trace is reported from a production device, run the symbols subcommand to download the exact .symbols file bound to the patch UUID:

tk-ota-push symbols --patch-id <uuid> [-o <output_path>] [options]

tk-ota-push symbols Options​

OptionAbbr.MandatoryDefaultDescription
--patch-id—Yes—UUID of the patch whose .symbols file should be downloaded.
--output-oNopatch_<patchId>.symbolsLocal destination path for the downloaded .symbols file.
--tenant-id—Noshorebird.yaml / session / defaultTenant identifier.
--server—Noshorebird.yaml / env / http://localhost:8080OTA server URL.
--project—No.Flutter project path (to read shorebird.yaml).

Complete Local Deobfuscation Example (flutter symbolize)​

# 1. Download the patch .symbols file
tk-ota-push symbols \
--patch-id 8b73f831-29cf-4cb6-8801-44ebda29910a \
-o build/crash_triage/patch_1.symbols

CLI output:

Téléchargement du fichier .symbols pour le patch 8b73f831-29cf-4cb6-8801-44ebda29910a...

✅ Fichier .symbols enregistré dans : build/crash_triage/patch_1.symbols (418204 octets)
Pour dé-obfusquer une stacktrace : flutter symbolize -i crash.txt -d build/crash_triage/patch_1.symbols
# 2. Deobfuscate the stack trace using the standard Flutter tool
flutter symbolize -i crash.txt -d build/crash_triage/patch_1.symbols

3. Downloading Release Symbols or Server-Side Deobfuscation​

In addition to tk-ota-push symbols, OtaApiClient and OtaAdminController expose two additional endpoints:

  • Download the base .symbols of a Release (OtaApiClient.downloadReleaseSymbols):
    curl -L "$OTA_SERVER_URL/api/admin/v1/releases/$RELEASE_ID/symbols" \
    -H "Authorization: Bearer $OTA_API_KEY" \
    -o release_base.symbols
  • Deobfuscate a stack trace directly via the REST API:
    curl -X POST "$OTA_SERVER_URL/api/admin/v1/patches/$PATCH_ID/deobfuscate" \
    -H "Authorization: Bearer $OTA_API_KEY" \
    --data-urlencode "stacktrace@crash.txt"