Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/litevm.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
- uses: actions/setup-python@v4
name: Set up Python
with:
python-version: '3.x'
python-version: '3.12'
- name: Install pre-commit
run: pip install pre-commit
- name: Run pre-commit hooks
Expand Down Expand Up @@ -62,7 +62,7 @@ jobs:
- name: Build and install drgn with CTF support
run: |
cd ..
git clone https://github.com/brenns10/drgn -b ctf_0.0.32
git clone https://github.com/brenns10/drgn -b ctf_0.0.33
cd drgn
../drgn-tools/venv/bin/pip install .
- name: Run tests
Expand Down
122 changes: 72 additions & 50 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,77 +1,92 @@
# drgn-tools

drgn-tools is a library of helpers for use with [drgn][drgn]. It contains
helpers with a slightly reduced scope than what drgn itself can contain.

The main target for these helpers is the Oracle UEK kernel. Helpers may contain
code that assumes a UEK configuration and UEK architectures. This makes a lower
bar for acceptance than drgn, where helpers should be as configuration and
architecture agnostic as possible. In general, helpers should be contributed to
drgn itself, unless there is an Oracle UEK-specific reason to keep them here.

In addition to the helper functions, drgn-tools contains some helper utilities
that we find useful:

1. The `DRGN` script which can automatically download, extract, and load
debuginfo for UEK kernels.
2. The `corelens` tool, which contains a library of modules that can extract
information from a live kernel or vmcore, and write it to a sosreport-style
directory for later analysis.

Please note, each drgn-tools version is only supported with a corresponding
version of Drgn.

See the [documentation][doc] for more information on how to use these tools and
how to contribute to them.
drgn-tools is Oracle's set of helpers and tools based on [drgn][drgn], including
Corelens, our tool for generating summary reports of a vmcore or live system.

The main target for drgn-tools is the Oracle UEK kernel. Thus, it may assume
kernels with UEK configurations and architectures. This is different from drgn,
which aims to support a much broader set of configurations and architectures.
Where possible, we aim to contribute to drgn upstream first.

In addition to helper functions, drgn-tools contains some tools that we find
useful:

1. The `drgn_tools.cli` script which provides a CLI similar to drgn's, with our
helpers imported.
2. The `corelens` tool (`drgn_tools.corelens`), which contains a library of
modules that can extract information from a live kernel or vmcore, and write
it to a sosreport-style directory for later analysis. You can learn more
about Corelens in [this article][blog-corelens].

Drgn-tools also contains logic that can help automatically fetch & extract
Oracle Linux kernel debuginfo, as well as configure and load Compact Type Format
(CTF) for supported UEK kernels. This makes using tools like Corelens and the
CLI seamless on OL, frequently not even requiring installation of debuginfo
packages. You can learn more about CTF in [this article][blog-ctf].

## Getting Started

Requires Python 3.6 or later, and an Linux system (preferably Oracle Linux 8 or
later). For this guide, we'll assume you have a core dump (vmcore).
Oracle Linux users should consult the Oracle Linux Documentation section
entitled "Installing drgn-tools" for the most up-to-date instructions: [OL 8][],
[OL 9][], [OL 10][]. To summarize, enable the Add-ons channel, and then install
the `drgn-tools` package. For example:

1. Install Drgn, if you haven't already: `pip install drgn`. Alternatively, `yum
install drgn`, or use your system's package manager, if appropriate.
2. Clone the repository: `git clone
https://github.com/oracle-samples/drgn-tools`
``` sh
dnf config-manager --enable ol10_addons
dnf install drgn-tools
```

That's it! See below for ways to use drgn-tools.
For other users, or those interested in running from source: Drgn-tools requires
Python 3.6 or later, and drgn 0.0.32 or later. These can be installed from your
OS package manager preferably, or via pip, uv, etc. Once installed, you can
clone `drgn-tools` with git and start running against your kernel.

## Documentation

