Commit Graph

91 Commits

Author SHA1 Message Date
Omar Sandoval
690b5fd650 libdrgn: generalize architecture to platform
For stack trace support, we'll need to have some architecture-specific
functionality. drgn's current notion of an architecture doesn't actually
include the instruction set architecture. This change expands it to a
"platform", which includes the ISA as well as the existing flags.
2019-08-02 00:11:56 -07:00
Omar Sandoval
71e6744210 libdrgn: add symbol table interface
Now that we're not overloading the name "symbol", we can define struct
drgn_symbol as a symbol table entry. For now, this is very minimal: it's
just a name, address, and size. We can then add a way to find the symbol
for a given address, drgn_program_find_symbol(). For now, this is only
supported through the actual ELF symbol tables. However, in the future,
we can probably support adding "symbol finders".
2019-07-30 09:25:34 -07:00
Omar Sandoval
0c5df56fba libdrgn: replace symbol index with object index
struct drgn_symbol doesn't really represent a symbol; it's just an
object which hasn't been fully initialized (see c2be52dff0 ("libdrgn:
rename object index to symbol index"), it used to be called a "partial
object"). For stack traces, we're going to have a notion of a symbol
that more closely represents an ELF symbol, so let's get rid of the
temporary struct drgn_symbol representation and just return an object
directly.
2019-07-29 17:04:47 -07:00
Omar Sandoval
27a27940bc libdrgn: split up drgn_program_get_dwarf()
We don't need to get the DWARF index at the time we get the Dwfl handle,
so get rid of drgn_program_get_dwarf(), add drgn_program_get_dwfl(), and
create the DWARF index right before we update in a new function,
drgn_program_update_dwarf_index().
2019-07-19 09:26:30 -07:00
Omar Sandoval
e5874ad18a libdrgn: use libdwfl
libdwfl is the elfutils "DWARF frontend library". It has high-level
functionality for looking up symbols, walking stack traces, etc. In
order to use this functionality, we need to report our debugging
information through libdwfl. For userspace programs, libdwfl has a much
better implementation than drgn for automatically finding debug
information from a core dump or PID. However, for the kernel, libdwfl
has a few issues:

- It only supports finding debug information for the running kernel, not
  vmcores.
- It determines the vmlinux address range by reading /proc/kallsyms,
  which is slow (~70ms on my machine).
- If separate debug information isn't available for a kernel module, it
  finds it by walking /lib/modules/$(uname -r)/kernel; this is repeated
  for every module.
- It doesn't find kernel modules with names containing both dashes and
  underscores (e.g., aes-x86_64).

Luckily, drgn already solved all of these problems, and with some
effort, we can keep doing it ourselves and report it to libdwfl.

The conversion replaces a bunch of code for dealing with userspace core
dump notes, /proc/$pid/maps, and relocations.
2019-07-15 12:27:48 -07:00
Omar Sandoval
9f9bec4762 libdrgn: use common vector where applicable
This converts several open-coded dynamic arrays to the new common vector
implementation:

- drgn_lexer stack
- Array dimension array for DWARF parsing
- drgn_program_read_c_string()
- DWARF index directory name hashes
- DWARF index file name hashes
- DWARF index abbreviation table
- DWARF index shard entries
2019-07-15 12:27:16 -07:00
Omar Sandoval
74c0aa8612 libdrgn: reorder drgn_error_create_os() arguments
To make it more consistent with the upcoming drgn_error_format_os().
2019-07-11 16:12:56 -07:00
Omar Sandoval
e73346b488 libdrgn: generalize IS_RUNNING_KERNEL flag to IS_LIVE
I.e., also flag running processes as live.
2019-07-08 16:55:54 -07:00
Omar Sandoval
129f1493b8 libdrgn: split kernel-specific stuff out of program.c
Almost half of program.c is stuff specific to the Linux kernel, so let's
separate that out (and combine it with the existing kernel module code).
2019-07-08 16:53:58 -07:00
Omar Sandoval
25e7a9d3b8 libdrgn/python: implement Program.__contains__ 2019-06-28 16:02:52 -07:00
Omar Sandoval
f55158c74c libdrgn: add PAGE_{SHIFT,SIZE,MASK} symbols from vmcoreinfo
Since we currently don't parse DWARF macro information, there's no easy
way to get the value PAGE_SIZE and friends in drgn. However, vmcoreinfo
contains the value of PAGE_SIZE, so let's add a special symbol finder
that returns that.
2019-05-29 00:02:48 -07:00
Omar Sandoval
1614b1e6f6 libdrgn: add better vmcoreinfo fallback
Currently, if we don't get vmcoreinfo from /proc/kcore, and we can't get
it from /sys/kernel/vmcoreinfo, then we manually determine the kernel
release and KASLR offset. This has a couple of issues:

