So far we've been getting away with only unit testing through Python.
However, there's plenty of (existing and upcoming) internal code that
would be nice to unit test directly in C. For a framework, I opted for
check (https://libcheck.github.io/check/) because it is minimal, mature,
and available on all major distros. Add the autotools scaffolding,
including a copy of the checkmk script from check 0.15.2 since RHEL and
CentOS don't package it. We check the dependencies at configure time but
only fail if they're not available at `make check` time. Also wire up
`setup.py test` to run `make check`.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
The next change will use an annotation from _typeshed, which looks ugly
in the generated documentation. Let's strip it when appropriate.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
For screens that aren't terribly wide, there's a break point where the
current documentation design will snap to 50% width, and the text is
difficult to read due to the narrow layout. Rather than using 50% as the
rule, let's setup a couple good breakpoints that are wider than
Alabaster's default.
In particular, at the 875px breakpoint the sidebar appears, removing
220px from the content. So add a breakpoint at 875 + 220 px, allowing
the content width to grow up until that point, at which point we can cap
the width.
Fixes: 98cf8d51 ("docs: make page body wider")
Signed-off-by: Stephen Brennan <stephen@brennan.io>
For an upcoming case study, I want to link to Linux kernel source files
at specific line numbers, and I want it to be formatted as inline code.
The extlinks extension doesn't seem to support that easily, so let's add
our own small extension specifically for Linux kernel code.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
The Alabaster theme's body is awkwardly narrow, especially for code
blocks. Override the theme options with something wider that doesn't
look too overwhelming on large screens.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
The generated header causes confusion for some tooling. The only reason
we're generating it is to substitute the version number. For now, let's
just manually duplicate the version number from configure.ac. We could
probably do something fancier like what autoconf itself does [1], but
that looks much more involved than simply adding a step to my release
runbook.
Closes#375.
1: https://lists.gnu.org/archive/html/autoconf/2007-12/msg00027.html
Signed-off-by: Omar Sandoval <osandov@osandov.com>
A few people have told me that they frequently forget whether
stack_trace() is a Program method or a function. Now that we have a
default program, it can be both.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
To simplify converting helpers to allow omitting the prog argument, add
a couple of decorators that take care all of the messy details.
@takes_program_or_default is based on an example from Stephen Brennan,
and the rest handle progressively more complex calling conventions.
Also update drgndoc to be aware of these decorators and add some
boilerplate to the generated documentation.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
Some feedback that I've gotten that resonated with me was that it feels
silly and too verbose to always pass prog to helpers, like
for_each_task(prog), find_task(prog, pid), etc. Passing prog makes sense
from the library point of view, but it's not great for interactive
usability. And even when you include usage as a library, the vast
majority of use cases only need one program.
So, let's introduce the concept of the "default program". It has a
getter (get_default_prog()) and a setter (set_default_prog()). The CLI
sets it automatically. Library users can do it manually if they want to.
It is a per-thread setting.
Upcoming commits will update all of our helpers and functions that take
a Program to make it optional and default to the default program.
P.S. This was inspired by asyncio, which has many interfaces that take
an optional loop parameter but default to the current loop. Cf.
asyncio.get_event_loop() and asyncio.set_event_loop().
Signed-off-by: Omar Sandoval <osandov@osandov.com>
It needed the linux_helper_task_iterator update and a fix for
/proc/kcore upstream (fe2c34bab6d4 ("iov_iter: fix
copy_page_to_iter_nofault()")).
Signed-off-by: Omar Sandoval <osandov@osandov.com>
Every build_sphinx command does a full rebuild with the following log:
updating environment: [config changed ('project')] 14 added, 0 changed, 0 removed
It looks like Sphinx is comparing the config saved at the end of a run
to the config before the builder-inited event. Fix it by connecting to
the config-inited event first, which according to the Sphinx
documentation [1] happens earlier.
1: https://www.sphinx-doc.org/en/master/extdev/appapi.html#sphinx-core-events
Signed-off-by: Omar Sandoval <osandov@osandov.com>
Setting the env.ref_context["py:module"] is equivalent to the
py:currentmodule directive; it doesn't create index entries, so
references to module documentation generated with drgndoc don't work.
Generate an explicit py:module instead of doing it ourselves.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
Pyre apparently doesn't support __getattribute__, but it does support
__getattr__. Update the type stub to work around this limitation.
The actual implementation in the C extension uses tp_getattro, which is
essentially __getattribute__, but it tries the equivalent of
object.__getattribute__ first, so it's closer to __getattr__ in spirit.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
Sphinx normally makes type names in annotations links to the
documentation for that type, but this doesn't work for type aliases
(like drgn.Path). See sphinx-doc/sphinx#10785. Add a workaround inspired
by adafruit/circuitpython#8236.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
The replacements of * with [0], -> with ., and & with address_of_() are
documented in the Object class docstring, but they're important enough
that we should mention them in the user guide. Also expand the
documentation of __getitem__ and __getattribute__ to mention this.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
For Python-based object, type, and symbol finders, the vmcoreinfo is a
critical source of information. It can contain addresses necessary for
loading certain information (such as kallsyms). Expose this information
as a special object.
Signed-off-by: Stephen Brennan <stephen.s.brennan@oracle.com>
Rather than coming up with our own, separate logging API for the Python
bindings, let's integrate with the logging module. The straightforward
part is creating a logger from the C extension and adding a log callback
that calls its log() method. However, syncing the log level between the
logging module and libdrgn requires monkey patching.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
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>
It's quite useful to run drgn's interactive REPL from a user-provided
script. One reason is saving the drgn core dump and debuginfo setup into
a script to more easily start analysis. Another might be to replace
drgn's debuginfo loading scheme with one customized to a different
environment. Or, a script might want to handle errors by allowing an
interactive user to examine the program themselves.
To serve all of these cases and more, separate out the logic of running
the drgn REPL from the internal logic relating to argument parsing,
choosing the correct target, and loading debuginfo. While this may seem
like a simple case of code.interact, there are several important
internal features drgn provides in its CLI: a custom displayhook, a
custom readline completer, a history file, and of course the logic to
import and include the proper drgn APIs and helpers for a core dump.
This means creating a run_interactive() function and moving the cli
module out of the drgn.internal package.
Signed-off-by: Stephen Brennan <stephen.s.brennan@oracle.com>
The parameters of the read_file function in the example are swapped.
This matches the parameters order used by py_memory_read_fn.
Fixes: c0bc72b0ea ("libdrgn: use splay tree for memory reader")
Signed-off-by: Timothée Cocault <timothee.cocault@gmail.com>
drgn is able to lookup some special metadata for the Linux kernel,
sometimes even without debuginfo. For users who may expect that
Program.object() will only return objects corresponding to variables,
these metadata are unexpected and can be quite useful. Regardless,
they're currently undocumented. Add documentation under Advanced Usage
for these, and reference it in the Program.object() docstring.
Signed-off-by: Stephen Brennan <stephen.s.brennan@oracle.com>
I've been posting these internally at Meta for previous releases, but I
think others would find them useful, too. In the future, I'll write them
up before cutting the release.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
It's come up several times that it'd be nice to have somewhere to dump
drgn scripts that people write while debugging without requiring them to
be cleaned up and scrutinized in code review. Serapheim Dimitropoulos
noted that several projects have a "contrib" directory for this purpose.
See [1]. Let's create one, document it, exclude it from pre-commit, and
move our (mostly unmaintained) examples there.
1: https://drewdevault.com/2020/06/06/Add-a-contrib-directory.html
Signed-off-by: Omar Sandoval <osandov@osandov.com>
drgn is currently licensed as GPLv3+. Part of the long term vision for
drgn is that other projects can use it as a library providing
programmatic interfaces for debugger functionality. A more permissive
license is better suited to this goal. We decided on LGPLv2.1+ as a good
balance between software freedom and permissiveness.
All contributors not employed by Meta were contacted via email and
consented to the license change. The only exception was the author of
commit c4fbf7e589 ("libdrgn: fix for compilation error"), who did not
respond. That commit reverted a single line of code to one originally
written by me in commit 640b1c011d ("libdrgn: embed DWARF index in
DWARF info cache").
Signed-off-by: Omar Sandoval <osandov@osandov.com>
For the next fix, we need the address of the .data..percpu section,
which is only available directly from the struct module and not from
anywhere in /proc or /sys. Get rid of the /proc/modules fast path (and
update the name of the testing environment variable from
DRGN_USE_PROC_AND_SYS_MODULES to DRGN_USE_SYS_MODULE).
This has some small overhead (~20ms longer startup time in my
benchmarks) and means that we no longer determine the loaded modules if
vmlinux is missing, but fixing the per-CPU issue is more important.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
Replace the old "Scriptable debugger library" and
"Debugger-as-a-library" taglines with the one we're using on GitHub,
"Programmable debugger". Make up for it by emphasizing that drgn can
also be used as a library a tiny bit more in the README.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
Instead of adding type information to directive descriptions with the
:type:, :rtype:, and :vartype: fields, document types with type
annotations. For functions and methods, we add the type annotations to
the signature. For variables and attributes, we use the :type: option.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
Just picking up the newest version. Also fix the following warning:
WARNING: extlinks: Sphinx-6.0 will require a caption string to contain exactly one '%s' and all other '%' need to be escaped as '%%'.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
"Object finder" was renamed from "symbol finder" awhile ago, but we
forgot to update the advanced usage documentation.
Fixes: 0c5df56fba ("libdrgn: replace symbol index with object index")
Signed-off-by: Omar Sandoval <osandov@osandov.com>