2026-08-23
Omar Sandoval wrote drgn at Facebook because gdb scripting on live kernels was painfully slow, crash(8)'s macro language was awkward, and neither could be embedded in production tooling. It's pip install drgn (or a distro package), and it does something none of those tools quite do: gives you a real Python 3 API for walking Linux kernel data structures on a running system, a /proc/kcore snapshot, or a kdump vmcore.
The trick is DWARF. Point drgn at your vmlinux (or the kernel-debuginfo package) and every struct field just… works, with tab completion and Python iteration protocols.
$ sudo drgn # attach to running kernel
>>> prog['init_task'].comm
(char[16])"swapper/0"
>>> prog['jiffies']
(volatile long unsigned int)4295567891
$ drgn -c /var/crash/vmcore \ # or postmortem on a vmcore
-s /usr/lib/debug/.../vmlinux
The killer feature is the helper library. Want every process holding an fd to a specific inode? In systemtap that's ~300 lines of C; in drgn:
from drgn.helpers.linux import for_each_task, for_each_file
for task in for_each_task(prog):
for fd, file in for_each_file(task):
if file.f_inode.i_ino == 12345:
print(task.pid.value_(),
task.comm.string_().decode(), fd)
Or "print every task stuck in D-state for >120s along with its kernel stack" — the classic hung-task investigation you normally do by squinting at dmesg:
from drgn.helpers.linux import for_each_task
from drgn.helpers.common.stack import print_annotated_stack
TASK_UNINTERRUPTIBLE = 2
now = prog['jiffies'].value_()
HZ = prog['CONFIG_HZ'].value_()
for t in for_each_task(prog):
if t.__state.value_() & TASK_UNINTERRUPTIBLE:
stuck = (now - t.last_switch_time.value_()) // HZ
if stuck > 120:
print(t.pid.value_(), t.comm.string_().decode(), stuck, "s")
print_annotated_stack(prog.stack_trace(t))
Where drgn quietly earns its keep in production:
/proc/kcore, walk the task list, dump stacks. No reboot, no kdump.page_counter.usage, spot the leaker.struct sock in tcp_hashinfo, print sk_state, sk_wmem_queued, ports. Do that in gdb./proc/kcore; it works unchanged on the vmcore that lands in /var/crash six hours later.There's also a --pid mode that attaches to userspace processes and loads their debuginfo — slower and less magical than kernel mode, but it covers the gdb -p case where you just want to pull a field out of a struct without setting breakpoints.
Why it beats the alternatives: crash(8) gives you a fixed vocabulary of commands (ps, foreach files, mount) plus its own scripting dialect you can only use inside crash. gdb's Python API technically works on kernels but symbol resolution and iteration over kernel lists is agonizingly slow — drgn was literally born from Omar timing "list every task" and finding gdb took minutes while a C program took milliseconds. bpftrace is fantastic for events, but useless for "what does the current state of this hash table look like right now."
Two gotchas that bounce people off it: (1) you need matching kernel debuginfo installed — usually a separate distro package; (2) live-kernel mode needs root because /proc/kcore is root-only. Neither is drgn's fault, and both go away the moment you've done it once.
