Inspect Debug Builds with gp-display-src

A crash names a function, and gp-display-src can pull up the exact source and disassembly behind it, if the debug information survived the build. It also lists every function in a compiled object when you just need the map. The command is part of GNU binutils 2.42 on this machine, supplied by the binutils-common package and exposed through architecture-prefixed aliases. Allow about fifteen minutes for a small test object, or longer if you are tracing a larger binary.

This guide assumes a readable executable, shared object, object file, or Java .class file. For source listings, the target must contain usable debug information and the referenced source files must still be available at the recorded paths. The examples are read-only. They do not need sudo, and you should not run the tool as root simply because the target was built by another user.

1. Confirm the installed command

Check the binary and version before relying on option details. The unprefixed command is a symlink to the host architecture's implementation here:

$ command -v gp-display-src
/usr/bin/gp-display-src
$ gp-display-src --version
GNU x86_64-linux-gnu-gp-display-src binutils version 2.42
Copyright (C) 2024 Free Software Foundation, Inc.

The installed manpage documents the normal interface as gprofng display src. The gp-display-src name is the direct command form, while gprofng display src is the driver form. Use one form consistently in scripts. The architecture-specific names, such as x86_64-linux-gnu-gp-display-src, are aliases for the same tool on matching installations.

Checkpoint: if command -v finds nothing, install or enable the binutils gprofng component through your normal package-management process. Do not copy a binary from an unrelated host and assume its libraries and debug-file handling will match.

2. Check the target before displaying it

Start with a file you own or are authorised to inspect. Confirm that it exists and identify its format without changing it:

$ test -r /path/to/program.o && echo readable
readable
$ file /path/to/program.o
/path/to/program.o: ELF 64-bit LSB relocatable, x86-64, version 1 (SYSV), with debug_info, not stripped

Your file output will vary. The useful clues are that the input is an object or executable format supported by the tool and that it has debug information if you expect source lines. A stripped target can still provide a function or disassembly view, but it may not provide names, line numbers, or source context.

Keep the source tree in place while investigating. The listing may refer to a path recorded by the compiler rather than the directory from which you run gp-display-src. If that path no longer exists, expect a source-file error even when the object itself is readable.

3. List functions before choosing a target

Use the function-listing option when you do not yet know the exact function spelling or when several names may be present:

$ gp-display-src -functions /path/to/program.o

Functions sorted in lexicographic order

Load Object: <program.o>

    Address                     Size        Name

  0x0000000000000056                47      main
  0x0000000000000040                22      triple

The addresses and sizes are properties of your target, so do not compare them with this sample. Copy the function name from your own output. The option is also accepted in the shorter installed spelling -func, but -functions is clearer in a command that someone else must maintain.

A repeated function name can require a tag to identify the occurrence. The command syntax requires that tag after the item name, even when it is not needed to disambiguate. The special pair all -1 selects every function in the target.

4. Display source for one function

Pass the function name, its tag, and the target file to -source. This example asks for the first tag:

$ gp-display-src -source main 0 /path/to/program.o
Source file: /path/to/program.c
Object file: /path/to/program.o
Load Object: /path/to/program.o

     1. #include <stdio.h>
     2. int main(void) { return 0; }
        <Function: main>

The output format includes a source header and numbered lines. It is not a source-file extractor: it presents the source context recorded in the object and annotates it with functions. With no options, the command requests all available source using the equivalent of -source all -1.

If the command says that a source file is not readable, check the exact path named in its error, the permissions on each directory, and whether the source was moved. A rebuild with debug information and stable source paths may be required. Do not make a readable copy of sensitive source in a world-readable directory just to satisfy the tool.

5. Add annotated disassembly

Use -disasm with the same item and tag when source lines alone do not explain the generated code:

$ gp-display-src -disasm main 0 /path/to/program.o
Annotated disassembly
---------------------------------------
Source file: /path/to/program.c
Object file: /path/to/program.o
Load Object: /path/to/program.o

     2. int main(void) { return 0; }
        <Function: main>
        [2]       56:  push   %rbp
        [2]       57:  mov    %rsp,%rbp

When source is unavailable, -disasm can still show disassembly-only output. This is useful for a stripped or third-party binary, but it does not restore source that was never embedded or cannot be found. Instruction syntax and addresses depend on the target architecture and compiler options.

To inspect everything in a target, use the documented all-functions form:

$ gp-display-src -disasm all -1 /path/to/program.o > all-functions.txt
$ test -s all-functions.txt && echo "listing written"
listing written

Redirecting to a new file is ordinary shell state and does not alter the object. For a large binary, expect a large listing. Do not send it to a terminal if you need to review it later.

6. Save output without overwriting evidence

The -outfile option writes results to a named file. A dash means standard output, which is also the default. Put it before the display option whose output it should capture:

$ gp-display-src -outfile main-source.txt -source main 0 /path/to/program.o
$ test -s main-source.txt && sed -n '1,12p' main-source.txt

Warning: do not use > or -outfile with a valuable existing report unless replacement is intentional. Both approaches can truncate or replace the destination. If you need an atomic replacement, write to a new name, inspect it, then move it over the old report:

$ gp-display-src -outfile main-source.txt.new -source main 0 /path/to/program.o
$ test -s main-source.txt.new && mv -- main-source.txt.new main-source.txt

The final mv changes the report name in its directory; it does not touch the target object. If the command fails, leave the old report alone and inspect the new file before deciding whether to remove it. Removing a report is irreversible, so do not add a blind cleanup command to a diagnostic script.

7. Diagnose the usual failures

A missing target is a path problem, not a reason to elevate privileges. Use ls -l and test -r to check it. An empty or unrecognised input is a format problem. A source-not-readable message usually means missing debug information, a moved source file, or permissions on the recorded path. A report with disassembly but no source is expected when only machine code or partial symbols are available.

If a function name is rejected, rerun -functions and copy the spelling exactly. If there are duplicate names, try the tags shown by the tool or qualify the item as function`file`, using the backtick-separated function and source or object file form documented by the manpage. Quote the whole argument if shell expansion could change it.

Security boundary: all examples inspect files. They do not execute the target being analysed, load code into a service, or alter compiler output. The boundary is still your input: avoid processing untrusted files in a privileged shell, and treat any report containing proprietary source or addresses as sensitive output.

Done means