Skip to content
Open
2 changes: 1 addition & 1 deletion apps/cli-docs/src/content/docs/contributing.md
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ cli/
│ │ ├── code-mappings/# upload
│ │ ├── dart-symbol-map/# upload
│ │ ├── dashboard/ # add, create, delete, edit, list, restore, revisions, view
│ │ ├── debug-files/ # bundle-jvm, bundle-sources, check, find, print-sources, upload
│ │ ├── debug-files/ # bundle-jvm, bundle-sources, check, find, prepare, print-sources, upload
│ │ ├── docs/ # list, query
│ │ ├── event/ # list, send, view
│ │ ├── feedback/ # list, view
Expand Down
35 changes: 35 additions & 0 deletions apps/cli-docs/src/fragments/commands/debug-files.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,8 +49,43 @@ sentry debug-files upload ./build --il2cpp-mapping --include-sources

# Preview what would be uploaded without uploading (no credentials needed)
sentry debug-files upload ./build --no-upload

# Split WebAssembly debug info and upload it (scans directories recursively)
sentry debug-files prepare ./dist

# Preview the split without writing or uploading anything
sentry debug-files prepare ./dist --dry-run

# Split only, keeping the companions local
sentry debug-files prepare ./dist --no-upload

# Write companions elsewhere; modules are still stripped in place
sentry debug-files prepare ./dist --out-dir ./symbols

# Fail the build if any module was compiled without DWARF
sentry debug-files prepare ./dist --require-dwarf
```

## Notes on `prepare`

- For each module carrying inline DWARF it injects a `build_id` (if absent),
writes a `*.debug.wasm` companion retaining the Code section and DWARF,
strips the `.debug_*` sections from the deployable module **in place**, and
points it at the companion via `external_debug_info`. Your build artifact
keeps its path; only the companion is new.
- The companion must keep the Code section — DWARF addresses are relative to it,
so a companion without it cannot be symbolicated.
- Modules without DWARF are still stamped with a `build_id` and reported with a
warning rather than failing the run. Sentry matches a frame to its debug file
by `build_id`, so stamping now keeps symbolication possible later.
- Name/symtab-only modules are not uploaded: the `name` section stays in the
deployable module and runtimes read function names from it directly, so a
debug file built from one adds nothing to the stack trace.
- The command is idempotent.
- `--require-dwarf` exits non-zero when any scanned module lacks DWARF, which is
the flag to use in CI. A module whose `external_debug_info` names a companion
that cannot be found fails the gate too, since its debug info is unreachable.

## Notes on `find`

- `debug-files find` locates debug files **locally** by debug identifier — it
Expand Down
1 change: 1 addition & 0 deletions packages/cli/plugins/sentry-cli/skills/sentry-cli/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,7 @@ Work with debug information files

- `sentry debug-files check <path>` — Inspect a debug information file
- `sentry debug-files find <id...>` — Locate debug files for given debug identifiers
- `sentry debug-files prepare <path...>` — Split WebAssembly debug info and upload it to Sentry
- `sentry debug-files upload <path...>` — Upload debug information files to Sentry
- `sentry debug-files print-sources <path>` — List the source files a debug file references
- `sentry debug-files bundle-sources <path>` — Bundle a debug file's source files for source context
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,23 @@ Locate debug files for given debug identifiers
- `--no-cwd - Do not look for debug files in the current directory`
- `-p, --path <value>... - Add a directory to search recursively (repeatable)`

### `sentry debug-files prepare <path...>`

Split WebAssembly debug info and upload it to Sentry

**Flags:**
- `--dry-run - Classify modules without writing or uploading anything`
- `--no-upload - Split modules but do not upload the companions`
- `--require-dwarf - Fail if any scanned module lacks DWARF debug info`
- `--out-dir <value> - Directory for *.debug.wasm companions (modules are stripped in place)`
- `--strip-names - Also drop the name section from split modules (companion keeps it)`
- `--build-id <value> - Use this UUID as the build id instead of a random one (one .wasm file only)`
- `--include-sources - Also upload a source bundle for each companion`
- `--ignore <value>... - Skip files and folders matching this glob (repeatable)`
- `--ignore-file <value> - Skip files and folders listed in this ignore file`
- `--wait - Wait for server-side processing and report any errors`
- `--wait-for <value> - Wait up to this many seconds for server-side processing`

### `sentry debug-files upload <path...>`

Upload debug information files to Sentry
Expand Down Expand Up @@ -112,6 +129,21 @@ sentry debug-files upload ./build --il2cpp-mapping --include-sources

# Preview what would be uploaded without uploading (no credentials needed)
sentry debug-files upload ./build --no-upload

# Split WebAssembly debug info and upload it (scans directories recursively)
sentry debug-files prepare ./dist

# Preview the split without writing or uploading anything
sentry debug-files prepare ./dist --dry-run

# Split only, keeping the companions local
sentry debug-files prepare ./dist --no-upload

# Write companions elsewhere; modules are still stripped in place
sentry debug-files prepare ./dist --out-dir ./symbols

# Fail the build if any module was compiled without DWARF
sentry debug-files prepare ./dist --require-dwarf
```

All commands also support `--json`, `--fields`, `--help`, `--log-level`, and `--verbose` flags.
15 changes: 2 additions & 13 deletions packages/cli/src/commands/debug-files/bundle-sources.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
* bundled `symbolic` WASM module (see `src/lib/dif/`).
*/

import { readFileSync } from "node:fs";
import { mkdir, writeFile } from "node:fs/promises";
import { basename, dirname, resolve } from "node:path";
import type { SentryContext } from "../../context.js";
Expand All @@ -28,7 +27,7 @@ import {
} from "../../lib/formatters/markdown.js";
import { CommandOutput } from "../../lib/formatters/output.js";
import { logger } from "../../lib/logger.js";
import { readDebugFile } from "./read-file.js";
import { readDebugFile, readSourceFile } from "./read-file.js";

const log = logger.withTag("debug-files.bundle-sources");

Expand Down Expand Up @@ -119,17 +118,7 @@ export const bundleSourcesCommand = buildCommand({
result = createSourceBundle(
new Uint8Array(content),
basename(path),
(sourcePath) => {
try {
return readFileSync(sourcePath);
} catch (err) {
log.debug(
`Source file not available, skipping: ${sourcePath}`,
err
);
return null;
}
}
readSourceFile
);
} catch (err) {
const msg = err instanceof Error ? err.message : String(err);
Expand Down
2 changes: 2 additions & 0 deletions packages/cli/src/commands/debug-files/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,15 @@ import { bundleJvmCommand } from "./bundle-jvm.js";
import { bundleSourcesCommand } from "./bundle-sources.js";
import { checkCommand } from "./check.js";
import { findCommand } from "./find.js";
import { prepareCommand } from "./prepare.js";
import { printSourcesCommand } from "./print-sources.js";
import { uploadCommand } from "./upload.js";

export const debugFilesRoute = buildRouteMap({
routes: {
check: checkCommand,
find: findCommand,
prepare: prepareCommand,
upload: uploadCommand,
"print-sources": printSourcesCommand,
"bundle-sources": bundleSourcesCommand,
Expand Down
Loading
Loading