Skip to content

drgn 0.0.33

Latest

Choose a tag to compare

@osandov osandov released this 29 Oct 20:50
· 132 commits to main since this release

New Features

Numerous Linux kernel memory management-related helpers were added:

  • nr_blockdev_pages() was added to drgn.helpers.linux.block. It returns the amount of memory used for block device buffers.
  • A new drgn.helpers.linux.hugetlb helper module was added.
    • for_each_hstate() iterates over all HugeTLB page sizes.
    • huge_page_size() returns the size of a HugeTLB state.
    • hugetlb_total_pages() returns the total number of HugeTLB pages.
    • hugetlb_total_usage() returns global HugeTLB usage information.
  • A new drgn.helpers.linux.swap helper module was added.
    • for_each_swap_info() iterates over all swap devices.
    • swap_file_path() returns the path of a swap device.
    • swap_is_file() returns whether a swap device is a regular file.
    • swap_usage_in_pages() returns the number of pages currently used on a given swap device.
    • swap_total_usage() returns global swap usage information.
    • total_swapcache_pages() returns the number of swap cached pages.
  • slab_cache_objects_per_slab(), slab_cache_pages_per_slab(), and slab_cache_order() were added to drgn.helpers.linux.slab. They return information about the layout of slab allocations.
  • slab_cache_usage() was added to drgn.helpers.linux.slab. It returns statistics on how many objects and slabs are allocated for a slab cache.
  • slab_total_usage() was added to drgn.helpers.linux.slab. It returns the total amount of memory used by the slab allocator.
  • for_each_valid_page_range() and for_each_valid_pfn_and_page() were added to drgn.helpers.linux.mm. They iterate over all valid pages.
  • task_rss() was added to drgn.helpers.linux.mm. It returns a task's resident set size. Contributed by Yassine Larhrissi.
  • vm_commit_limit() and vm_memory_committed() were added to drgn.helpers.linux.mm. They return virtual memory overcommit information.
  • decode_page_flags_value() was added to drgn.helpers.linux.mm. It is like decode_page_flags() but takes the flags value instead of the page.
  • Helpers for accessing common struct page fields regardless of kernel version were added to drgn.helpers.linux.mm.
    • page_flags() returns a page's flags. Contributed by Ye Liu.
    • page_index() returns a page's offset in its containing mapping.
  • Memory hotplug-related helpers were added to drgn.helpers.linux.mm.
    • for_each_memory_block() iterates over all memory hotplug blocks.
    • decode_memory_block_state() gets the state of a memory hotplug block.
    • memory_block_size_bytes() returns the size of a memory hotplug block.
  • A new drgn.helpers.linux.mmzone helper module was added.
    • NODE_DATA() gets the NUMA node memory layout data of a given node.
    • for_each_online_pgdat() iterates over the NUMA node data for each online node.
    • nr_to_section(), pfn_to_section_nr(), section_nr_to_pfn(), pfn_to_section(), section_mem_map_addr(), section_decode_mem_map() and for_each_present_section() look up SPARSEMEM sections.
    • present_section{,_nr}(), valid_section{,_nr}(), online_section{,_nr}(), early_section{,_nr}(), and decode_section_flags() check SPARSEMEM section flags.
    • {min_,low_,high_,}wmark_pages() get memory reclaim watermarks.
  • A new drgn.helpers.linux.vmstat helper module was added.
    • global_node_page_state(), zone_page_state(), global_zone_page_state(), nr_free_pages(), global_numa_event_state(), and global_vm_event_state() return various VM statistic counters.
  • identify_address_all() was added to drgn.helpers.common.memory. It is a programmatic variant of identify_address() that can return multiple matches and returns matches as objects with additional attributes instead of strings.
  • set_bit() and clear_bit() were added to drgn.helpers.experimental.kmodify. They atomically set or clear a bit in kernel memory, respectively.

