Decode trace format 4 and pick the debug file by the executable's debug id - #31
Open
robobun wants to merge 2 commits into
Open
Decode trace format 4 and pick the debug file by the executable's debug id#31robobun wants to merge 2 commits into
robobun wants to merge 2 commits into
Conversation
…ug id oven-sh/bun#38838 makes bun's crash handler emit trace format '4': after the sha, the build-flags VLQ of format 3 (bit 0 = canary) and then the id the linker stamped into the executable (PDB GUID, GNU build-id, LC_UUID) as a VLQ byte count plus lowercase hex. Until now a trace named its build by platform char plus sha, which is not a binary: a commit published as both bun-windows-x64 and bun-windows-x64-baseline reports 'w' from both links, and traces from the second were symbolized with the first one's PDB, producing plausible-looking nonsense. - lib/parser.ts: parse '4'; Parse.debug_id. - backend/debug-id.ts: read the same id out of the bun-profile executable in a profile zip (PE debug directory, ELF PT_NOTE, Mach-O LC_UUID), and the selection policy: check the trace's own arch artifact, fall back to the sibling x64 link that carries the id, flag a total mismatch. - backend/debug-store.ts, db.ts: record the artifact's id when it is downloaded (new nullable debug_file.debug_id column, added in place). - backend/remap.ts: on a mismatch leave the addresses unsymbolicated instead of remapping them against the wrong binary; Remap.arch is the link actually used; Remap.debug_id / debug_file carry the outcome. - backend/sentry.ts: arch/dist/baseline tags follow the link actually used; new debug_id and debug_file tags. - markdown, /remap response and the frontend footer say when a trace matched nothing. - lib/util.ts: the remap cache key includes the id so two links of one commit do not share entries; keys of older traces are unchanged. - tests: v4 roundtrips and field validation, synthetic PE/ELF/Mach-O files (the PE one pinned to a GUID llvm-readobj printed for a real bun-debug.exe), the selection policy, and two real v4 captures as parse fixtures.
…orm char The header after the sha is now a VLQ field count followed by (tag, char count, chars) fields, as bun's encoder writes it: tag 0 is the build flags VLQ, tag 1 the debug id in hex. Unknown tags are skipped, so bun can add fields without another version char and without the decoder deploying first. Selection now iterates every build a commit is published as under the same platform char: on Linux the glibc, musl and android builds all report 'l'/'L' and were all symbolized against the glibc binary; x64 additionally tries the -baseline name for trees that still build one. The build that matched is reported as Remap.variant (musl / android / baseline) and becomes Sentry's dist and a tag; Remap.arch stays the trace's arch. Cache rows and dirs for the plain build keep their existing names. Fixtures: the Linux capture is a real trace from the final encoder; the Windows one keeps its real frames with the header re-encoded.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Companion to oven-sh/bun#38838, which has to wait for this to be deployed: from that change on bun emits trace format
'4', which this server currently rejects.Problem
debug-store.tsturns that into exactly one artifact. A commit is published as more than one build per platform character: on Linux the glibc, musl and android builds all report'l'/'L'(bun'sPlatform::CURRENTonly distinguishes os and arch), and this server downloadsbun-linux-<arch>-profile.zip, the glibc one, for all of them. Every musl or android trace is therefore remapped against a different binary's symbols today, and the result looks like a normal remap.-baselinebinary is what the Windows x64 reports a downstream build of commit8bb8d04c4sends look like (BUN-4B1Q, BUN-4BST, BUN-4B64, BUN-4BW6, BUN-4B2Y, about 60 events a day): symbolized against the other link's PDB they read as date/time-zone crashes; against the right one they are a GC marking-thread crash and anIntl.Segmentercrash (evidence in crash_handler(windows): unwind through LLInt and vmEntryToJavaScript frames and stop the walk at non-code PCs bun#38789).Fix
'4'(lib/parser.ts): after the sha, a VLQ field count followed by fields of (VLQ tag, VLQ char count, chars). Tag 0 is the build flags VLQ (bit 0 = canary, replacing the'1'/'2'split), tag 1 the executable's debug id (PDB GUID / GNU build-id /LC_UUID) as lowercase hex in the byte order the platform's tools print it. Unknown tags are skipped by their length, so bun can add fields (registers, whatever comes next) without another version character and without this server having to deploy first; malformed counts, lengths, ids and flags fail the parse rather than being read into the fields after them. Exposed asParse.debug_id.backend/debug-id.tsreads the same id out of thebun-profileexecutable in a profile zip, lists the builds a commit is published as for a platform character (publishedLinks: plain, then musl and android on Linux, then the-baselinename on x64), and holds the selection policy (selectDebugFile): the plain build if it carries the id, otherwise the first of the others that does; the plain build flaggedunverifiedif its own id cannot be read; flaggedmismatchif nothing carries it. Traces without an id (formats 1 to 3) take exactly the old path.backend/debug-store.ts/db.tsdownload by build name, record each artifact's id when it is downloaded (nullabledebug_idcolumn added todebug_filein place), and keep the plain build's cache rows and directories under their existing names so the current cache stays valid (cacheName).backend/remap.ts: onmismatchthe symbolizer is not run and the addresses stay raw; Sentry still gets the event, tagged. The build that matched is reported asRemap.variant(musl/android/baseline), which becomes Sentry'sdistand avarianttag (backend/sentry.ts), is printed in the issue markdown, and is returned by/remapfor the frontend footer;Remap.archstays the trace's arch.debug_idanddebug_fileare carried on the remap and as tags, and the markdown and frontend say so when a trace matched nothing.lib/util.ts: the remap cache key includes the id, so two builds of one commit never share an entry; keys for traces without an id are unchanged.Verification
bun test: 206 pass. New: format-4 roundtrips (20-byte and 16-byte ids, no id, flags) and a test that fields with unknown tags are skipped and the fields after the header still decode; rejection of bad counts, lengths, ids and flags; field order independence; cache-key behaviour;readExecutableDebugIdon synthetic PE/ELF/Mach-O files (the PE case pinned to a GUIDllvm-readobjprinted for a realbun-debug.exe) and on the test runner's own binary;publishedLinksfor every os/arch; every branch ofselectDebugFile, including a musl trace landing on the musl build and the downstream baseline case;cacheNamekeeping legacy names and never colliding. Parse fixtures: a real format-4 trace from a Linux debug build of the bun PR (its id is the binary'sreadelf -nbuild id), and the real Windows x64 CI crash from the bun PR with its header re-encoded in the final layout, which decodes to the same frames, GUID and fault address as before. Snapshots reviewed by hand.bun x tsc --noEmitclean;bun build.tsbuilds the frontend.debug_filemigration was exercised against a database created with the old table shape: legacy rows read back without an id, new rows with one, and a second open does not re-run theALTER.bin/ci-remap-server.tsonly gains the ability to parse format 4 (it symbolizes against the local binary and skips the store); bun'sbun-tracestringspin will be bumped to this commit once it lands.Background
RSDS) record with the GUID of their PDB; ELF executables carry a hash of themselves in a.note.gnu.build-idnote; Mach-O executables carry anLC_UUIDload command that the dSYM repeats. Debuggers use these to match a binary to its symbols. bun's crash handler now puts its own into the trace, andbackend/debug-id.tsreads the same value out of the executable shipped in every profile zip.-baselinecopies of the x64 zips (an alias of the same binary upstream since ci: single arm64 debian-13 build host; ThinLTO everywhere; baseline-only x64; rust+link merge; sysroots; WebKit a36c188; rust 2026-07-20 bun#34782, a separate binary in trees that still build one). Only baseline ever had its own platform characters, and those are no longer emitted.