Build and Check a dSYM with LLVM 20 dsymutil

This guide uses LLVM's dsymutil to link a program's debug map into a dSYM bundle and verify it without touching the executable. By the end, you will have inspected the debug map, linked the DWARF into a separate bundle, and checked the result. The examples use Ubuntu's llvm-20 package, version 20.1.8 on the system used for this guide.

Allow about 15 minutes if you already have a valid Mach-O executable and its matching object files. You need dsymutil-20 from llvm-20, a readable executable, and the object files or paths recorded in its debug map. You do not need root privileges. A dSYM is debug information for a Darwin or other Mach-O build; installing this Linux package does not make an ordinary Linux ELF executable a valid input.

1. Check the installed tool

Start by checking the exact binary and version. The version matters when a build or a crash-reporting service expects a particular LLVM toolchain.

command -v dsymutil-20
dsymutil-20 --version

On the reference system, the second command begins with:

Ubuntu LLVM version 20.1.8

Checkpoint: Continue only if the command exists and the reported version is the toolchain you intend to use. dsymutil-20 --help prints the complete option list without reading an executable.

2. Confirm the input and its debug map

Set APP to the path of the valid Mach-O executable produced by your build. Keep the value quoted: build directories and product names often contain spaces.

APP='/path/to/MyApp'
file "$APP"
dsymutil-20 --dump-debug-map "$APP"

The dump is YAML describing the object files that contribute debug information. This mode exits after printing the map, so it does not link a dSYM. It is a useful first failure boundary: a missing object path, a stale build, or an input from the wrong architecture must be fixed in the build artefacts rather than hidden with a different output option.

Checkpoint: Save the map output in your build log if you need to diagnose reproducibility. A normal successful command returns exit status 0. This Ubuntu build rejects an ELF executable with an error such as cannot parse the debug map; that is expected for an ordinary Linux binary, not evidence that its DWARF is corrupt.

3. Link the dSYM into a new path

Run the link with an explicit output path. Without -o, dsymutil appends .dSYM to the executable name. An explicit destination makes it harder to confuse a newly generated bundle with an older one.

OUT='/tmp/MyApp-llvm20.dSYM'
dsymutil-20 --out "$OUT" "$APP"
printf 'exit status: %s
' "$?"
find "$OUT" -maxdepth 4 -type f -print

A successful run returns 0 and creates a bundle containing the linked DWARF file. The exact file name and bundle layout depend on the input product. A non-zero result means linking failed; the manpage documents 1 as the failure status. Common causes are missing object files, a timestamp mismatch, or asking for an architecture that cannot be linked.

Do not point -o at an existing release bundle while investigating. Keep the generated bundle as evidence until you have checked it. If this test bundle is disposable, remove only the exact directory you created, after checking the variable:

printf 'will remove: %s
' "$OUT"
rm -r -- "$OUT"

This is destructive and needs no elevated privilege. Never substitute a broad directory or an unreviewed variable for the explicit dSYM path.

4. Check the linked DWARF

Add --verify when creating the bundle to ask dsymutil to run its DWARF verifier on the linked information. It is also sensible to inspect the output with the LLVM DWARF tool installed alongside LLVM 20.

CHECKED='/tmp/MyApp-llvm20-checked.dSYM'
dsymutil-20 --verify --out "$CHECKED" "$APP"
llvm-dwarfdump-20 --verify "$CHECKED/Contents/Resources/DWARF/MyApp"

Replace MyApp in the second command with the actual DWARF file name shown by find. A clean check completes without an error and both commands return 0. If the path differs, do not guess: list the bundle again and use its actual file.

Useful diagnostics without writing output

Use the symbol-table mode when you want to inspect symbols and do not need a dSYM:

dsymutil-20 --symtab "$APP"

Use --no-output for a link performed in memory. It is useful in a build check because it avoids emitting a result file, but it still needs a valid input and accessible object files:

dsymutil-20 --no-output --verify "$APP"
echo "exit status: $?"

For a multi-architecture product, link only named architectures with repeated --arch options. The tool otherwise attempts all architectures and reports an error if one cannot be linked. Limit parallel work with --num-threads or -j when a large build is competing for CPU or memory.

Done means