Many other helpers were also added.

  • dev_name() was added to drgn.helpers.linux.device. It returns the name of a device.
  • super_block_for_each_mount() was added to drgn.helpers.linux.fs. It iterates over all mounts of a super block (filesystem).
  • bus_to_subsys() and class_to_subsys() were added to drgn.helpers.linux.device. They get the private data for a device bus or class, respectively.
  • bus_for_each_dev() and class_for_each_device() were added to drgn.helpers.linux.device. They iterate over all devices on a given bus or of a given class, respectively.
  • module_kallsyms() was added to drgn.helpers.linux.kallsyms. It returns a list of symbols for a given module from its kallsyms data. Originally contributed by Stephen Brennan.
  • kernfs_children() was added to drgn.helpers.linux.kernfs. It returns the children of a kernfs directory. Contributed by Joanne Koong.
  • validate_list_count_nodes() was added to drgn.helpers.linux.list. It returns the length of a Linux kernel list while validating it.
  • nr_node_ids() was added to drgn.helpers.linux.nodemask. It returns the upper bound on NUMA node ID numbers.
  • A new drgn.helpers.linux.panic helper module was added.
    • panic_task() returns the struct task_struct * that caused a crash.
    • panic_message() returns the message logged during a panic.
    • tainted() gets the kernel's taint flags as a string.
  • module_taints() was added to drgn.helpers.linux.module. It returns a kernel module's taint flags as a string.
  • percpu_counter_sum_positive() was added to drgn.helpers.linux.percpu. It returns the sum of a per-CPU counter, or 0 if it is negative.
  • for_each_task_in_group() was added to drgn.helpers.linux.pid. It iterates over the threads of a process. Contributed by Stephen Brennan.
  • rbtree_preorder_for_each{,_entry}() were added to drgn.helpers.linux.rbtree. These do a pre-order traversal instead of the in-order traversal that rbtree_inorder_for_each{,_entry()} do.
  • Runqueue-related helpers were added to drgn.helpers.linux.sched. Contributed by Richard Li.
    • cpu_rq() gets the runqueue for a given CPU.
    • task_rq() gets the runqueue that a given task is on.
    • task_since_last_arrival_ns() returns approximately how long a task has been in its current running status.
  • get_task_state() was added to drgn.helpers.linux.sched. It returns a human-readable description of a task's state ("R (running)", "S (sleeping)", etc.).
  • task_on_cpu() was added to drgn.helpers.linux.sched. It returns whether a given task is currently running.
  • double_quote_ascii_string() was added to drgn.helpers.common.format. It formats a byte string as a double-quoted string literal.
  • typeof_member() was added to drgn.helpers.common.type. It returns the type of a given member in another type.

Several helpers were extended.

  • drgn.helpers.common.memory.identify_address() (and the new identify_address_all()) now recognizes page and task addresses. It also now recognizes stack addresses on kernels configured without CONFIG_VMAP_STACK.
  • drgn.helpers.linux.slab.slab_object_info() and drgn.helpers.common.memory.identify_address() now return as much information as possible for the SLOB allocator instead of always returning None.
  • drgn.helpers.linux.printk.{get,print}_dmesg() now take a timestamps parameter controlling how timestamps are formatted. Contributed by Yassine Larhrissi.
  • drgn.helpers.linux.kernfs.kernfs_walk() can now follow symlinks. Contributed by Joanne Koong.
  • drgn.helpers.linux.timekeeping.ktime_get_real_seconds() can now get the time from the VMCOREINFO crash dump metadata, which is more reliable.
  • drgn.helpers.common.format.print_table() can now align interleaved rows in groups.

