drgn/docs/advanced_usage.rst
Omar Sandoval 18a8f69ad8 libdrgn: linux_kernel: add object finder for jiffies
We have a lot of examples that use jiffies, but they stopped working
long ago on x86-64 (since Linux kernel commit d8ad6d39c35d ("x86_64: Fix
jiffies ODR violation") (in v5.8 and backported to stable releases)) and
never worked on other architectures. This is because jiffies is defined
in the Linux kernel's linker script. #277 proposed updating the examples
to use jiffies_64, but I would guess that most kernel developers are
familiar with jiffies and many have never seen jiffies_64. jiffies is
also a nicer name to type in live demos. Let's add a case to the Linux
kernel object finder to get the jiffies variable.

Reported-by: Martin Liska <mliska@suse.cz>
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2023-02-22 11:15:37 -08:00

194 lines
6.9 KiB
ReStructuredText

Advanced Usage
==============
.. highlight:: pycon
The :doc:`user_guide` covers basic usage of drgn, but drgn also supports more
advanced use cases which are covered here.
Loading Debugging Symbols
-------------------------
drgn will automatically load debugging information based on the debugged
program (e.g., from loaded kernel modules or loaded shared libraries).
:meth:`drgn.Program.load_debug_info()` can be used to load additional debugging
information::
>>> prog.load_debug_info(['./libfoo.so', '/usr/lib/libbar.so'])
Library
-------
In addition to the CLI, drgn is also available as a library.
:func:`drgn.program_from_core_dump()`, :func:`drgn.program_from_kernel()`, and
:func:`drgn.program_from_pid()` correspond to the ``-c``, ``-k``, and ``-p``
command line options, respectively; they return a :class:`drgn.Program` that
can be used just like the one initialized by the CLI::
>>> import drgn
>>> prog = drgn.program_from_kernel()
C Library
---------
The core functionality of drgn is implemented in C and is available as a C
library, ``libdrgn``. See |drgn.h|_.
.. |drgn.h| replace:: ``drgn.h``
.. _drgn.h: https://github.com/osandov/drgn/blob/main/libdrgn/drgn.h.in
Full documentation can be generated by running ``doxygen`` in the ``libdrgn``
directory of the source code. Note that the API and ABI are not yet stable.
Custom Programs
---------------
The main components of a :class:`drgn.Program` are the program memory, types,
and symbols. The CLI and equivalent library interfaces automatically determine
these. However, it is also possible to create a "blank" ``Program`` and plug in
the main components. The :func:`drgn.cli.run_interactive()` function allows you
to run the same drgn CLI once you've created a :class:`drgn.Program`, so it's
easy to make a custom program which allows interactive debugging.
:meth:`drgn.Program.add_memory_segment()` defines a range of memory and how to
read that memory. The following example uses a Btrfs filesystem image as the
program "memory":
.. code-block:: python3
import drgn
import os
import sys
from drgn.cli import run_interactive
def btrfs_debugger(dev):
file = open(dev, 'rb')
size = file.seek(0, 2)
def read_file(address, count, offset, physical):
file.seek(offset)
return file.read(count)
platform = drgn.Platform(drgn.Architecture.UNKNOWN,
drgn.PlatformFlags.IS_LITTLE_ENDIAN)
prog = drgn.Program(platform)
prog.add_memory_segment(0, size, read_file)
prog.load_debug_info([f'/lib/modules/{os.uname().release}/kernel/fs/btrfs/btrfs.ko'])
return prog
prog = btrfs_debugger(sys.argv[1] if len(sys.argv) >= 2 else '/dev/sda')
print(drgn.Object(prog, 'struct btrfs_super_block', address=65536))
run_interactive(prog, banner_func=lambda _: "BTRFS debugger")
:meth:`drgn.Program.add_type_finder()` and
:meth:`drgn.Program.add_object_finder()` are the equivalent methods for
plugging in types and objects.
Environment Variables
---------------------
Some of drgn's behavior can be modified through environment variables:
``DRGN_MAX_DEBUG_INFO_ERRORS``
The maximum number of individual errors to report in a
:exc:`drgn.MissingDebugInfoError`. Any additional errors are truncated. The
default is 5; -1 is unlimited.
``DRGN_PREFER_ORC_UNWINDER``
Whether to prefer using `ORC
<https://www.kernel.org/doc/html/latest/x86/orc-unwinder.html>`_ over DWARF
for stack unwinding (0 or 1). The default is 0. Note that drgn will always
fall back to ORC for functions lacking DWARF call frame information and
vice versa. This environment variable is mainly intended for testing and
may be ignored in the future.
``DRGN_USE_LIBDWFL_REPORT``
Whether drgn should use libdwfl to find debugging information for core
dumps instead of its own implementation (0 or 1). The default is 0. This
environment variable is mainly intended as an escape hatch in case of bugs
in drgn's implementation and will be ignored in the future.
``DRGN_USE_LIBKDUMPFILE_FOR_ELF``
Whether drgn should use libkdumpfile for ELF vmcores (0 or 1). The default
is 0. This functionality will be removed in the future.
``DRGN_USE_SYS_MODULE``
Whether drgn should use ``/sys/module`` to find information about loaded
kernel modules for the running kernel instead of getting them from the core
dump (0 or 1). The default is 1. This environment variable is mainly
intended for testing and may be ignored in the future.
.. _kernel-special-objects:
Linux Kernel Special Objects
----------------------------
When debugging the Linux kernel, there are some special :class:`drgn.Object`\ s
accessible with :meth:`drgn.Program.object()` and :meth:`drgn.Program[]
<drgn.Program.__getitem__>`. Some of these are available even without debugging
information, thanks to metadata called "vmcoreinfo" which is present in kernel
core dumps. These special objects include:
``UTS_RELEASE``
Object type: ``const char []``
This corresponds to the ``UTS_RELEASE`` macro in the Linux kernel source
code. This is the exact kernel release (i.e., the output of ``uname -r``).
To use this as a Python string, you must convert it::
>>> release = prog["UTS_RELEASE"].string_().decode("ascii")
This is available without debugging information.
``PAGE_SIZE``
Object type: ``unsigned long``
``PAGE_SHIFT``
Object type: ``unsigned int``
``PAGE_MASK``
Object type: ``unsigned long``
These correspond to the macros of the same name in the Linux kernel source
code. The page size is the smallest contiguous unit of physical memory
which can be allocated or mapped by the kernel.
>>> prog['PAGE_SIZE']
(unsigned long)4096
>>> prog['PAGE_SHIFT']
(int)12
>>> prog['PAGE_MASK']
(unsigned long)18446744073709547520
>>> 1 << prog['PAGE_SHIFT'] == prog['PAGE_SIZE']
True
>>> ~(prog['PAGE_SIZE'] - 1) == prog['PAGE_MASK']
True
These are available without debugging information.
``jiffies``
Object type: ``volatile unsigned long``
This is a counter of timer ticks. It is actually an alias of ``jiffies_64``
on 64-bit architectures, or the least significant 32 bits of ``jiffies_64``
on 32-bit architectures. Since this alias is defined via the linker, drgn
handles it specially.
This is *not* available without debugging information.
``vmemmap``
Object type: ``struct page *``
This is a pointer to the "virtual memory map", an array of ``struct page``
for each physical page of memory. While the purpose and implementation
details of this array are beyond the scope of this documentation, it is
enough to say that it is represented in the kernel source in an
architecture-dependent way, frequently as a macro or constant. The
definition provided by drgn ensures that users can access it without
resorting to architecture-specific logic.
This is *not* available without debugging information.