You can find documentation for the helpers, as well as contributing guide and
guide to using our tools, [here](https://oracle-samples.github.io/drgn-tools/).
Documentation for usage of drgn & drgn-tools can be found in the Oracle Linux
Documentation section entitled ["Debugging the Kernel with Drgn and
Corelens"][ol10doc].

## Examples
You can find some automatically generated documentation of the helpers, as well
as contributing guide and guide to using our tools,
[here](https://oracle-samples.github.io/drgn-tools/). Please note that this site
is not always fully up-to-date, and content here reflects internal
implementation details not supported by Oracle.

One of the benefits of using drgn-tools, in addition to the added UEK-specific
helpers, is the ability to fetch debuginfo directly from the Oracle debuginfo
Yum server. To enable this, you should put the following contents in
`~/.config/drgn_tools.ini`:

``` ini
[debuginfo]
fetchers = OracleLinuxYumFetcher
```
## Examples

With that, you can use the drgn-tools CLI with:
Use Corelens to generate a report of the running kernel. Output is written to a
directory named "output":

``` sh
python -m drgn_tools.cli VMCORE
corelens /proc/kcore -a -o output
```

To run it against the running kernel, use:
The above command uses the Corelens binary installed to the system. If you have
cloned the drgn-tools source code, you could instead run this command from the
git repository root:

``` sh
python -m drgn_tools.cli /proc/kcore
python -m drgn_tools.corelens /proc/kcore -a -o output
```

Use the drgn-tools Corelens system (which outputs a range of information from
several diagnostic systems):
One of the benefits of using drgn-tools, in addition to the added UEK-specific
helpers, is the ability to fetch debuginfo directly from the Oracle debuginfo
Yum server. Corelens and the drgn-tools CLI enable this automatically, but when
drgn-tools is installed, you can use it with drgn too:

``` sh
python -m drgn_tools.corelens VMCORE
# Use CTF (on Oracle Linux with UEK)
drgn -c /proc/kcore --try-symbols-by=ctf

# Download and extract debuginfo RPMs for Oracle Linux
drgn -c /proc/kcore --try-symbols-by=ol-download
```

Downloaded debuginfo is stored in a directory `~/vmlinux_repo` by default. You
can configure this and many other aspects of debuginfo finding and loading in
`/etc/drgn_tools.ini` or `~/.config/drgn_tools.ini`.

## Help

If you're having trouble using drgn-tools or its helpers, please create a Github
Expand All @@ -96,10 +111,17 @@ vulnerability disclosure process.

## License

Copyright (c) 2023 Oracle and/or its affiliates.
Copyright (c) 2023-2025 Oracle and/or its affiliates.

Released under the Universal Permissive License v1.0 as shown at
<https://oss.oracle.com/licenses/upl/>.

[drgn]: https://drgn.readthedocs.io
[doc]: https://oracle-samples.github.io/drgn-tools/
[OL 8]: https://docs.oracle.com/en/operating-systems/oracle-linux/8/drgn/installing_drgn_tools.html
[OL 9]: https://docs.oracle.com/en/operating-systems/oracle-linux/9/drgn/installing_drgn_tools.html
[OL 10]: https://docs.oracle.com/en/operating-systems/oracle-linux/10/drgn/installing_drgn_tools.html
[drgn plugin]:https://drgn.readthedocs.io/en/latest/advanced_usage.html#writing-plugins
[blog-corelens]: https://blogs.oracle.com/linux/corelens-a-microscope-for-your-vmcores
[blog-ctf]: https://blogs.oracle.com/linux/introducing-ctf-support-in-drgn-for-oracle-linux
[ol10doc]: https://docs.oracle.com/en/operating-systems/oracle-linux/10/drgn/about_drgn_and_corelens.html
25 changes: 23 additions & 2 deletions buildrpm/python-drgn-tools.spec
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@


Name: python-drgn-tools
Version: 2.1.0
Version: 2.2.0
Release: 1%{?dist}
Summary: Helper scripts for drgn, containing the corelens utility

Expand Down Expand Up @@ -59,7 +59,7 @@ a running kernel image (via /proc/kcore).}
# The drgn dependency can be fulfilled by drgn with, or without, CTF support.
# However, drgn-tools is tied to specific drgn releases.
%global drgn_min 0.0.32
%global drgn_max 0.0.33
%global drgn_max 0.0.34

%package -n drgn-tools
Summary: %{summary}
Expand Down Expand Up @@ -135,6 +135,27 @@ rm %{buildroot}/usr/bin/DRGN
%endif

%changelog
* Tue Nov 04 2025 Stephen Brennan <[email protected]> - 2.2.0-1
- Rework drgn-tools debuginfo loading to be based on drgn's Module API (Stephen Brennan)
- Create "oracle" drgn plugin which encapsulates drgn-tools debuginfo logic (Stephen Brennan)
- New corelens module: "pstack" for printing userspace stack traces (Stephen Brennan)
- Corelens module: equivalent to oled memstate [Orabug: 37357348] (Yassine Larhrissi)
- Corelens fails accessing rds_ib_devices [Orabug: 37502613] (Stephen Brennan)
- Print ioeventfd, iobus, vmstat and vcpustat information in kvm corelens module. [Orabug: 37713468] (Siddhi Katage)
- crash in corelens rds module [Orabug: 38225228] (Stephen Brennan)
- test_dump_page_cache_pages_pinning_cgroups produces too much output [Orabug: 37974100] (Stephen Brennan)
- Test failure for module_build_id() in Linux 6.14 [Orabug: 37973187] (Stephen Brennan)
- False negatives in module debuginfo detection [Orabug: 37894875] (Stephen Brennan)
- Make md helper not crash with uninitialized percpu refcount [Orabug: 37968889] (Junxiao Bi)
- UEK8, drgn-tools-2.1.0-1.el9.noarch : Error with corelens binary when run with /proc/kcore or vmcore [Orabug: 37894852] (Stephen Brennan)
- drgn-tools-2.1.0-1.el9: python traceback when ctrl-c done with corelens command [Orabug: 37894865] (Stephen Brennan)
- Mountinfo fails on a (nearly) empty struct mount [Orabug: 37911508] (Stephen Brennan)
- lockup: detect the blocker for process hang in RCU grace period [Orabug: 37899681] (Richard Li)
- Add vectorinfo module to drgn_tools [Orabug: 38383772] (Srivathsa Dara)
- corelens: dump panic bt [Orabug: 38074929] (Richard Li)
- Enhance rds helper to extract rdma resources and RDS QP state [Orabug: 38221449] (Anand Khoje)
- Add sosreport module for collecting corelens reports (Anil Palakunnathu Kunnengeri)

* Thu Apr 17 2025 Stephen Brennan <[email protected]> - 2.1.0-1
- Add helper and module for unsubmitted pending work (Imran Khan)
- Add -V option to display version, and include the version in corelens reports (Stephen Brennan) [Orabug: 37503503]
Expand Down
49 changes: 49 additions & 0 deletions drgn_tools.ini
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,18 @@
# These configurations affect the behavior of the Oracle plugin and its debug
# info finders. They specify paths and how the finders behave. However, they do
# not control *which* finders get enabled or when.
#
# Paths here will be formatted using Python's str.format() function, with the
# following string keys available:
#
# - bits: 32 or 64 depending on the architecture of the kernel
# - rpm: the name of the debuginfo RPM for this kernel version
# - ol_version, olver: the "major version" of Oracle Linux for that kernel
# - arch: the architecture string from the kernel release string
# - uname: the kernel release string
# - vmcore_path: the original path of the core dump
#
# Further string keys can be defined using "expansions", see that section below.

# Controls the path where drgn-tools searches for DWARF debuginfo, and where it
# would extract the files from a debuginfo RPM. This path does not need to
Expand Down Expand Up @@ -71,3 +83,40 @@
# ol-local-rpm, and ol-download, as well as drgn's "standard" finder.
#
# disable_dwarf = false

[extractions]

# Extractions are an uncommonly used feature, which add flexibility for
# constructing paths. The string configurations above, such as vmlinux_repo,
# rpm_path_format, and urls, each can specify an important path for finding
# debuginfo. They are able to use Python formatting strings, using pre-defined
# fields related to the kernel version and vmcore path.
#
# However, in some cases the path can't be determined just from the kernel
# version or vmcore_path. For example, one requirement might be storing the
# debuginfo in a subdirectory adjacent to the vmcore. For such a requirement,
# you could use an expansion to achieve it.
#
# Expansions define a new field, and they must be of the form:
#
# new_field = old_field:default_value:regex
#
# Where:
# old_field: the name of the field you're extracting text from
# default_value: the value to use for the new_field if old_field doesn't
# exist or the regex does not match
# regex: a regular expression pattern. Group number 1 from this regex will
# be used for the new_field value.
#
# For example, the following extracts the directory containing the vmcore to a
# new field named vmcore_dir. If for any reason the extraction could not work,
# we fall back to "/var/tmp/" for safety:
#
# [extractions]
# vmcore_dir = vmcore_path:/var/tmp/:^(.*/)[^/]+$
#
# With this, you can specify that debuginfo should be extracted adjacent to the
# vmcore, or even in the same directory:
#
# vmlinux_repo = {vmcore_dir}/debuginfo
# vmlinux_repo = {vmcore_dir}
3 changes: 2 additions & 1 deletion drgn_tools/block.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
from drgn.helpers.linux.device import MAJOR
from drgn.helpers.linux.device import MINOR
from drgn.helpers.linux.list import list_for_each_entry
from drgn.helpers.linux.timekeeping import ktime_get_coarse_ns
from drgn.helpers.linux.xarray import xa_for_each

from drgn_tools.bitops import for_each_bit_set
Expand Down Expand Up @@ -337,7 +338,7 @@ def rq_pending_time_ns(rq: Object) -> int:
if has_member(rq, "start_time"):
return (prog["jiffies"] - rq.start_time).value_() * 1000000
elif has_member(rq, "start_time_ns"):
base = prog["tk_core"].timekeeper.tkr_mono.base
base = ktime_get_coarse_ns(prog)
delta = base - rq.start_time_ns
return delta.value_() if base > rq.start_time_ns else 0
else:
Expand Down
7 changes: 5 additions & 2 deletions drgn_tools/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,7 @@ def main() -> None:

prog = Program()
prog.cache["drgn_tools.debuginfo.options"] = opts
prog.cache["drgn_tools.debuginfo.vmcore_path"] = args.vmcore
try:
prog.set_core_dump(args.vmcore)
except PermissionError:
Expand Down Expand Up @@ -144,8 +145,10 @@ def main() -> None:

if prog.cache.get("using_ctf"):
db_kind = "CTF"
db_file = prog.cache.get("ctf_file", "(unknown)")
else:
db_kind = f"DWARF: {prog.main_module().debug_file_path}"
db_kind = "DWARF"
db_file = prog.main_module().debug_file_path

def banner_func(banner: str) -> str:
header = version_header()
Expand All @@ -154,7 +157,7 @@ def banner_func(banner: str) -> str:
imports = "\n"
for mod_name, names in CLI_HELPERS.items():
imports += f">>> from {mod_name} import {', '.join(names)}\n"
db_info = f"Using {db_kind}"
db_info = f"Using {db_kind}: {db_file}"
db_info += "\n" + str(get_module_load_summary(prog))
return (
header
Expand Down
19 changes: 14 additions & 5 deletions drgn_tools/corelens.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
from drgn_tools.logging import FilterMissingDebugSymbolsMessages
from drgn_tools.module import get_module_load_summary
from drgn_tools.util import redirect_stdout
from drgn_tools.util import redirectable


log = logging.getLogger("corelens")
Expand Down Expand Up @@ -360,6 +361,7 @@ def _load_prog_and_debuginfo(args: argparse.Namespace) -> Program:

prog = Program()
prog.cache["drgn_tools.debuginfo.options"] = opts
prog.cache["drgn_tools.debuginfo.vmcore_path"] = args.vmcore
try:
prog.set_core_dump(args.vmcore)
except PermissionError:
Expand Down Expand Up @@ -729,8 +731,13 @@ def _do_main() -> None:
load_time = time.time() - start_time

log.info("%s", _version_string())
kind = "CTF" if prog.cache.get("using_ctf") else "DWARF"
log.info("Loaded %s debuginfo in in %.03fs", kind, load_time)
if prog.cache.get("using_ctf"):
kind = "CTF"
db_file = prog.cache.get("ctf_file", "(unknown)")
else:
kind = "DWARF"
db_file = prog.main_module().debug_file_path
log.info("Loaded %s debuginfo (%s) in in %.03fs", kind, db_file, load_time)
log.debug(
"Enabled debuginfo finders: %r", prog.enabled_debug_info_finders()
)
Expand Down Expand Up @@ -765,7 +772,8 @@ def main() -> None:
pass


def run(prog: Program, cl_cmd: str) -> None:
@redirectable
def run(prog: Program, cl_cmd: str, outfile: Optional[str] = None) -> None:
"""
Run a single corelens command

Expand All @@ -775,6 +783,7 @@ def run(prog: Program, cl_cmd: str) -> None:
against ``prog``.

:param cl_cmd: command string to execute
:param outfile: filename to redirect output to (see @redirectable)
"""
cmd = shlex.split(cl_cmd)
module_name, args = cmd[0], cmd[1:]
Expand All @@ -800,8 +809,8 @@ def make_runner(prog: Program) -> Callable[[str], None]:
argument. This is intended for interactive environments.
"""

def cl(cl_cmd: str) -> None:
return run(prog, cl_cmd)
def cl(cl_cmd: str, outfile: Optional[str] = None) -> None:
return run(prog, cl_cmd, outfile=outfile)

return cl

Expand Down
Loading
Loading