Add Build IDs to a perf.data Stream with perf inject
You will create a second perf.data file with build ID records injected for the shared objects reached by samples, while leaving the original capture untouched. Allow about fifteen minutes, plus the time needed to process a large recording. You need the Linux perf tools that match the running kernel and a readable perf.data file produced by perf record.
The route
Jump straight to the step you need, or tick off Done means at the end.
This guide describes the perf-inject(1) installed with linux-tools-common version 6.8.0-142.142. The local manual is dated 1 September 2026. On this machine, the perf wrapper also reports that the kernel-specific binary for 6.8.0-139 is missing, so the example commands cannot be executed here until the matching tools package is installed. That is a local packaging problem, not a reason to change the capture.
1. Check the input and the matching tool
Start with ordinary, read-only checks. Replace /path/to/perf.data with the capture you intend to process:
$ command -v perf
/usr/bin/perf
$ dpkg-query -W -f='${Package} ${Version}\n' linux-tools-common
linux-tools-common 6.8.0-142.142
$ test -r /path/to/perf.data && file /path/to/perf.data
/path/to/perf.data: data
The exact file description can vary. The useful checks are that the path exists and is readable. Confirm the tool before starting a long conversion:
$ perf inject --help
Usage: perf inject <options>
If the command instead prints a warning that perf is not installed for the running kernel, stop at this checkpoint. Install or select the matching package through your normal system-management process, then rerun the check. Do not substitute a random version for a performance capture you need to trust.
2. Inject build IDs for sampled DSOs
The normal build-ID mode scans sample records, finds the dynamic shared objects reached by those samples, and adds their build IDs to the output stream. Write to a new path:
$ perf inject --input=/path/to/perf.data \
--output=/path/to/perf-with-buildids.data \
--build-ids
The short spelling is -i, -o and -b:
$ perf inject -i /path/to/perf.data \
-o /path/to/perf-with-buildids.data \
-b
$ printf 'exit status: %s\n' "$?"
exit status: 0
A zero status means the command completed successfully. It does not mean every symbol can be resolved later: a build ID identifies an object, while symbol names still depend on the object and its debug information being available to the consumer.
Checkpoint: confirm that a new, non-empty file exists and that the source still exists:
$ test -s /path/to/perf-with-buildids.data && \
test -r /path/to/perf.data && \
ls -lh /path/to/perf.data /path/to/perf-with-buildids.data
There is no rollback command because this workflow does not alter the input. If the generated file is wrong or incomplete, keep the original and choose a different output path for the next attempt. Do not use --force merely to make an existing destination disappear.
3. Inject all DSO build IDs instead
Use --buildid-all when the output should contain build IDs for all DSOs in the recording, including objects that were not hit by samples:
$ perf inject -i /path/to/perf.data \
-o /path/to/perf-with-all-buildids.data \
--buildid-all
This mode skips SAMPLE processing. That is a meaningful difference from --build-ids, not just a longer spelling. Choose it when later processing needs the complete set of recorded objects; otherwise the sample-driven mode usually keeps the result narrower.
Do not confuse a DSO with a source file. The option concerns the binary objects referenced by the event stream. It does not collect source code, install debuginfo or make an unavailable library available.
4. Use an explicit build-ID list when paths need overriding
--known-build-ids= accepts comma-separated build-ID and path pairs. It also accepts file://filename, allowing a list generated by perf buildid-list to be supplied as a file:
$ perf inject -i /path/to/perf.data \
-o /path/to/perf-with-known-buildids.data \
--known-build-ids=file:///path/to/buildids.txt
Treat the list as input data, not as a shell script. Quote a path containing spaces, and inspect the file before passing it to perf. Do not paste build IDs or paths from an untrusted source into a command line without checking them. If you do not have a verified list, omit this option and use one of the two automatic modes above.
5. Make the output easier to diagnose
Input and output default to standard input and standard output. That makes a pipeline possible, but named files are easier to audit and less likely to be mixed up with diagnostic text:
$ perf inject --build-ids \
< /path/to/perf.data \
> /path/to/perf-with-buildids.data
Use --verbose when you need additional diagnostics:
$ perf inject --verbose --build-ids \
-i /path/to/perf.data \
-o /path/to/perf-with-buildids.data
Keep standard output reserved for the event stream when using a pipeline. For a repeatable job, prefer --input and --output, then record the command and its exit status in the same place as the profiling result.
6. Keep specialised modes separate
--sched-stat merges scheduler sleep duration records with scheduler switch records. It is useful when analysing where and how long tasks slept, but it is unrelated to build-ID injection. Add it only when that scheduler analysis is part of the question:
$ perf inject -i /path/to/perf.data \
-o /path/to/perf-with-scheduler-data.data \
--sched-stat
--itrace decodes instruction-tracing data into synthesised events, and --strip removes non-synthesised events when used with it. These options can materially change what later tools see. The manual documents a default set of decoded event types, period units, call-chain limits and branch-entry limits. Do not add --itrace to a build-ID job unless the input contains instruction tracing and you have decided which derived events you need.
Similarly, --jit processes jitdump files and generates ELF images for jitted functions. This can create additional files, so treat it as a deliberate output-producing operation. For virtual-machine timestamp correlation, the manual says that --vm-time-correlation updates the input file in place and does not accept a separate output file. That is an overwrite operation: use its dry-run form first when supported, take a backup, and do not include it in the safe copy-to-a-new-file workflow above.
7. Diagnose the common failures
If the input cannot be opened, check its path and permissions first. If the output already exists, choose a new name rather than adding --force by reflex. If the command fails with a missing perf binary for the running kernel, install the matching Linux tools package and rerun perf inject --help before processing the capture.
A command that completes does not prove that every later report will have symbols. Preserve the original perf.data file, the injected copy, the exact command line and the tool version. If a later analysis reports missing objects, compare its search paths and available binaries with the build IDs recorded in the capture rather than regenerating the input destructively.
Done means
- The installed perf tool matches the running kernel, or the mismatch is recorded as an unresolved prerequisite.
- The original
perf.datafile remains unchanged and readable. - A separate output file was created with
--build-idsor--buildid-all. - The output is non-empty and the command returned status 0.
- Any known build-ID list was inspected before use.
- You did not use the in-place virtual-machine timestamp mode accidentally.