Finally, quite a few other features were added.

  • Array and pointer objects can now be sliced (e.g., arr[1:2]) to construct a new array with a different start and length.
  • The kernel stack size is now available as prog["THREAD_SIZE"]. Contributed by Stephen Brennan.
  • Various SPARSEMEM parameters are now available with prog["name"]: NR_SECTION_ROOTS, SECTIONS_PER_ROOT, SECTION_SIZE_BITS, MAX_PHYSMEM_BITS.
  • drgn.Type.variable_declaration() was added. It formats a variable declaration with a given type.
  • drgn.Type.unaliased() and drgn.Type.unaliased_kind() were added. They get information about a type with top-level typedefs removed.
  • drgn.Object.format_() now takes a integer_base parameter to control whether integers are printed in decimal, hexadecimal, or octal.
  • drgn.Object.subobject_() was added. It does one or more member or element lookups from a string.
  • drgn.Program.read_c_string() was added. It reads a null-terminated string from program memory.
  • drgn.Program.address_size() was added. It returns the size of an address in the program.
  • drgn.Program.config was added. It is a dictionary that can be used internally and by users to store arbitrary configuration information.
  • drgn.Program.core_dump_path was added. It is the path of the core dump file being debugged.
  • Object lookups (e.g., drgn.Program[], drgn.Program.object()) now raise drgn.ObjectNotFoundError instead of KeyError or LookupError. ObjectNotFoundError is a subclass of KeyError, so this should not break existing code.
  • Linux 6.17 and 6.18 are now supported.
    • The drgn.helpers.linux.timekeeping helpers were updated to handle the core timekeeping structure being changed in Linux 6.17.
    • tools/fsrefs.py was updated to handle a change in how block devices used by Btrfs were tracked in Linux 6.17.
    • drgn.helpers.linux.fs.d_path() when passed only a dentry was updated to handle a change to the list of super block mounts in Linux 6.18.
    • drgn.helpers.linux.net.get_net_ns_by_inode() was updated to handle a moved structure member in Linux 6.18.
    • drgn now handles empty ELF program headers in vmlinux, which were observed on some Linux 6.18 builds.

Incompatible Changes

  • Support for Python 3.6 and 3.7 was removed.
  • drgn.helpers.common.memory.identify_address() now returns "task stack: ..." instead of "vmap stack: ..." when it identifies an address as belonging to a vmapped task stack.

Bug Fixes

  • Stack traces on x86-64 kernels using the frame pointer unwinder (instead of ORC) and on AArch64 can now unwind through an interrupt. Contributed by Stephen Brennan.
  • drgn.helpers.linux.mm.for_each_page() was fixed to not return invalid pages that can't be dereferenced.
  • drgn.helpers.experimental.kmodify.write_object() was fixed to handle bit fields of size 1 and reject larger bit fields. Previously, it would write to the wrong bits and overwrite additional memory.
  • Symbol lookups of Linux kernel per-CPU symbols (drgn.Program.symbol{,s}()) now return the correct address instead of incorrectly applying the KASLR offset.
  • An UnboundLocalError from drgn.helpers.linux.cgroup.css_next_child() when racing with a cgroup being released was fixed.
  • drgn.helpers.linux.percpu.percpu_counter_sum() was fixed on !SMP kernels. It would previously fail with an AttributeError.
  • slab_cache_for_each_allocated_object() and slab_object_info() in drgn.helpers.linux.slab were made more resilient to races with slab allocator activity on live kernels.
  • slab_cache_for_each_allocated_object() and slab_object_info() in drgn.helpers.linux.slab were fixed to consider per-node caches in the old SLAB allocator.
  • tools/fsrefs.py was fixed to not print "unknown uprobe" warnings when the uprobe was actually found.
  • Subscripting an array with a negative index was fixed. It previously computed an incorrect address.
  • A buffer underwrite when creating an object with size 0 from bytes was fixed.
  • A race leaving the GIL in an invalid state on Python versions before 3.12 was fixed.
  • A deprecation warning when building for Python 3.14 was fixed.

contrib Directory

  • contrib/pstack.py was added. It collects stack traces of userspace tasks when debugging the kernel. Contributed by Stephen Brennan.
  • contrib/bt_by_pid_and_frame.py was added. It is convenience script for getting stack traces and local variables from the kernel. Contributed by Ye Liu.
  • contrib/show_page_info.py was added. It dumps the page state of a given virtual address in a given PID. Contributed by Ye Liu.
  • contrib/mutex_owner.py was added. It lists what task holds a mutex and what tasks are waiting. Contributed by Matt Fleming.
  • contrib/search_kernel_memory.py now handles kernel core dumps (as long as the kernel was configured with CONFIG_PROC_KCORE=y). It can also now accept the value to search for as a string or address-sized integer.

Internal

  • A system for CLI-like commands was implemented, and several commands from the crash utility were ported to drgn. This is not quite polished yet, so it is not enabled by default. It can be enabled for alpha testing by running import drgn.commands._builtin. Commands are accessed by starting a line in the REPL with %. This contains contributions from Stephen Brennan, Ye Liu, and Srikanth C S.