0.0.28 & 0.0.29 (Released October 7th & 8th, 2024)

These are some of the highlights of drgn 0.0.28. See the GitHub release for the full release notes, including more improvements and bug fixes.

drgn 0.0.29 was released shortly after 0.0.28 with a single bug fix for the drgn.helpers.experimental.kmodify module. See the release notes.

Calling Arbitrary Functions in the Running Kernel

This release added call_function(), which calls a function in the running kernel. This is the first ever feature in drgn that allows modifying the state of the kernel. Its primary use cases are experimentation in development environments and mitigating kernel bugs in production. For example, this recent lost wake-up bug could be mitigated with something like:

from drgn.helpers.experimental.kmodify import call_function
for task in for_each_task():
    for frame in stack_trace(task):
        if frame.name == "perf_event_free_task":
            call_function("wake_up_process", task)
            break

Note that this feature is currently experimental, only supported on x86-64, and may have a different API in the future.

There is a blog post about how this feature works.

Writing to Kernel Memory

In a similar vein, drgn can now write to kernel memory, either via an address (with write_memory()):

>>> import os
>>> from drgn.helpers.experimental.kmodify import write_memory
>>> os.uname().sysname
'Linux'
>>> write_memory(prog["init_uts_ns"].name.sysname.address_, b"Lol\\0")
>>> os.uname().sysname
'Lol'

or an object (with write_object()):

>>> from drgn.helpers.experimental.kmodify import write_object
>>> os.system("uptime -p")
up 12 minutes
>>> write_object(prog["init_time_ns"].offsets.boottime.tv_sec, 1000000000)
>>> os.system("uptime -p")
up 3 decades, 1 year, 37 weeks, 1 hour, 59 minutes

This feature is also experimental. It uses the same underlying mechanism as call_function().

More C Operators

This release added a couple of new functions corresponding to operators in C. The alignof() function is analogous to the _Alignof() operator in C:

>>> alignof(prog.type("long long"))
8

The implicit_convert() function implements implicit conversions in C, like when assigning a variable, passing an argument to a function call, or returning a value:

>>> implicit_convert("unsigned int", Object(prog, "float", 2.0))
(unsigned int)2
>>> implicit_convert("void *", Object(prog, "int", 0))
Traceback (most recent call last):
  ...
TypeError: cannot convert 'int' to incompatible type 'void *'

Kernel Module Helpers

Stephen Brennan contributed several helpers for working with Linux kernel modules.

for_each_module() iterates over loaded modules:

>>> for module in for_each_module():
...     print(module.name.string_().decode())
...
overlay
vhost_net
vhost
...

find_module() finds the module with a given name:

>>> module = find_module("overlay")
>>> module
*(struct module *)0xffffffffc23dae00 = {
        ...
}

module_address_regions() and module_percpu_region() return all of the memory regions associated with a module, and address_to_module() finds the module containing an address:

>>> for start, size in module_address_regions(module):
...     print(hex(start), size)
...
0xffffffffc23be000 102400
0xffffffffc23d8000 65536
0xffffffffc23e9000 73728
0xffffffffc2385000 4096
0x0 0
0x0 0
0x0 0
>>> address_to_module(0xffffffffc23bf000) == module
True

Thread Names

Ryan Wilson added the name attribute to drgn.Thread. This provides a consistent interface for getting the name of a thread regardless of whether you’re debugging the kernel or a userspace program. (Unfortunately, userspace core dumps on Linux don’t save the name of any threads other than the main thread.)

Full 32-Bit Arm Support

This release added support for virtual address translation and stack traces on 32-bit Arm. This is the state of architecture support in this release:

Architecture

Linux Kernel Modules

Stack Traces

Virtual Address Translation

x86-64

AArch64

s390x

ppc64

i386

Arm

RISC-V

Note that there are known Linux kernel issues with debugging 32-bit Arm, both live and in kdump. Please reach out to the linux-debuggers@vger.kernel.org mailing list if these affect you.

AArch64 and s390x Virtual Address Translation Fixes

As of Linux 6.9, the default AArch64 kernel configuration enables 52-bit virtual addresses and falls back to a smaller virtual address size if the hardware does not support 52 bits. This required updates to drgn that were missed in v0.0.27.

As of Linux 6.10, on s390x, virtual addresses in the direct mapping are no longer equal to physical addresses. This also required updates to drgn that were missed in v0.0.27.

Linux 6.11 and 6.12 Support

A change in Linux 6.12 broke tools/fsrefs.py. This error from visit_uprobes() is fixed in this release:

TypeError: cannot convert 'struct list_head' to bool

No other changes were required to support Linux 6.11 and 6.12.