drgn_object_truthiness() is a misnomer, as truthiness is a
language-specific concept. Instead, invert the return value and rename
it to drgn_object_is_zero(), which more accurately conveys the meaning.
Instead of having two internal variants (drgn_find_symbol_internal() and
drgn_program_find_symbol_in_module()), combine them into the former and
add a separate drgn_error_symbol_not_found() for translating the static
error to the user-facing one. This makes things more flexible for the
next change.
We'd like to have more control over how objects are formatted. I
considered defining a custom string format specification syntax, but
that's not easily discoverable. Instead, let's get rid of the current
format specification support and replace it with a normal method.
In preparation for making drgn_pretty_print_object() more flexible
(i.e., not always "pretty"), rename it to drgn_format_object(). For
consistency, let's rename drgn_pretty_print_type_name(),
drgn_pretty_print_type(), and drgn_pretty_print_stack_trace(), too.
Commit f327552229 ("libdrgn: add strstartswith()") flipped the test
for a name entry in modinfo. This introduced a regression resulting in
kernel modules not loading at the right offset. This patch fixes the
regression.
The previous commit was the real fix for the failed symbol lookups. On
the bright side, the build fixes were merged, so we can rebase on master
and drop those.
Based on:
277c2c54f libcpu: Compile i386_lex.c with -Wno-implicit-fallthrough
With the following patches:
configure: Add --disable-programs
configure: Add --disable-shared
libdwfl: add interface for attaching to/detaching from threads
libdwfl: cache Dwfl_Module and Dwarf_Frame for Dwfl_Frame
libdwfl: add interface for evaluating DWARF expressions in a frame
It turns out this wasn't a problem with dwfl_addrmodule() at all; the
real problem is that .init sections are freed once the module is loaded
but we're still considering them for the address range we pass to
dwfl_report_module(). Ignore those sections entirely (by omitting them
from the section name to section index map). While we're here, let's not
bother inserting non-SHF_ALLOC sections in the map.
This fixes the issue that Program.symbol() sometimes fails for kernel
module symbols.
Based on:
2c7c4037 elfutils.spec.in: Sync with fedora spec, remove rhel/fedora specifics.
With the following patches:
configure: Add --disable-programs
configure: Add --disable-shared
configure: Fix -D_FORTIFY_SOURCE=2 check when CFLAGS contains -Wno-error
libcpu: compile i386_lex.c with -Wno-implicit-fallthrough
libdwfl: add interface for attaching to/detaching from threads
libdwfl: cache Dwfl_Module and Dwarf_Frame for Dwfl_Frame
libdwfl: add interface for evaluating DWARF expressions in a frame
libdwfl: return error from __libdwfl_relocate_value for unloaded sections
libdwfl: remove broken coalescing logic in dwfl_report_segment
libdwfl: store module lookup table separately from segments
libdwfl: use sections of relocatable files for dwfl_addrmodule
For live userspace processes, we add a single [0, UINT64_MAX) memory
file segment for /proc/$pid/mem. Of course, not every address in that
range is valid; reading from an invalid address returns EIO. We should
translate this to a DRGN_ERROR_FAULT instead of DRGN_ERROR_OS, but only
for /proc/$pid/mem.
execscript() is supposed to behave more or less like the script was
typed in at the console. However, if the script raises an exception,
then the variables or functions it defines are not added to the calling
context, which can be pretty confusing.
The problem is that runpy.run_code() returns the new globals, so if it
raises an exception, then we can't get them. Fix it by doing the exec()
ourselves; we just need to do the same setup that runpy does.
In commit 55a9700435 ("libdrgn: python: accept integer-like arguments
in more places"), I converted Program_symbol to use index_converter but
forgot to initialize the struct index_arg. Then, in commit c243daed59
("Translate find_task() helper (and dependencies) to C"), I added a
bunch more cases of uninitialized struct index_arg. If
index_arg.allow_none gets a non-zero garbage value, then this can end up
allowing None through when it shouldn't. Furthermore, since commit
2561226918 ("libdrgn: python: add signed integer support to
index_converter"), if index_arg.is_signed gets a non-zero garbage value,
then this will try to get a signed integer when we're expecting an
unsigned integer, which can blow up for values >= 2**63 (like kernel
symbols). Fix it by initializing struct index_arg everywhere.
Fixes#30.
Not all architectures name the bootable image bzImage, so to make
supporting other architectures easier in the future, let's use the more
generic name, vmlinuz.
If I forget to git fetch, manage.py tries to build releases that don't
exist, which litters the repository with incomplete build-$release
directories. Verify that the commit exists before we do anything.
The vmtest shared folder just got large enough to be paginated, which
manage.py doesn't handle. Handle it by making the same XHR requests that
the webpage makes in a browser.
Rebase on 0.178. The only additional change needed is to pass
--disable-debuginfod to configure.
Based on:
2c7c4037 elfutils.spec.in: Sync with fedora spec, remove rhel/fedora specifics.
With the following patches:
configure: Add --disable-programs
configure: Add --disable-shared
configure: Fix -D_FORTIFY_SOURCE=2 check when CFLAGS contains -Wno-error
libcpu: compile i386_lex.c with -Wno-implicit-fallthrough
libdwfl: add interface for attaching to/detaching from threads
libdwfl: cache Dwfl_Module and Dwarf_Frame for Dwfl_Frame
libdwfl: add interface for evaluating DWARF expressions in a frame
Matt Ahrens reported that comparing two types would sometimes end up in
a seemingly infinite loop, which he discovered was because we repeat
comparisons of types as long as they're not in a cycle. Fix it by
caching all comparisons during a call.
Some tests (e.g., tests.test_object.TestSpecialMethods.test_round) are
printing:
DeprecationWarning: an integer is required (got type float). Implicit
conversion to integers using __int__ is deprecated, and may be removed
in a future version of Python.
See https://bugs.python.org/issue36048. This is coming from calls like:
Object(prog, 'int', value=1.5)
We actually want the truncating behavior, so explicitly call
PyNumber_Long().
Now that we have tests for kernel-specific functionality, we should run
them on various kernel versions. This adds a script for doing so using
QEMU with a pre-built root filesystem image and kernels that I'm hosting
on my Dropbox. The script can be run locally, but this also sets it up
to be run on Travis. For now, we're testing the mainline, stable, and
longterm releases from kernel.org (not including v3.16, which doesn't
even boot for me).
We currently have no test coverage for helpers. This is a problem, as
they can be fairly complicated and are susceptible to breaking with new
kernel versions. It's actually not too hard to test user-facing
subsystems on the running kernel as long as we're root and have debug
info for vmlinux, so let's add several tests for those. Specific data
structures will be a little trickier to test, so for now I'm not
covering those.
If we only want debugging information for vmlinux and not kernel
modules, it'd be nice to only load the former. This adds a load_main
parameter to drgn_program_load_debug_info() which specifies just that.
For now, it's only implemented for the Linux kernel. While we're here,
let's make the paths parameter optional for the Python bindings.
_follow_mount() needs to check that the parent mount matches like
__lookup_mnt() in the kernel, otherwise for
mount --bind /tmp/foo /tmp/foo
path_lookup(prog, '/tmp/foo') will loop forever.
d_path() for bind mounts returns the wrong path. E.g., for
mount --bind /tmp/foo /tmp/foo
print_mounts() shows '/tmp/foo/foo'. Let's do exactly what
prepend_path() in the kernel does, which fixes this case.
setuptools has a long-standing bug that if files are removed from the
list of sources but were included in a previous run of egg_info, they
remain in the generated list of sources (pypa/setuptools#436). This
affects egg_info and sdist. Let's work around this by removing the old
SOURCES.txt if we can recreate it from git.
This implements the first step at supporting C++: class types. In
particular, this adds a new drgn_type_kind, DRGN_TYPE_CLASS, and support
for parsing DW_TAG_class_type from DWARF. Although classes are not valid
in C, this adds support for pretty printing them, for completeness.
Python 3.8 replaced the unused void *tp_print field with Py_ssize_t
tp_vectorcall_offset, so with -Werror we get "error: initialization of
‘long int’ from ‘void *’ makes integer from pointer without a cast".
Let's just use designated initializers.
We currently don't check that the task we're unwinding is actually
blocked, which means that linux_kernel_set_initial_registers_x86_64()
will get garbage from the stack and we'll return a nonsense stack trace.
Let's avoid this by checking that the task isn't running if we didn't
find a NT_PRSTATUS note.
Add a helper to get the state of a task (e.g., 'R', 'S', 'D'). This will
be used to make sure that a task is not running when getting a stack
trace, so implement it in libdrgn.
When debugging the Linux kernel, it's inconvenient to have to get the
task_struct of a thread in order to get its stack trace. This adds
support for looking it up solely by PID. In that case, we do the
find_task() inside of libdrgn. This also gives us stack trace support
for userspace core dumps almost for free since we already added support
for NT_PRSTATUS.