Commit Graph

670 Commits

Author SHA1 Message Date
Omar Sandoval
8b264f8823 Update copyright headers to Facebook and add missing headers
drgn was originally my side project, but for awhile now it's also been
my work project. Update the copyright headers to reflect this, and add a
copyright header to various files that were missing it.
2020-05-15 15:13:02 -07:00
Omar Sandoval
c339113f9c libdrgn: adjust program counter when looking up frame symbol
For functions that call a noreturn function, the compiler may omit code
after the call instruction. This means that the return address may not
lie in the caller's symbol. dwfl_frame_pc() returns whether a frame is
an "activation", i.e., its program counter is guaranteed to lie within
the caller. This is only the case for the initial frame, frames
interrupted by a signal, and the signal trampoline frame. For everything
else, we need to decrement the program counter before doing any lookups.
2020-05-13 17:11:54 -07:00
Omar Sandoval
175f83fc23 Update elfutils with noreturn unwinding fix
Rebase on master and fix dwfl_frame_module/dwfl_frame_dwarf_frame to
decrement the program counter when necessary.

Based on:

a8493c12a libdw: Skip imported compiler_units in libdw_visit_scopes walking DIE tree

With the following patches:

configure: Add --disable-programs
configure: Add --disable-shared
libdwfl: simplify activation frame logic
libdwfl: add interface for attaching to/detaching from threads
libdwfl: add interface for getting Dwfl_Module and Dwarf_Frame for Dwfl_Frame
libdwfl: export __libdwfl_frame_reg_get as dwfl_frame_register
libdwfl: add interface for evaluating DWARF expressions in a frame
2020-05-13 16:41:52 -07:00
Omar Sandoval
bf545105c6 libdrgn: build in silent mode by default
The automake/libtool compilation output is obnoxiously verbose. Switch
on automake's silent mode, and make the custom rules honor it.
2020-05-10 00:12:50 -07:00
Omar Sandoval
62ddc96350 setup.py: add 5.7 to vmtest kernels
5.7 is up to rc4 (oops). Better late than never.
2020-05-08 18:13:12 -07:00
Omar Sandoval
2d1481f5ab libdrgn: add page table walker kernel memory reader
Now that we can walk page tables, we can use it in a memory reader that
reads kernel memory via the kernel page table. This means that we don't
need libkdumpfile for ELF vmcores anymore (although I'll keep the
functionality around until this code has been validated more).
2020-05-08 17:37:56 -07:00
Omar Sandoval
e697be707c libdrgn: use swapper_pg_dir in vmcoreinfo for fallback PAGE_OFFSET
I originally wanted to avoid depending on another vmcoreinfo field, but
an the next change is going to depend on swapper_pg_dir in vmcoreinfo
anyways, and it ends up being simpler to use it.
2020-05-08 17:37:56 -07:00
Omar Sandoval
4b82d1e075 helpers: add cmdline() and environ()
These are two of the most common use cases for reading a process's
memory.
2020-05-08 17:37:56 -07:00
Omar Sandoval
8a276838ac helpers: add access_process_vm() and access_remote_vm()
Now that we can walk page tables, we can finally read memory from
userspace tasks.

Closes #53.
2020-05-08 17:37:01 -07:00
Omar Sandoval
d0a1718451 libdrgn: implement virtual address translation/page table walking
There are a few big use cases for this in drgn:

* Helpers for accessing memory in the virtual address space of userspace
  tasks.
* Removing the libkdumpfile dependency for vmcores.
* Handling gaps in the virtual address space of /proc/kcore (cf. #27).

I dragged my feet on implementing this because I thought it would be
more complicated, but the page table layout on x86-64 isn't too bad.
This commit implements page table walking using a page table iterator
abstraction. The first thing we'll add on top of this will be a helper
for reading memory from a virtual address space, but in the future it'd
also be possible to export the page table iterator directly.
2020-05-08 17:36:19 -07:00
Omar Sandoval
63299e0701 libdrgn: actually use uint64_t for two's complement unary ops
UNARY_OP_SIGNED_2C() uses a union of int64_t and uint64_t to avoid
signed integer overflow... except that there's a typo and the uint64_t
is actually an int64_t. Fix it and add a test that would catch it with
-fsanitize=undefined.
2020-05-08 13:50:24 -07:00
Omar Sandoval
8f81ea255f libdrgn: don't use unaligned loads to parse DWARF
-fsanitize=undefined reports that the read_u* helpers rely on unaligned
loads. Use memcpy() instead.
2020-05-08 13:50:24 -07:00
Omar Sandoval
3d59e042f4 libdrgn: don't open-code fls()
c_integer_literal() has an open-coded equivalent of fls() that assumes
that unsigned long long is 64 bits. Use fls() instead.
2020-05-08 00:20:42 -07:00
Omar Sandoval
340e00dfb5 libdrgn: improve and document bit operations
fls() can be implemented with __bitop(), and we can get rid of clz() since
it's only used by fls().
2020-05-08 00:14:25 -07:00
Omar Sandoval
f49d68d8f9 libdrgn: split generic utility functions out of internal.h
internal.h includes both drgn-specific helpers and generic utility
functions. Split the latter into their own util.h header and use it
instead of internal.h in the generic data structure code. This makes it
easier to copy the data structures into other projects/test programs.
2020-05-07 16:03:43 -07:00
Omar Sandoval
a95e42ef2e libdrgn/python: use vector for Program_load_debug_info()
Program_load_debug_info() is the last user of the
resize_array()/realloc_array() utility functions. We can clean it up by
using a vector and finally get rid of those functions.

This also happens to fix three bugs in Program_load_debug_info(): we
weren't setting a Python exception if we couldn't allocate the path_args
array, we weren't zeroing path_args after resizing the array, and we
weren't freeing the path_args array. Shame on whoever wrote this.
2020-05-07 15:47:57 -07:00
Omar Sandoval
0a100064c1 libdrgn: improve and rename DRGN_UNREACHABLE()
DRGN_UNREACHABLE() currently expands to abort(), but assert() provides
more information. If NDEBUG is defined, we can use
__builtin_unreachable() instead.

DRGN_UNREACHABLE() isn't drgn-specific, so this renames it to
UNREACHABLE(). It's also not really related to errors, so this moves it
to internal.h.
2020-05-07 15:16:22 -07:00
Omar Sandoval
d759c7ed20 libdrgn: get rid of OFF_MAX
This hasn't been used since commit 417a6f0d76 ("libdrgn: make memory
reader pluggable with callbacks").
2020-05-07 14:41:05 -07:00
Omar Sandoval
23574e59d5 libdrgn: add /proc/kcore physical segments on old kernels
Before Linux v4.11, /proc/kcore didn't have valid physical addresses, so
it's currently not possible to read from physical memory on old kernels.
However, if we can figure out the address of the direct mapping, then we
can determine the corresponding physical addresses for the segments and
add them.
2020-05-04 13:20:27 -07:00
Omar Sandoval
f8c33518eb libdrgn: handle kernel core dumps with all zero p_paddr
We treat core dumps with all zero p_paddrs as not having valid physical
addresses. However, it is theoretically possible for a kernel core dump
to only have one segment which legitimately has a p_paddr of 0 (e.g., if
it only has a segment for the direct mapping, although note that this
isn't currently possible on x86, as Linux on x86 reserves PFN 0 for the
BIOS [1]).

If the core dump has a VMCOREINFO note, then it is either a vmcore,
which has valid physical addresses, or it is /proc/kcore with Linux
kernel commit 23c85094fe18 ("proc/kcore: add vmcoreinfo note to
/proc/kcore") (in v4.19), so it must also have Linux kernel commit
464920104bf7 ("/proc/kcore: update physical address for kcore ram and
text") (in v4.11) (ignoring the possibility of a franken-kernel which
backported the former but not the latter). Therefore, treat core dumps
with a VMCOREINFO note as having valid physical addresses.

1: https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/arch/x86/kernel/setup.c?h=v5.6#n678
2020-05-04 13:20:27 -07:00
Omar Sandoval
5505628235 libdrgn: get rid of struct drgn_program.num_file_segments
This isn't used anymore. Remove it and simplify the loop adding file
segments.
2020-05-04 13:20:27 -07:00
Omar Sandoval
510b6ef3b5 libdrgn: read vmcoreinfo physical address as uint64_t
Even on 32-bit architectures, physical addresses can be 64 bits (e.g.,
x86 with PAE). It's unlikely that the vmcoreinfo note would be in such
an address, but let's always parse it as a uint64_t just to be safe.
2020-05-04 13:20:27 -07:00
Omar Sandoval
10e58777c3 Add Program.read_{u8,u16,u32,u64,word}()
I've found that I do this manually a lot (e.g., when digging through a
task's stack). Add shortcuts for reading unsigned integers and a note
for how to manually read other formats.
2020-04-27 17:27:10 -07:00
Omar Sandoval
b1315fcaa1 libdrgn: add drgn_program_bswap()
This is clearer than open-coding the endianness check.
2020-04-27 17:08:02 -07:00
Omar Sandoval
02743b2da7 drgndoc: don't add :rtype: if function doesn't have docstring 2020-04-27 17:08:02 -07:00
Omar Sandoval
36d350bf93 Add scripts/cscope.sh
For generating the cscope index from the proper files.
2020-04-27 17:07:15 -07:00
Omar Sandoval
0d64d66c80 Add examples and tools to source distribution 2020-04-27 16:53:14 -07:00
Omar Sandoval
1af57230c4 drgn 0.0.4 2020-04-21 15:52:01 -07:00
Omar Sandoval
61a7a0c39d Fix Object.__getitem__() idx type annotation
In obj[idx], idx can also be another Object. Technically, it can be
anything that implements __index__() (), but typing.SupportsIndex was added
in v3.8. For now, allow Object explicitly.
2020-04-21 15:49:26 -07:00
Omar Sandoval
ea8cdede6d Fix Program.pointer_type() type annotation
"type" can be a string or Type object.
2020-04-21 15:03:33 -07:00
Omar Sandoval
55135d5854 Remove stray type comments
These are already emitted by drgndoc, so we don't need them.
2020-04-21 14:59:04 -07:00
Omar Sandoval
a070f1ca14 drgndoc: visit submodules in deterministic order
parse_package() visits submodules in whatever order they're returned by
the filesystem, which is arbitrary. Let's sort them so we always visit
them in the same order.
2020-04-21 10:44:52 -07:00
Omar Sandoval
ea3cdb43f7 libdrgn/python: optimize Object.__getattribute__()
DrgnObject_getattro() uses PyObject_GenericGetAttr() and catches the
AttributeError raised if the name is not an attribute of the Object
class. If the member is found, we then destroy the AttributeError.
Raising an exception only to destroy it is obviously wasteful. Luckily,
as of Python 3.7, the lower-level _PyObject_GenericGetAttrWithDict() can
suppress the AttributeError; we can raise it ourselves if we need it. In
my microbenchmarks, this makes Object.__getattribute__() at least twice
as fast when the member exists.

This also fixes a drgn_error leak.
2020-04-20 17:45:30 -07:00
Omar Sandoval
da0c637f2d Fix Object.__getattribute__() return type annotation
mypy only uses the annotated return type of __getattribute__() for
attributes which aren't otherwise annotated, so we can annotate it as
returning Object.
2020-04-20 12:37:55 -07:00
Omar Sandoval
7b08f7682e Fix mypy errors
There are a handful of mypy errors that I hadn't gotten around to
fixing. This cleans them up and makes drgn mypy-clean (although not in
strict mode).
2020-04-18 20:55:13 -07:00
Omar Sandoval
12a23a6e98 Add stubs for internal helpers
mypy complains about these functions not existing, so add stubs to let
mypy know they exist. In the future, we probably want the docstring to
be in these stubs and use them directly instead of wrapping them in
Python, but that's for another day.
2020-04-18 15:10:29 -07:00
Omar Sandoval
7613dfb178 helpers: fix enum_type_to_class() return type annotation
This returns an enum.IntEnum _class_, not an object of type
enum.IntEnum.
2020-04-18 15:00:56 -07:00
Omar Sandoval
3b0988bd81 docs: mention tools directory
This will need to be fleshed out in the future, but at least mention it
to start.
2020-04-17 16:15:35 -07:00
Omar Sandoval
e03563221d vmtest: use BusyBox shell script as init
Currently, vmtest runs a custom program as init in the guest that
communicates with the host via virtio-serial. This is a lot of C code
that turns out can be replaced with a shell script. In order to keep the
dependencies minimal, we use BusyBox.
2020-04-17 15:11:54 -07:00
Jeffrey Mahoney
9bb2ccecb7 Enable DWARF indexing to work with partial units
Loading debuginfo from a kernel with separate or re-combined debuginfo
results in the following failure:

Traceback (most recent call last):
  File "/home/jeffm/.local/bin/drgn", line 11, in <module>
    load_entry_point('drgn==0.0.3+39.gbf05d9bf', 'console_scripts', 'drgn')()
  File "/home/jeffm/.local/lib/python3.6/site-packages/drgn-0.0.3+39.gbf05d9bf-py3.6-linux-x86_64.egg/drgn/internal/cli.py", line 121, in main
    prog.load_debug_info(args.symbols, **args.default_symbols)
Exception: invalid DW_AT_decl_file 10

A typical kernel build results in DWARF information with
DW_TAG_compile_unit tags but the objcopy --only-keep-debug and eu-unstrip
commands use DW_TAG_partial_unit tags.  The DWARF indexer only handles
the former, so the file table isn't populated and we get the exception.

Fortunately, the two are more or less interchangeable. (See
http://dwarfstd.org/doc/Dwarf3.pdf, section E.2.3).  Accepting both for
indexing compile units results in a working session.
2020-04-14 14:11:24 -07:00
Omar Sandoval
1376674068 setup.py: log test returncode from VM
I'm seeing some spurious failures on Travis where the tests pass in the
VM but setup.py reports that they failed. Log the returncode that
setup.py sees to narrow down the issue.
2020-04-13 17:21:02 -07:00
Omar Sandoval
a3248b51e3 libdrgn: fix use after free when formatting compound types
compound_initializer_init_next() saves a pointer to the compound
initializer stack and uses it after appending to the stack, which may
have reallocated the stack.
2020-04-13 16:49:18 -07:00
Jay Kamat
ecef9d74ef libdrgn: get rid of arrays embedded in drgn_type
For C++ support, we need to add an array of template parameters to
struct drgn_type. struct drgn_type already has arrays for members,
enumerators, and parameters embedded at the end of the structure,
because no type needs more than one of those. However, struct, union,
and class types may need members and template parameters. We could add a
separate array of templates, but then it gets confusing having two
methods of storing arrays in struct drgn_type. Let's make these arrays
separate instead of embedding them.
2020-04-13 16:47:05 -07:00
Omar Sandoval
35bb02443d tests: add mm helper tests
Add tests for pfn_to_virt(), virt_to_pfn(), pfn_to_page(), and
page_to_pfn() using the pagemap interface
(https://www.kernel.org/doc/html/latest/admin-guide/mm/pagemap.html).
Also add tests for the PAGE_SIZE, PAGE_SHIFT, and PAGE_MASK macros.
2020-04-10 15:33:29 -07:00
Omar Sandoval
7a9fad0fd2 libdrgn: move _vmemmap() to object finder
Similarly to PAGE_OFFSET, vmemmap makes more sense as part of the Linux
kernel object finder than an internal helper.

While we're here, let's fix the definition for 5-level page tables. This
only matters for kernels with commit 77ef56e4f0fb ("x86: Enable 5-level
paging support via CONFIG_X86_5LEVEL=y") but without eedb92abb9bb
("x86/mm: Make virtual memory layout dynamic for CONFIG_X86_5LEVEL=y")
(namely, v4.14, v4.15, and v4.16); since v4.17, 5-level page table
support enables KASLR.
2020-04-10 15:33:29 -07:00
Omar Sandoval
5ac95e491a libdrgn: fix _page_offset() helper and move to object finder
The internal _page_offset() helper gets the value of PAGE_OFFSET, but
the fallback when KASLR is disabled has been out of date since Linux
v4.20 and never handled 5-level page tables. Additionally, it makes more
sense as part of the Linux kernel (formerly vmcoreinfo) object finder so
that it's cleanly accessible outside of drgn internals.
2020-04-10 15:33:27 -07:00
Omar Sandoval
1dbc718840 helpers: add pgtable_l5_enabled() 2020-04-10 15:18:46 -07:00
Omar Sandoval
3adc8f2ffe vmtest: use -cpu host instead of kvm64
drgn may be compiled with some CPU-specific features (e.g.,
-march=native), so make sure that we support those features inside of
the VM, too.
2020-04-10 15:18:46 -07:00
Omar Sandoval
cf8d969048 Run black on some stray changes
A few recent changes weren't formatted with black.
2020-04-10 15:18:10 -07:00
Jeff Mahoney
bf05d9bf3f libdrgn: allow to build without openmp
The configure script allows the user to not use any openmp
implementation but dwarf_index.c uses the locking APIs unconditionally.
This compiles but fails at runtime.

Adding simple stubs for the locking API. This is useful when debugging
crashes in dwarf indexing during development.
2020-04-08 12:33:40 -07:00