Debug Identifiers

Each debug information file specifies a unique identifier. Crash reports declare these identifiers to allow debuggers and crash reporting systems to resolve the correct files. Sentry distinguishes two kinds of identifiers:

  • Code Identifier: The unique identifier of the executable or dynamic library -- the code file. The contents of this identifier are platform-dependent: Mach-O files use a UUID, ELF files a SHA hash, PE files use a concatenation of certain header attributes. For WebAssembly we use an embedded UUID in the build_id section of the file.

  • Debug Identifier: The unique identifier of the debug companion file. In contrast to the code identifier, Sentry enforces the same structure on all platforms. On Windows, this is the actual unique id of the PDB file; on all other platforms this is a lossy transformation of the code identifier.

When uploading debug information files to Sentry, the CLI and server will always compute a Debug Identifier for each uploaded file. This identifier is associated with executables and libraries as well as debug companions to ensure that they can be uniquely located via one common mechanism.

For native events, the issue details page displays a list of Loaded Images. This list contains the executable and all loaded dynamic libraries including their debug identifiers. You can copy this identifier and search for the exact files that match it in the Debug Files settings screen.

sentry-cli can help to print properties of debug information files like their debug identifier. See Checking Debug Information Files for more information.

For ELF files on Linux, Sentry uses the GNU build identifier to compute the debug identifier. All recent compilers and linkers support the emission of build IDs, but sometimes they might require additional configuration. gcc does this by default, for clang use one of the following flags:

  • --build-id=uuid for a fast but non-reproducible random identifier.
  • --build-id=sha1 for a slower but reproducible identifier generated by hashing the first page of the code section.

The identifier needs to be present and identical in the binary as well as stripped debug information files. If the ID is missing for some reason, upload the files before stripping so that sentry-cli can compute a stable identifier from the unstripped file.

Microsoft PDBs compose their identifiers from two parts: A unique signature and an age field. The signature is generated when the PDB is written initially and usually changes with every build. The age is a counter that is incremented every time the PDB is modified.

PE files, such as executables and dynamic libraries, specify the full identifier of the corresponding PDB in their header. This includes the age. If the PDB is modified after the PE has been generated, however, its age might diverge. This can lead to different identifiers:

Copied
PE:  3003763b-afcb-4a97-aae3-28de8f188d7c-2
PDB: 3003763b-afcb-4a97-aae3-28de8f188d7c-4

sentry-cli can detect these differences during the upload process and associates the same identifier to both files. However, this requires that both files are uploaded in the same invocation of the upload command. Otherwise, the identifiers diverge and Sentry might not be able to resolve the correct file for symbolication.

WebAssembly does not yet support build IDs. The option proposed to implement build IDs for WebAssembly (Build ID Section for WASM) has not yet found widespread adoption. Instead, we use a custom extension to WebAssembly.

Our recommendation is to embed a UUID in the build_id custom section as raw binary. Our wasm-split tool can do this for you automatically.

Unlike other debug information files, ProGuard files do not have an intrinsic unique identifier. Sentry CLI assigns them a SHA1 UUID based on the checksum of the file. You can use sentry-cli debug-files check on a ProGuard file to see the generated UUID.

If you need to generate the UUID yourself, you can do so with the following algorithm (Python code for reference):

Copied
import uuid

NAMESPACE = uuid.uuid5(uuid.NAMESPACE_DNS, "guardsquare.com")

def get_proguard_uuid(filename):
with open(filename, 'rb') as f:
return uuid.uuid5(NAMESPACE, f.read())
Help improve this content
Our documentation is open source and available on GitHub. Your contributions are welcome, whether fixing a typo (drat!) or suggesting an update ("yeah, this would be better").