1. We look for vmlinux to determine the KASLR offset, which may not be
   in a standard location.
2. We might want to start using other information from vmcoreinfo which
   can't be determined as easily.

Instead, we can get the virtual address of vmcoreinfo from
/proc/kallsyms and read it directly from there.
2019-05-28 15:54:49 -07:00
Omar Sandoval
8e45a305fb libdrgn: fix file/memory leak in proc_kallsyms_symbol_addr() 2019-05-28 15:01:35 -07:00
Serapheim Dimitropoulos
2396cdca47 libdrgn: add /usr/lib/debug/boot in the vmlinux_paths
Ubuntu-based distros tend to put vmlinux with debug info
under /usr/lib/debug/boot/vmlinux-<version>.
2019-05-27 17:43:10 -07:00
Omar Sandoval
eeac241c65 libdrgn: make all kernel module iterator errors non-fatal when loading default symbols
kernel_module_iterator_next() can also fail in
open_loaded_kernel_modules(), so handle it in the same way that we
currently handle kernel_module_iterator_init().
2019-05-26 14:58:02 -07:00
Omar Sandoval
68f7b87d6a libdrgn: ignore physical core dump segments with address -1
/proc/kcore contains segments which don't have a valid physical address,
which it indicates with a p_paddr of -1. Skip those segments, otherwise
we got an overflow error from the memory reader.
2019-05-26 14:49:48 -07:00
Omar Sandoval
c0bc72b0ea libdrgn: use splay tree for memory reader
The current array-based memory reader has a bug in the following
scenario:

    prog.add_memory_segment(0xffff0000, 128, ...)
    # This should replace a subset of the first segment.
    prog.add_memory_segment(0xffff0020, 32, ...)
    # This moves the first segment back to the front of the array.
    prog.read(0xffff0000, 32)
    # This finds the first segment instead of the second segment.
    prog.read(0xffff0032, 32)

Fix it by using the newly-added splay tree. This also splits up the
virtual and physical memory segments into separate trees.
2019-05-24 17:48:08 -07:00
Omar Sandoval
0026eeae66 libdrgn: find kernel module name in kernels < v4.13
If we can't find the module name in .modinfo, fall back to
.gnu.linkonce.this_module.
2019-05-14 15:39:16 -07:00
Omar Sandoval
39876ccbac libdrgn: find kernel module debuginfo on Debian
Debian's linux-image*-dbg packages name the ELF files without the extra
.debug suffix that Fedora includes.
2019-05-14 12:42:56 -07:00
Omar Sandoval
ac27f2c1ec libdrgn: only load debug information from loaded kernel modules
Currently, we load debug information for every kernel module that we
find under /lib/modules/$(uname -r)/kernel. This has a few issues:

1. Distribution kernels have lots of modules (~3000 for Fedora and
   Debian).
   a) This can exceed the default soft limit on the number of open file
      descriptors.
   b) The mmap'd debug information can trip the overcommit heuristics
      and cause OOM kills.
   c) It can take a long time to parse all of the debug information.
2. Not all modules are under the "kernel" directory; some distros also
   have an "extra" directory.
3. The user is not made aware of loaded kernel modules that don't have
   debug information available.

So, instead of walking /lib/modules, walk the list of loaded kernel
modules and look up their debugging information.
2019-05-14 11:55:39 -07:00
Omar Sandoval
e21ed988fb libdrgn: add drgn_error_from_string_builder()
And use that instead of exposing drgn_error_create_nodup().
2019-05-14 10:16:01 -07:00
Omar Sandoval
f08d4c9a08 libdrgn: make string_builder API return bool
It can only fail with no memory, so simplify it.
2019-05-14 10:07:50 -07:00
Omar Sandoval
ed6a6f0b3e libdrgn: get module section address from sysfs when possible
In the running kernel, we don't have to walk the list of modules and
module sections, since we can just look it up directly in sysfs.
2019-05-13 18:05:09 -07:00
Omar Sandoval
f11e030aaa libdrgn: factor out kernel module iteration and section lookup 2019-05-13 16:39:30 -07:00
Omar Sandoval
9b563170f8 libdrgn: make load_debug_info() API saner
Rather than exposing the underlying open and load steps of DWARF index,
simplify it down to a single load step.
2019-05-13 15:04:27 -07:00
Omar Sandoval
baba1ff3f0 libdrgn: make program components pluggable
Currently, programs can be created for three main use-cases: core dumps,
the running kernel, and a running process. However, internally, the
program memory, types, and symbols are pluggable. Expose that as a
callback API, which makes it possible to use drgn in much more creative
ways.
2019-05-10 12:41:07 -07:00
Omar Sandoval
5200a6652c libdrgn: embed memory reader, type index, and symbol index in program 2019-05-06 14:55:34 -07:00
Omar Sandoval
640b1c011d libdrgn: embed DWARF index in DWARF info cache 2019-05-06 14:55:34 -07:00
Omar Sandoval
2ed8e3148c libdrgn: get architecture info from core file instead of DWARF index 2019-05-06 14:55:34 -07:00
Omar Sandoval
ba162ac001 libdrgn: remove endianness from type index
The type index doesn't need to know or care about endianness. Move it to
the program.
2019-05-06 14:55:34 -07:00
Omar Sandoval
565e0343ef libdrgn: make symbol index pluggable with callbacks
The last piece of making the major program components pluggable.
2019-05-06 14:55:34 -07:00
Omar Sandoval
9c6575e783 libdrgn: move relocation hook to drgn_info_cache 2019-05-06 14:55:34 -07:00
Omar Sandoval
52a8681a8d libdrgn: rename drgn_dwarf_type_cache to drgn_dwarf_info_cache
This is preparation for sharing this with the symbol index.
2019-05-06 14:55:34 -07:00
Omar Sandoval
a98445c277 libdrgn: make type index pluggable with callbacks
Similar to "libdrgn: make memory reader pluggable with callbacks", we
want to support custom type indexes (imagine, e.g., using drgn to parse
a binary format). For now, this disables the dwarf index tests; we'll
have a better way to test them later, so let's not bother adding more
test scaffolding.
2019-05-06 14:55:34 -07:00
Omar Sandoval
c2be52dff0 libdrgn: rename object index to symbol index
An "object index" doesn't actually index objects, but really "partial
objects" -- i.e., a type + address. "Symbol" is a better name for this.
2019-05-06 14:55:34 -07:00
Omar Sandoval
417a6f0d76 libdrgn: make memory reader pluggable with callbacks
I've been planning to make memory readers pluggable (in order to support
use cases like, e.g., reading a core file over the network), but the
C-style "inheritance" drgn uses internally is awkward as a library
interface; it's much easier to just register a callback. This change
effectively makes drgn_memory_reader a mapping from a memory range to an
arbitrary callback. As a bonus, this means that read callbacks can be
mixed and matched; a part of memory can be in a core file, another part
can be in the executable file, and another part could be filled from an
arbitrary buffer.
2019-05-06 14:55:34 -07:00
Omar Sandoval
d0633d2f1a libdrgn: allow multiple cleanup callbacks
For now, this makes things slightly awkward, but it will be necessary
for the upcoming changes making drgn_program more pluggable.
2019-05-06 14:55:34 -07:00
Omar Sandoval
043cddf6d8 libdrgn: move member cache to type index
It makes more sense here than in struct drgn_program.
2019-05-06 14:55:34 -07:00
Omar Sandoval
839252564a libdrgn: deduplicate files in DWARF index
Currently, we deduplicate files for userspace mappings manually.
However, to prepare for adding symbol files at runtime, move the
deduplication to DWARF index. In the future, we probably want to
deduplicate based on build ID, as well.
2019-05-06 14:55:34 -07:00
Omar Sandoval
2dd14ad522 libdrgn: work around "undefined reference to '__muloti4'" when using Clang
Older versions of Clang generate a call to __muloti4() for
__builtin_mul_overflow() with mixed signed and unsigned types. However,
Clang doesn't link to compiler-rt by default. Work around it by making
all of our calls to __builtin_mul_overflow() use unsigned types only.

1: https://bugs.llvm.org/show_bug.cgi?id=16404
2019-04-02 14:12:11 -07:00
Omar Sandoval
75c3679147 Rewrite drgn core in C
The current mixed Python/C implementation works well, but it has a
couple of important limitations:

- It's too slow for some common use cases, like iterating over large
  data structures.
- It can't be reused in utilities written in other languages.

This replaces the internals with a new library written in C, libdrgn. It
includes Python bindings with mostly the same public interface as
before, with some important improvements:

- Types are now represented by a single Type class rather than the messy
  polymorphism in the Python implementation.
- Qualifiers are a bitmask instead of a set of strings.
- Bit fields are not considered a separate type.
- The lvalue/rvalue terminology is replaced with reference/value.
- Structure, union, and array values are better supported.
- Function objects are supported.
- Program distinguishes between lookups of variables, constants, and
  functions.

The C rewrite is about 6x as fast as the original Python when using the
Python bindings, and about 8x when using the C API directly.

Currently, the exposed API in C is fairly conservative. In the future,
the memory reader, type index, and object index APIs will probably be
exposed for more flexibility.
2019-04-02 14:12:07 -07:00