Commit Graph

474 Commits

Author SHA1 Message Date
Stephen Brennan
7e8c5d7bb2 tests: Fix print_annotated_memory test on SLOB
The test for print_annotated_memory() shouldn't assert anything when
CONFIG_SLOB is enabled, because we can't find slab objects. However, the
test shouldn't be skipped entirely, because print_annotated_memory()
should run without error in this case. Skip the assertion only.

Fixes: c7717280 ("helpers.common.memory: add print_annotated_memory() helper")

Signed-off-by: Stephen Brennan <stephen.s.brennan@oracle.com>
2024-07-18 19:14:48 -07:00
Stephen Brennan
de8ba223de Add linux kernel module helpers
There are a few common use cases that I find myself re-writing:
iterating over the list of modules, looking up a module by name, and
getting memory addresses related to modules (or vice versa). Add helpers
for each.

Signed-off-by: Stephen Brennan <stephen.s.brennan@oracle.com>
2024-07-12 20:01:52 -07:00
Sourabh Jain
c6efb6ecff tests/linux_kernel: Skip TestStackDepot unless test kmod is present
TestStackDeport needs the drgn test kernel module, so if it is not
present, skip the test.

Signed-off-by: Sourabh Jain <sourabhjain@linux.ibm.com>
2024-07-12 09:34:34 -07:00
Omar Sandoval
a991bd523b tests: require full MM support for print_annotated_memory() test
Full MM support is required to identify slab objects.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-06-18 12:20:48 -07:00
Omar Sandoval
45c67be431 drgn.helpers.linux.block: add bdev_partno() helper to fix for_each_disk() for Linux 6.10
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-06-05 15:35:45 -07:00
Omar Sandoval
2d8aeacb30 Allow naming and configuring order of object finders
This one doesn't need any changes to the callback signature, just the
new interface. We also keep add_object_finder() for compatibility.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-06-05 13:40:26 -07:00
Omar Sandoval
5c9797a633 Allow naming and configuring order of type finders
Like for symbol finders, we want extra flexibility around configuring
type finders. The type finder callback signature also has a couple of
warts: it doesn't take the program since it was added before types
needed to be constructed from a program, and it is called separately for
each type kind since originally type lookups were for only one kind.
While we're adding a new interface, let's fix these warts: pass the
program and a set of type kinds. However, we need to keep the old
add_type_finder() interface for backwards compatibility.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-06-05 13:40:26 -07:00
Omar Sandoval
9b73b44908 python: add TypeKindSet
C type finders are passed a bitset of type kinds, but Python type
finders currently get called for each type kind. An upcoming update to
the type finder interface will fix this, but we need a set of TypeKinds,
and we'd rather not construct a real Python set for it. Instead, add a
TypeKindSet bitset that satisfies the collections.abc.Set interface.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-06-05 13:40:26 -07:00
Omar Sandoval
f20b41c8c0 Allow naming and configuring order of symbol finders
Currently, the bare-bones add_symbol_finder() interface only allows
adding a symbol finder that is called before any existing finders. It'd
be useful to be able to specify the order that symbol finders should be
called in and to selectively enable and disable them. To do that, we
also need finders to have a name to identify them by. So, replace
add_symbol_finder() (which hasn't been in a release yet) with a set of
interfaces providing this flexibility: register_symbol_finder(),
set_enabled_symbol_finders(), registered_symbol_finders(), and
enabled_symbol_finders(). Also change the callback signature to take the
program.

In particular, this flexibility will be very useful for a plugin system:
pre-installed plugins can register symbol finders that the user can
choose to enable or disable.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-06-05 13:40:26 -07:00
Omar Sandoval
af890a3199 Translate path_iterator tests to C unit tests
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-04-26 14:53:53 -07:00
Omar Sandoval
7d251fee6e Translate C lexer tests to C unit tests
This allows us to get rid of a bunch of exports and ctypes wrappers.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-04-26 14:53:53 -07:00
Omar Sandoval
04ee3c3ec7 Translate tests/test_lexer.py to C unit test
To try out our new testing framework, move some simple Python unit tests
for the internal lexer API to C unit tests.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-04-26 14:53:53 -07:00
Omar Sandoval
6ae88a0b90 tests: fix -Wmissing-prototypes warning in drgn_test kmod
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-04-04 16:21:30 -07:00
Omar Sandoval
31539d1bd5 tests: test member_at_offset() on padding in nested structs/array elements
I thought I had forgotten to handle these cases. Turns out I handled
them, but I didn't have test cases for them.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-04-04 16:20:58 -07:00
Omar Sandoval
a8551604ae helpers.common.type: add member_at_offset() helper
This is basically the opposite of offsetof(). I've wanted it to figure
out what member an offset returned by slab_object_info() or
identify_address() corresponds to.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-04-04 15:17:04 -07:00
Omar Sandoval
bbbbf0262b helpers.common.memory: recognize vmap stacks in identify_address()
Vmap stacks are an important special case of vmap.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-04-03 01:54:11 -07:00
Omar Sandoval
48e0c51b0a helper.common.memory: recognize vmap addresses in identify_address()
This requires rearranging a couple of things: symbols from modules are
also vmap addresses, so we need to check for symbols first, and we need
to open-code slab_object_info to avoid some redundant operations.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-04-03 01:41:35 -07:00
Omar Sandoval
ab0dd37509 helpers.linux.mm: add find_vmap_area() and for_each_vmap_area()
These can be used to look at vmap/vmalloc allocations.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-04-03 01:39:32 -07:00
Omar Sandoval
c7717280ad helpers.common.memory: add print_annotated_memory() helper
This is similar to print_annotated_stack() except that it works on an
arbitrary memory range. It's useful for trying to find some context in
mystery memory.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-04-03 01:39:32 -07:00
Omar Sandoval
24b53f2702 tests: add infrastructure for test resources
We currently only have one test resource file, sample.coredump.zst, but
the tests for #332 will add more. Create a package, tests.resources, to
contain test resources and a function, get_resource(), to decompress
them. It can also be used on the command line:

  python3 -m tests.resources $resource_name

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-03-22 16:12:05 -07:00
Stephen Brennan
f96a3f59e0 Add test for Symbol Finder API
Specify a "fake" symbol finder and then test that its results are
plumbed through the API successfully. While this is a contrived test, it
helps build confidence in the plumbing of the API.

Signed-off-by: Stephen Brennan <stephen.s.brennan@oracle.com>
2024-03-11 16:43:43 -07:00
Stephen Brennan
d1ebf5e9fe python: Allow construction of Symbol objects
Previously, Symbol objects could not be constructed in Python. However,
in order to allow Python Symbol finders, this needs to be changed.
Unfortunately, Symbol name lifetimes are tricky to manage. We introduce
a lifetime enumeration to handle this. The lifetime may be "static",
i.e. longer than the life of the program; "external", i.e. longer than
the life of the symbol, but no guarantees beyond that; or "owned", i.e.
owned by the Symbol itself.

Symbol objects constructed in Python are "external". The Symbol struct
owns the pointer to the drgn_symbol, and it holds a reference to the
Python object keeping the name valid (either the program, or a PyUnicode
object).

The added complexity is justified by the fact that most symbols are from
the ELF file, and thus share a lifetime with the Program. It would be a
waste to constantly strdup() these strings, just to support a small
number of Symbols created by Python code.

Signed-off-by: Stephen Brennan <stephen.s.brennan@oracle.com>
2024-03-11 16:43:43 -07:00
Omar Sandoval
f4e43ddf14 tests: hack around crashed thread stack trace test failures on s390x
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-03-08 15:23:40 -08:00
Omar Sandoval
bab4f43d68 tests: replace fork_and_sigwait() and fork_and_call() with fork_and_stop()
Before Linux kernel commit 4e57a4ddf6b0 ("ARM: 9107/1: syscall: always
store thread_info->abi_syscall") (in v5.15), on Arm, the syscall number
in /proc/<pid>/syscall is unreliable unless the process is being traced.
fork_and_sigwait() relies on this to detect when the created process has
scheduled out for good. Instead, we can have the created process raise
SIGSTOP and wait for it to be stopped. This is simpler and also doesn't
require us to care about the sigwait syscall numbers. While we're
reworking it, let's also consolidate it with fork_and_call().
test_task_state_to_char() can't use the new function because it wants
the function to sleep, then stop, then die, but it's easy enough to
open-code that one special case.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-03-08 11:57:29 -08:00
Omar Sandoval
fca8b9859d tests: disable get_kconfig() test on Arm
elfutils commit c1c1c06e30f0 ("libebl: Add ebl_func_addr_mask plus ARM
backend implementation.") has a bug that I haven't gotten around to
fixing: it masks the least significant bit of all symbol values, not
just function symbol values. This breaks the get_kconfig() helper: if
the kernel_config_data_end symbol value is odd, then the length of the
compressed config data is truncated by one byte and gzip decompression
fails. Disable the test on Arm until we get it fixed.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-03-08 11:57:29 -08:00
Omar Sandoval
a0a86364a8 libdrgn: memory_reader: indicate when fault is for physical memory
It can be confusing and misleading to see a FaultError for a strange
address that is actually physical.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-03-08 02:23:30 -08:00
Omar Sandoval
a5da128bb1 tools/fsrefs.py: check for references from uprobes
This one is pretty involved to implement and to test.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-03-06 16:18:45 -08:00
Omar Sandoval
3272a62f3b tools/fsrefs.py: check for references from swap files
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-03-06 16:18:45 -08:00
Omar Sandoval
9cf7768ce8 tools/fsrefs.py: check for references from loop devices
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-03-06 16:18:45 -08:00
Omar Sandoval
bb61dc78a0 tools/fsrefs.py: check for references from binfmt_misc
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-03-06 16:18:45 -08:00
Omar Sandoval
71da69c9c4 tests: add fork_and_call()
Like fork_and_sigwait(), but returns the called function's return value,
and only waits for the function to return, not sigwait.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-03-06 16:18:45 -08:00
Omar Sandoval
bb137f1887 tools/fsrefs.py: add mode to find references to a filesystem/super block
In this mode, we print the paths of the referenced files. Now that we
have multiple "checks" we're doing, also add an option to enable or
disable specific checks.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-03-06 16:18:45 -08:00
Omar Sandoval
8aa998035a helpers.linux.idr: add idr_for_each_entry()
This is a convenience wrapper around idr_for_each() and a cast.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-03-05 10:43:03 -08:00
Omar Sandoval
0562be06cb helpers.linux: add plist helpers
I ran into plists in the swap code, but they're also used in the
real-time scheduler and futexes. The helpers are trivial wrappers around
the list helpers.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-03-05 10:27:31 -08:00
Omar Sandoval
9d53e65414 tools: add fsrefs.py
My team and I have investigated many issues that turned out to be caused
by a stray reference to a file or filesystem, either by user error or
due to a kernel bug. Userspace tools like lsof and fuser can't find all
of these. This adds a drgn-based tool similar to lsof/fuser. This
initial version only checks the basics: file descriptors, task working
directories, task root directories, task executables, and VMAs. Upcoming
changes will check additional, more obscure places.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-03-01 13:06:30 -08:00
Omar Sandoval
a337e9f45f tests: use virtio-blk instead of loop for Linux block helper tests
Now that we enable CONFIG_VIRTIO_BLK in our kconfig, there's no need to
use a loop device. Configure a virtio-blk device in vmtest.vm so that
the block helper tests have a disk to test with.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-03-01 10:55:31 -08:00
Omar Sandoval
586ca27436 tests: allow fork_and_sigwait() to pass arguments to function
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-02-29 21:58:44 -08:00
Omar Sandoval
5ea7704609 tests: add a test case for stack_depot_fetch()
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-01-14 00:31:08 -08:00
Omar Sandoval
21cfb0436e tests: add a test case for stack_trace_from_pcs()
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-01-14 00:30:54 -08:00
Omar Sandoval
d1ffd581bd libdrgn: allow reinterpreting primitive scalar values
We don't allow this because "value objects with a scalar type cannot be
reinterpreted, as their memory layout in the program is not known". That
doesn't really make sense: we already support reconstructing the
in-memory representation with drgn_object_read_bytes().

Implement this by making drgn_object_slice() support slicing all
objects, using drgn_object_read_bytes() when necessary, then make
drgn_object_reinterpret() a trivial wrapper around it.

Closes #378.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2024-01-12 15:50:23 -08:00
Omar Sandoval
e6f43c90d2 drgn.helpers.linux.mm: add vma_find()
Just like we have the higher-level for_each_vma() on top of
mt_for_each(). For now, it only does a point query. We may want to
extend it to allow for range queries like the kernel's vma_iterator.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2023-11-30 22:20:22 -08:00
Omar Sandoval
38939cce5e helpers: add decorators to use the default program
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>
2023-11-30 14:44:51 -08:00
Omar Sandoval
20dad39000 Add interface for "default program"
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>
2023-11-30 14:44:51 -08:00
Omar Sandoval
8c7927413b tests: add test for cmdline() and environ() on kernel threads
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2023-11-29 16:44:57 -08:00
Omar Sandoval
9f9f945a31 tests: expose _AssertIdenticalWrapper as IdenticalMatcher
This is for upcoming tests using the
unittest.mock.Mock.assert_called_with() family of functions, which
compares with ==.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2023-11-08 13:24:11 -08:00
Omar Sandoval
60a289fdff tests: make identical() stricter
Require exact type matches, not subclasses, and fail hard for types we
don't explicitly handle. This caught one place where we weren't testing
what we thought we were.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2023-11-08 13:18:44 -08:00
Imran Khan
79a1ea2a33 tests: add tests for waitqueue helpers.
Signed-off-by: Imran Khan <imran.f.khan@oracle.com>
2023-11-06 11:26:44 -08:00
Omar Sandoval
9a45af4ec7 libdrgn: stack_trace: check for PRSTATUS note earlier
There's no reason to go through the trouble of checking the task_struct
if we were given a PRSTATUS note; it must be a thread that was running
at the time of the core dump. Refactor drgn_get_initial_registers() so
that we can use PRSTATUS earlier.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2023-10-30 23:22:17 -07:00
Omar Sandoval
eab64bdbc4 drgn.helpers.linux.mm: add for_each_vma() helper
This takes care of the transition from the VMA linked list to maple
trees for users.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2023-10-30 13:09:21 -07:00
Omar Sandoval
e4100db4d5 drgn.helpers.linux: add maple tree helpers
Maple trees have been around and used for VMAs for almost a year now
(since Linux 6.1). Finally add helpers and tests for them.

Closes #261.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2023-10-30 13:09:19 -07:00