I missed the drgn_program_set_kdump() code path when making sure that we
set the platform before adding memory segments.
Fixes: 0e3054a0ba ("libdrgn: make addresses wrap around when reading memory")
Signed-off-by: Omar Sandoval <osandov@osandov.com>
This workaround was originally present in commit e5874ad18a ("libdrgn:
use libdwfl"). We dropped in in commit 6a13d74c0c ("libdrgn: build
with bundled elfutils") because the bundled version of elfutils had the
fix. We forgot to bring it back in commit 4c5c5f3842 ("Remove bundled
version of elfutils") even though we support versions without the fix.
Reported-by: Serapheim Dimitropoulos <serapheim@delphix.com>
Signed-off-by: Omar Sandoval <osandov@osandov.com>
copy_lsbytes() doesn't copy enough bytes when copying from a smaller
little-endian value to a larger big-endian value. This was caught by the
test cases for DW_OP_deref{,_size}, but it can affect other places when
debugging a little-endian target from a big-endian host or vice-versa.
Closes#105.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
The stack trace variable work introduced a regression that causes
objects with size zero to always be marked absent even if they have an
address. This matters because GCC sometimes seems to omit the complete
array type for arrays declared without a length, so an array variable
can end up with an incomplete array type. I saw this with the
"swapper_spaces" variable in mm/swap_state.c from the Linux kernel.
Make sure to use the address of an empty piece if the variable is also
empty.
Fixes: ffcb9ccb19 ("libdrgn: debug_info: implement creating objects from DWARF location descriptions")
Signed-off-by: Omar Sandoval <osandov@osandov.com>
drgn depends heavily on libelf and libdw, so it's useful to know what
version we're using. Add drgn._elfutils_version and use that in the CLI
and in the test cases where we currently check the libdw version.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
After all of the preparatory work, the last two missing pieces are a way
to find a variable by name in the list of scopes that we saved while
unwinding, and a way to find the containing scopes of an inlined
function. With that, we can finally look up parameters and variables in
stack traces.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
If we want to access a parameter or local variable in an inlined
function, then we need a stack frame for that function. It's also much
more useful to see inlined functions in the stack trace in general. So,
when we've unwound the registers for a stack frame, walk the debugging
information to find all of the (possibly inlined) functions at the
program counter, and add a drgn stack frame for each of those.
Also add StackFrame.name and StackFrame.is_inline so that we can
distinguish inline frames. Also add StackFrame.source() to get the
filename and line and column numbers. Finally, add the source code
location to pretty-printed stack traces and add pretty-printing for
individual stack frames that includes extra information.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
This will be used for finding the ancestors of the abstract instance
root corresponding to a concrete inlined instance root for variable
lookups in inlined functions.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
This will be used for finding functions, inlined functions, and blocks
containing a PC for stack unwinding and variable lookups.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
We have a couple of upcoming use cases for iterating through all of the
DIEs in a module: searching for scopes and searching for a DIE's
ancestors. Add a DIE iterator interface to abstract away the details of
walking DIEs and allows us to efficiently track ancestors.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
Add support for evaluating a DWARF location description and translating
it into a drgn object. In this commit, this is just used for global
variables, but an upcoming commit will wire this up to stack traces for
parameters and local variables.
There are a few locations that drgn's object model can't represent yet.
DW_OP_piece/DW_OP_bit_piece can describe objects that are only partially
known or partially in memory; we approximate these where we can. We
don't have a good way to support DW_OP_implicit_pointer at all yet.
This also adds test cases for DWARF expressions, which we couldn't
easily test before.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
Implement looking up location descriptions and evaluating DW_OP_fbreg.
This isn't actually used yet since CFI expressions don't have a current
function DIE, but it will be used for parameters/local variables in
stack traces.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
It doesn't make a difference anywhere it's currently used, but let's do
it just in case that changes in the future.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
A malformed DWARF expression can easily get us into an infinite loop.
Avoid this by capping the number of operations that we'll execute.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
Define that addresses for memory reads wrap around after the maximum
address rather than the current unpredictable behavior. This is done by:
1. Reworking drgn_memory_reader to work with an inclusive address range
so that a segment can contain UINT64_MAX. drgn_memory_reader remains
agnostic to the maximum address and requires that address ranges do
not overflow a uint64_t.
2. Adding the overflow/wrap-around logic to
drgn_program_add_memory_segment() and drgn_program_read_memory().
3. Changing direct uses of drgn_memory_reader_reader() to
drgn_program_read_memory() now that they are no longer equivalent.
(For some platforms, a fault might be more appropriate than wrapping
around, but this is a step in the right direction.)
Signed-off-by: Omar Sandoval <osandov@osandov.com>
If the program already had a platform set, we should its callbacks
instead of the ones from the ELF file's platform.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
drgn.Program has supported the "in" operator since commit 25e7a9d3b8
("libdrgn/python: implement Program.__contains__"), but it's
undocumented and unannotated. Add a type annotation with a docstring
along with a METH_COEXIST method.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
libomp (at least in LLVM 9 and 10) seems to have buggy OpenMP tasking
support. See commit 1cc3868955 ("CI: temporarily disable Clang") for
one example. OpenMP tasks aren't buying us much; they simplify DWARF
index updates in some places but complicate it in others. Let's ditch
tasks and go back to building an array of CUs to index similar to what
we did before commit f83bb7c71b ("libdrgn: move debugging information
tracking into drgn_debug_info"). There is no significant performance
difference.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
First, add instructions for DW_FORM_indirect. Then, we can call the
function to convert a form to an instruction whenever we see an indirect
instruction.
Note that without elfutils commit d63b26b8d21f ("libdw: handle
DW_FORM_indirect when reading attributes") (queued for elfutils
0.184), DW_FORM_indirect will cause errors later when parsing with
libdw.
Signed-off-by: Jay Kamat <jaygkamat@gmail.com>
Rather than silently ignoring attributes whose form we don't recognize,
return an error. This way, we won't mysteriously skip indexing DIEs.
While we're doing this, split the form -> instruction mapping to its own
functions.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
I often use examples/load_debug_info to benchmark loading/DWARF
indexing, so add a -T option that prints the time it takes to load debug
info.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
When using type units, skeleton declarations are made instead of
concrete ones. However, these declarations have signature tags attached
that point to the type unit with the definition, so we can simply follow
the signature to get the concrete type.
Signed-off-by: Jay Kamat <jaygkamat@gmail.com>
Adds support for parsing of type units as enabled by
-fdebug-types-section. If a module has both a debug info section and
type unit section, both are read.
Signed-off-by: Jay Kamat <jaygkamat@gmail.com>
If the DIE passed to drgn_type_from_dwarf_internal() is a declaration,
then we overwrite it with dwarf_offdie(). As far as I can tell, this
doesn't break anything at the moment, but it's sketchy to overwrite an
input parameter and may cause issues in the future. Use a temporary DIE
on the stack in this case instead.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
CPython commit fb5db7ec5862 ("bpo-42006: Stop using PyDict_GetItem,
PyDict_GetItemString and _PyDict_GetItemId. (GH-22648)") (in v3.10)
removed _PyDict_GetItemId() because it suppresses errors. Use
_PyDict_GetItemIdWithError() instead (which we should've been using
anyways).
Closes#101.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
Using a Python dictionary for this is much more heavyweight than just
using a thread-local variable (with no benefit as far as I can tell).
This also gets rid of a call to _PyDict_GetItem().
Signed-off-by: Omar Sandoval <osandov@osandov.com>
/proc/pid/mem is indexed by address. On 32-bit systems, addresses may be
out of the range of a 32-bit signed off_t. This results in pread()
returning EINVAL in drgn_read_memory_file(). Use AC_SYS_LARGEFILE in
configure.ac so that we use 64-bit off_t by default.
Closes#98.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
We don't actually want make clean to remove the generated files that are
included in a distribution tarball, because then the user will need to
regenerate them, and they might not have the dependencies installed.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
GCC doesn't warn about table##_delete_iterator() being unused because it
is inline, but Clang does, so add the unused attribute.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
The folly implementation calls this elsewhere, but we only need it in
table##_chunk_mark_eof(), so it was folded in there.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
Clang enables -Wgnu-variable-sized-type-not-at-end by default, which
warns for DRGN_CFI_ROW():
arch_x86_64.c:735:27: warning: field 'row' with variable sized type 'struct drgn_cfi_row' not at the end of a struct or class is a GNU extension
[-Wgnu-variable-sized-type-not-at-end]
.default_dwarf_cfi_row = DRGN_CFI_ROW(
DRGN_CFI_ROW() is gnarly anyways, so instead of having it expand to a
pointer expression relying on this GCC extension, make it expand to an
initializer. Then, we can initialize default_dwarf_cfi_row as a separate
variable rather than directly in the initializer for struct
drgn_architecture_info.
This still relies on a GCC extension for static initialization of
flexible array members, but apparently Clang is okay with that one by
default (-Wgnu-flexible-array-initializer must be enabled explictly or
by -Wgnu or -Wpedantic).
Signed-off-by: Omar Sandoval <osandov@osandov.com>
See commit 0cb77b303c ("libdrgn: work around Clang __muloti4 again")
and commit 2dd14ad522 ("libdrgn: work around "undefined reference to
'__muloti4'" when using Clang"). These keep sneaking in because I don't
have an old enough version of Clang lying around.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
There are a couple of places where we compute `NULL + 0`, which is
undefined behavior. Add a helper to do this safely.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
drgn_object_reinit() and drgn_object_copy() can both load from an
uninitialized little_endian field, causing UBSan errors like:
libdrgn/object.h:105:27: runtime error: load of value 68, which is not a valid value for type '_Bool'
This only happens when little_endian isn't valid for the type and won't
be used anyways, but it's easy enough to work around.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
It's undefined behavior to pass NULL to memcpy() even if the length is
zero. See also commit a17215e984 ("libdrgn: dwarf_index: fix memcpy()
undefined behavior").
Signed-off-by: Omar Sandoval <osandov@osandov.com>
Building drgn from an sdist currently requires autotools and gawk
because libdrgn in the sdist is more or less a git checkout. It's more
user-friendly to include the autotools output and generated code. Do
this by extending the sdist command to include a full libdrgn
distribution with `make distdir`.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
The Linux kernel has its own stack unwinding format for x86-64 called
ORC: https://www.kernel.org/doc/html/latest/x86/orc-unwinder.html. It is
essentially a simplified, less complete version of DWARF CFI. ORC is
generated by analyzing machine code, so it is present for all but a few
ignored functions. In contrast, DWARF CFI is generated by the compiler
and is therefore missing for functions written in assembly and inline
assembly (which is widespread in the kernel).
This implements an ORC stack unwinder: it applies ELF relocations to the
ORC sections, adds a new DRGN_CFI_RULE_REGISTER_ADD_OFFSET CFI rule
kind, parses and efficiently stores ORC data, and translates ORC to drgn
CFI rules. This will allow us to stack trace through assembly code,
interrupts, and system calls.
Signed-off-by: Omar Sandoval <osandov@osandov.com>
To support unwinding with ORC, we need to apply relocations to
.orc_unwind_ip, which libdwfl doesn't do. That means that we always need
to apply relocations on x86-64, not just as a fast path when the file's
byte order matches the host's. So, generalize handling of 64- vs 32-bit
and little- vs big-endian relocations, and move the handling of
relocation types to an arch-specific callback.
Signed-off-by: Omar Sandoval <osandov@osandov.com>