Skip to content

Support for debugging Linux kernel with Compact Type Format (CTF) #495

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: main
Choose a base branch
from

Conversation

brenns10
Copy link
Contributor

CTF is a lightweight format for representing C types. While there is an older format which seems to be currently in use by some BSDs, this pull request refers to the CTF format specified and actively maintained in the binutils project, aka CTF v3. The format can be generated by GCC, linked and deduplicated by GNU ld, and consumed by GDB, as well as DTrace for Linux. This pull request adds the ability for drgn to use CTF for a type & object finder for the Linux kernel. (The object finder relies on the existence of a symbol finder, e.g. from kallsyms).

CTF is currently used by DTrace on Oracle Linux. It is packaged as part of UEK kernels in a file named /lib/modules/$(uname -r)/kernel/vmlinux.ctfa. This is an out-of-tree patch carried by UEK, but we're working to upstream it. The vmlinux.ctfa file is a CTF "archive", which contains a 1-level hierarchy of "dicts" (dictionaries). The leaf dictionaries each represent the kernel ("vmlinux") or kernel module. They all inherit from the root dict ("shared_ctf") which contains deduplicated type definitions that can be shared among all dicts.

CTF is not widely used in userspace, but there is no reason it could not be. Typically, CTF information is stored in the .ctf section of an ELF file. It's generated by GCC with -gctf. Since CTF is generally intended for runtime debugging, userspace CTF relies on the dynamic symbol table, and so the linker typically only includes types for the functions and variables which are exported in this symbol table. Userspace programs might either use ld's --export-dynamic option to include all symbols in the dynamic symbol table, or else they may use ld's --ctf-variables option to retain non-exported type names, and rely on another source of information (e.g. the .gnu_debugdata) to contain the addresses.

The PR as-is supports kernel CTF only, though it can support simple userspace programs if you force it to. We use that provisional support for the test suite.

You can find the CTFv3 specification here, and the best documentation for the API is found in ctf-api.h.

I'd like to use this pull request as a first step to see whether the high-level approach is reasonable. I'm adding two functions to the _drgn module which attach either a CTF archive, or an out-of-tree kernel module, to a Program. These are of course private APIs, and I've shared two examples of how they could be used: via the load_ctf() helper function, or a drgn plugin, thanks to the new API.

brenns10 added 5 commits June 23, 2025 15:49
Using drgn_program_find_object() to check for the existence of
vmemmap_populate is overkill. It requires type information for the
function, which may not be available. All we need to do is verify the
existence, so lookup the symbol, and verify that the symbol kind is a
function.

Signed-off-by: Stephen Brennan <[email protected]>
The Compact C Type Format (CTF) is an alternative debug information
format which describes the types of C data structures. Unlike other
debug information formats (like DWARF), it is designed to be very
compact, so that it can be included in production binaries and packages:
NOT in debuginfo packages.

Support for generating CTF exists in GCC, and support for consuming CTF
exists in GDB. The Linux kernel does not currently support building with
CTF, but an effort is underway to change this. Oracle UEK kernels
already build with CTF: each kernel RPM contains a file named
"vmlinux.ctfa" which is a CTF archive: it contains type information for
the kernel and all modules.

CTF can be used as an alternative to DWARF. It cannot provide all the
features that DWARF would - in particular, stack traces require frame
pointers, or ORC, or DWARF CFI. CTF cannot allow drgn to read variables
from stack frames, nor can it provide information about the source code
files and line numbers associated with program elements. But it can
provide the necessary information to implement a Type Finder. Assuming
symbol information is available (e.g. from kallsyms), then an Object
Finder can be implemented, which looks up names in the symbol table and
then uses libctf to find the type of the object.

This commit introduces a CTF type & object finder according to this
approach. To use it, a helper function is added, which allows a user to
provide the location of the vmlinux.ctfa file.

Signed-off-by: Stephen Brennan <[email protected]>
The CTF format needs to be tested, but it is primarily used by the
kernel, and it is currently out-of-tree in Oracle kernels (but being
upstreamed). Rather than adding several out-of-tree patches to the
vmtest subsystem to test kernel CTF directly, a simpler approach is to
test userspace CTF.

The current drgn CTF implementation isn't generic enough to support
userspace properly. However, it is good enough to load a simple core
dump with CTF data, without a symbol table. This gives us everything we
need to begin testing type representations.

Add a "test.c" file which can be built either with DWARF, GCC's CTF, or
dwarf2ctf. The two CTF implementations have subtle differences which
drgn supports, and thus need to each be tested.

Along with this test.c file, add some basic tests. The goal is that
these tests should pass on both DWARF and CTF. This is not even close to
a complete test suite, but it does incorporate several areas where the
CTF implementation needs careful attention: structs with bitfields, and
multidimensional arrays.

Signed-off-by: Stephen Brennan <[email protected]>
Out-of-tree modules are well-supported by the CTF kernel using the
standard module building process. A ".ctf" section is included in the
ELF section for the loaded module, much like the relevant DWARF sections
in the debuginfo file. In the future, integration with the drgn module
API will make this much better integrated with all of drgn. But for now,
we rely on the fact that libctf with libbfd can find read the ELF file
and find the relevant data. Just like loading a standard CTF archive,
this is exposed as a private helper function from the _drgn module.

Supporting out-of-tree modules is critical for enabling kernel CTF tests
with the vmtest infrastructure, since many of drgn's tests use an
out-of-tree kernel module to create control data which can then be
tested against.

Signed-off-by: Stephen Brennan <[email protected]>
Running drgn scripts via "drgn -c TARGET -s DEBUGINFO script.py" is a
really handy part of drgn. As it is, CTF support can't be used in this
way, because drgn's CLI doesn't support CTF and it's not automatically
used.

We don't want to automatically use CTF, so let's instead add a new
argument, "-C". When provided, the "-s" argument is assumed to be a
"vmlinux.ctfa" file, and if "-s" is not provided, we just use the
default (which is usually the right thing to do anyway).

Signed-off-by: Stephen Brennan <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant