Commit Graph

471 Commits

Author SHA1 Message Date
Omar Sandoval
26001733f6 libdrgn: debug_info: support DWARF 5 location lists
The DWARF 5 format is a little more complicated than DWARF 2-4 but
functionally very similar.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-07-09 01:52:08 -07:00
Omar Sandoval
215f7d79d7 libdrgn: debug_info: implement DW_OP_{addr,const}x
These were added in DWARF 5. They need to know the CU that they're being
evaluated in, but the parameters for drgn_eval_dwarf_expression() were
already getting unwieldy. Wrap the evaluation context in a new struct
drgn_dwarf_expression_context, add the additional CU information, and
implement the operations.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-07-09 01:52:08 -07:00
Omar Sandoval
81053a1c57 libdrgn: dwarf_index: support DWARF 5
The main changes are:

1. Skipping the new attribute forms.
2. Handling DW_FORM_strx*, DW_FORM_line_strp, and DW_FORM_implicit_const
   for the attributes that we care about.
3. Parsing the new unit header format.
4. Parsing the new line number program header format.

Note that Clang currently produces an incorrect DWARF 5 line number
program header for the Linux kernel (https://reviews.llvm.org/D105662),
so some types are not properly deduplicated in that case.

Closes #104.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-07-09 01:51:59 -07:00
Omar Sandoval
347c578aa0 libdrgn: debug_info: don't open-code drgn_platform_address_size()
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-07-07 15:03:03 -07:00
Omar Sandoval
add17a9a36 libdrgn: stack_trace: fix source info without .debug_aranges
dwfl_module_getsrc() relies on .debug_aranges to find the CU containing
the PC. If the module has a missing or incomplete .debug_aranges, it
fails. This lookup is actually redundant since we already found the CU
when we unwound the stack. Use the libdw helpers that take the CU DIE
instead to avoid this. We also need to save the CU for frames where we
found it but couldn't find the subprogram (typically assembly files).

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-07-07 13:41:17 -07:00
Omar Sandoval
fbe102f37e libdrgn: debug_info: handle incomplete .debug_aranges
Clang does not generate .debug_aranges by default, but the GNU toolchain
does. This means that a Linux kernel binary compiled with Clang and GNU
binutils will have ranges in .debug_aranges for assembly files and
nothing else. This breaks our assumption that a non-empty .debug_aranges
has ranges for every compilation unit. Fix it by always falling back to
checking every CU if a range was not found in .debug_aranges.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-07-07 11:25:13 -07:00
Omar Sandoval
2e04e6b73c libdrgn: binary_buffer: handle non-canonical LEB128 numbers
LEB128 allows for redundant zero/sign bits, but we currently always
treat extra bytes as overflow. Let's check those bytes correctly.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-06-30 21:39:31 -07:00
Omar Sandoval
d12d4368b8 libdrgn: support passing debug info files to load_debug_info example program
And don't set the target by default; -k must be given explicitly now.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-06-30 16:58:47 -07:00
Omar Sandoval
73d5a207c8 libdrgn: dwarf_index: fix skipping DW_FORM_ref_addr in DWARF 2
In DWARF 2, DW_FORM_ref_addr has the size of an address, not a size
depending on the format.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-06-30 11:53:34 -07:00
Omar Sandoval
86e966fbf8 libdrgn: dwarf_index: handle DW_FORM_block
Somehow I missed this form, and I've never seen it used. It's the same
as DW_FORM_exprloc for our purposes, so it's an easy fix.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-06-30 01:34:52 -07:00
Omar Sandoval
018b00cede libdrgn: binary_buffer: check bounds with 64-bit size
There are a few places in the DWARF indexing code that we skip a 64-bit
size. On 32-bit systems, this can wrap if the count is greater than
SIZE_MAX. Rather than requiring vigilance against this, change the size
to uint64_t.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-06-30 01:27:47 -07:00
Omar Sandoval
52df3cb5ff libdrgn: dwarf_index: properly return error when hashing path fails
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-06-30 01:21:47 -07:00
Omar Sandoval
157f8ed7dc libdrgn: dwarf_index: #define FNV constants
Older versions of GCC and Clang don't accept const variables for
initializers ("error: initializer element is not constant"), so #define
the FNV constants instead.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-06-28 11:08:30 -07:00
Omar Sandoval
87809f7692 libdrgn: dwarf_index: improve file path hashing for deduplication
We currently don't include the compilation directory when hashing file
names for deduplication. This can cause us to incorrectly deduplicate a
definition if, for example, two libraries have a definition with the
same name in files with the same name. Fix this by hashing the full file
path including the compilation directory.

This also requires reworking our strategy for path normalization to
better handle ".." components, since directories may end up outside of
the compilation directory. The new strategy keeps a linked list of
hashes (now FNV-1a instead of SipHash) for each parent directory. This
is actually more efficient than the previous approach, offsetting the
cost of the extra hash computations for the compilation directory. It
also correctly handles file names in the line number program header
which consist of multiple components.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-06-25 18:03:01 -07:00
Omar Sandoval
82824c0e5f libdrgn: path: simplify logic in path_iterator_next()
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-06-25 18:03:01 -07:00
Omar Sandoval
57cc0deb98 libdrgn: replace struct path_iterator_component with struct string
The former is the same as the latter with less generic naming.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-06-25 18:03:01 -07:00
Omar Sandoval
420d2bb1dc libdrgn: dwarf_index: fix DW_AT_strp bounds check
The string must be null terminated, so there must be at least one byte
left in .debug_str.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-06-25 17:50:08 -07:00
Omar Sandoval
c4b174af74 libdrgn: fix kdump format support
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>
2021-06-09 15:30:48 -07:00
Omar Sandoval
6b2dda3f95 libdrgn: bring back dwfl_core_file_report() bug workaround
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>
2021-06-09 15:16:12 -07:00
Omar Sandoval
82ca5634b5 libdrgn: fix copying value to big-endian from little-endian
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>
2021-06-08 12:24:20 -07:00
Omar Sandoval
5a03d6b13f drgn 0.0.13
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-06-07 16:17:11 -07:00
Omar Sandoval
faad25d7b2 libdrgn: debug_info: fix address of objects with size zero
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>
2021-06-07 15:46:22 -07:00
Omar Sandoval
f7fe93e573 cli: show elfutils version in use
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>
2021-06-07 11:10:50 -07:00
Omar Sandoval
6357cea46b drgn 0.0.12
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-06-07 01:13:28 -07:00
Omar Sandoval
bc85767e5f libdrgn: support looking up parameters and variables in stack traces
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>
2021-06-05 16:18:51 -07:00
Omar Sandoval
38573cfdde libdrgn: stack_trace: pretty print frames and add frames for inline functions
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>
2021-06-05 16:18:51 -07:00
Omar Sandoval
0e113ecc8d libdrgn: debug_info: add drgn_find_die_ancestors()
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>
2021-06-05 16:18:51 -07:00
Omar Sandoval
d8d4157346 libdrgn: debug_info: add drgn_debug_info_module_find_dwarf_scopes()
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>
2021-06-05 16:18:51 -07:00
Omar Sandoval
b6d810b344 libdrgn: debug_info: add DWARF DIE iterator
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>
2021-06-05 16:18:51 -07:00
Omar Sandoval
ffcb9ccb19 libdrgn: debug_info: implement creating objects from DWARF location descriptions
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>
2021-06-05 16:18:51 -07:00
Omar Sandoval
8335450ecb libdrgn: debug_info: implement DW_OP_fbreg
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>
2021-06-05 16:18:51 -07:00
Omar Sandoval
d5b68455b8 libdrgn: debug_info: save .debug_loc
.debug_loc will be used for variable resolution.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-06-05 16:18:51 -07:00
Omar Sandoval
e105be6c18 libdrgn: debug_info: add helper to cache module section
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-06-05 16:18:51 -07:00
Omar Sandoval
dcda688c9a libdrgn: debug_info: parenthesize PUSH() macro argument
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>
2021-06-05 16:18:51 -07:00
Omar Sandoval
5fc879ef3e libdrgn: debug_info: limit number of DWARF expression operations executed
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>
2021-06-05 16:18:51 -07:00
Omar Sandoval
0e3054a0ba libdrgn: make addresses wrap around when reading memory
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>
2021-06-03 17:49:29 -07:00
Omar Sandoval
e5ff1ea7ac libdrgn: program: use preset platform in drgn_program_set_core_dump()
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>
2021-06-03 17:04:28 -07:00
Omar Sandoval
43b90ffb1b libdrgn: debug_info: add missing stack size check for DW_OP_deref
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-05-23 13:14:28 -07:00
Omar Sandoval
ad37c79cba libdrgn: python: add documentation and type annotation for Program.__contains__()
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>
2021-05-12 16:26:56 -07:00
Omar Sandoval
92fd967a3a libdrgn: print uint8_t as hex with PRIx8 format, not x
In practice, they're probably always the same, but PRIx8 is more
correct.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-05-07 15:34:30 -07:00
Omar Sandoval
e0921c5bdb libdrgn: don't use OpenMP tasking
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>
2021-05-06 16:56:02 -07:00
Jay Kamat
95646b47c9 libdrgn: dwarf_index: add support for DW_FORM_indirect
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>
2021-05-04 16:56:54 -07:00
Omar Sandoval
609a1cafc6 libdrgn: dwarf_index: check for attribute forms more strictly
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>
2021-05-04 16:56:54 -07:00
Omar Sandoval
2ad52cb5f4 libdrgn: add option to time load_debug_info example program
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>
2021-04-23 09:29:44 -07:00
Omar Sandoval
2d40d6e146 libdrgn: add configure~ to .gitignore
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-04-23 09:18:16 -07:00
Jay Kamat
6be21f674a libdrgn: follow DW_AT_signature when parsing DWARF types
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>
2021-04-23 02:37:31 -07:00
Jay Kamat
9dabec1264 libdrgn: add support for parsing type units
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>
2021-04-23 02:37:31 -07:00
Omar Sandoval
33300d426e libdrgn: debug_info: don't overwrite Dwarf_Die passed to drgn_type_from_dwarf_internal()
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>
2021-04-23 02:37:31 -07:00
Omar Sandoval
155ec92ef2 libdrgn: fix reading 32-bit float object values on big-endian
Closes #99.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-04-22 09:45:41 -07:00
Omar Sandoval
0e2703dd4e libdrgn: python: use _PyDict_GetItemIdWithError()
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>
2021-04-22 01:17:22 -07:00