Commit Graph

1135 Commits

Author SHA1 Message Date
Omar Sandoval
6ee7ba4cb1 vmtest: add some Traffic Control config options
We need these to test #117.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-09-01 14:13:34 -07:00
Omar Sandoval
77b9d3ad98 tests: change LinuxHelperTestCase.setUp to setUpClass
This already caches class variables, and it's shared across all Linux
helper test cases, so it makes more sense as setUpClass. This will also
allow subclasses to use cls.prog in their own setUpClass.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-08-31 17:43:18 -07:00
Omar Sandoval
fba5947fec libdrgn: add array_for_each()
And use it in a few appropriate places. This should hopefully make it
harder to make iteration mistakes like the one fixed by commit
4755cfac7c ("libdrgn: dwarf_index: increment correct variable when
rolling back"). While we're doing this, move ARRAY_SIZE() into a new
header file with array_for_each() and make it lowercase.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-08-23 17:32:00 -07:00
Omar Sandoval
4755cfac7c libdrgn: dwarf_index: increment correct variable when rolling back
We need to increment to the next DIE, not the next shard here.

Fixes: 1c9ab2e7d1 ("libdrgn: dwarf_index: fix leak of DWARF index entries on failure")
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-08-23 17:06:24 -07:00
Omar Sandoval
84f6142879 libdrgn: dwarf_index: remove any_name functionality from dwarf_index_iterator
This hasn't been used since commit 06960f591c ("libdrgn: look up
primitive types on demand").

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-08-23 17:06:15 -07:00
Stephen Brennan
207ca0e16b tests: Add Symbol test
Signed-off-by: Stephen Brennan <stephen.s.brennan@oracle.com>
2021-08-20 18:16:57 -07:00
Stephen Brennan
1744d8d93c libdrgn: python: Add binding, kind to drgn.Symbol
Signed-off-by: Stephen Brennan <stephen.s.brennan@oracle.com>
2021-08-20 18:16:57 -07:00
Stephen Brennan
3d8db22c47 libdrgn: Add kind and binding fields to drgn_symbol
Signed-off-by: Stephen Brennan <stephen.s.brennan@oracle.com>
2021-08-20 18:16:57 -07:00
Omar Sandoval
8d383fb89a libdrgn: fix alphabetization in gen_constants.py
PlatformFlags obviously comes before PrimitiveType.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-08-20 15:02:31 -07:00
Omar Sandoval
27906d0cf1 libdrgn: python: cast enums when wrapping with Python call
The "k" format expects an unsigned long, so make sure we cast C enums to
the proper type. This probably doesn't matter for x86 in practice, but
it's better to be safe.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-08-20 14:58:33 -07:00
Peilin Ye
242d1484f9 helpers: Add get_net_ns_by_{inode,fd}()
Add a helper, get_net_ns_by_inode(), to get the network namespace
("netns") descriptor (struct net *) given an netns NSFS pseudo-file
inode (struct inode *) e.g. "/proc/$PID/ns/net" or "/run/netns/$NAME".
As an example:

	>>> inode = path_lookup(prog, "/run/netns/foo").dentry.d_inode
	>>> net = get_net_ns_by_inode(inode)
	>>> netdev = netdev_get_by_name(net, "eth3")
	>>> netdev.ifindex.value_()
	5

Conventionally ip netns files can be found under "/var/run/netns/",
while Docker netns files can be found under "/var/run/docker/netns".
However, as pointed out by Omar, path_lookup() doesn't know how to
deal with symlinks; resolve it using something like "pwd -P" before
passing it to path_lookup().

Also add a get_net_ns_by_fd() wrapper around it as suggested by Omar.
Example:

	>>> import os
	>>> pid = os.getpid()
	>>> task = find_task(prog, pid)
	>>> file = open(f"/proc/{pid}/ns/net")
	>>> net = get_net_ns_by_fd(task, file.fileno())

Add a test for get_net_ns_by_inode().

Signed-off-by: Peilin Ye <peilin.ye@bytedance.com>
2021-08-20 11:39:56 -07:00
Omar Sandoval
c9cb28b649 docs: set required Sphinx version for Read the Docs
Read the Docs defaults to Sphinx 1.8.5. This version was released in
2019 and doesn't know about the :classmethod: option, so the
documentation for Object.from_bytes_() is missing from
drgn.readthedocs.io. Set the required version to the current latest
version as recommended by Read the Docs:
https://docs.readthedocs.io/en/stable/guides/reproducible-builds.html#pinning-dependencies.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-08-17 15:01:14 -07:00
Peilin Ye
cf06be1813 helpers: Add for_each_net()
Add a helper to iterate over all network namespaces in the system.  As
an example:

	>>> for net in for_each_net(prog):
	...     if netdev_get_by_name(net, "enp0s3"):
	...         print(net.ipv4.sysctl_ip_early_demux.value_())
	...
	1

Also add a test for this new helper to tests/helpers/linux/test_net.py.

Suggested-by: Cong Wang <cong.wang@bytedance.com>
Signed-off-by: Peilin Ye <peilin.ye@bytedance.com>
2021-08-16 16:48:25 -07:00
Omar Sandoval
5977dcc1e8 vmtest: use larger msize for 9pfs mounts
QEMU warns about the default 8k msize
(https://wiki.qemu.org/Documentation/9psetup#msize). I wasn't able to
measure any performance difference, but bump it to 1MiB to silence the
warning.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-08-16 12:47:05 -07:00
Omar Sandoval
333652dba3 vmtest: fix deprecated QEMU option warnings
QEMU 6.0 deprecated boolean options without an explicit =on or =off
(https://wiki.qemu.org/ChangeLog/6.0#New_deprecated_options_and_features).
Change readonly to readonly=on.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-08-16 12:43:14 -07:00
Omar Sandoval
8b4532ca0a libdrgn: debug_info: improve handling of DW_AT_data_member_location
There are a couple of issues with how we interpret
DW_AT_data_member_location:

1. DW_AT_data_member_location can be a location list, and we shouldn't
   interpret the section offset as the member offset.
2. DW_AT_data_member_location can be location description block, and in
   DWARF 2, it cannot be a constant. We should handle constant offset
   expressions as generated by GCC and Clang.

Closes #13.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-08-16 11:57:42 -07:00
Omar Sandoval
611e4d90b2 libdrgn: debug_info: support DWARF 3 forms for loclistptr
DWARF 3 uses DW_FORM_data4 or DW_FORM_data8 for DW_AT_location
loclistptrs.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-08-13 17:52:24 -07:00
Omar Sandoval
ad2119aaa3 Tell pytest not to match classes/functions starting with "test"
I run tests with setup.py or with the unittest module, but Fedora uses
pytest. pytest assumes that any class or function starting with "test"
is a test case, which is not always the case (e.g.,
drgn.helpers.linux.bitops.test_bit()). We've hit this at least twice, in
#94 and #112.

All of our tests are unittest.TestCase cases, so we can tell pytest to
not match anything else. I'm using pytest.ini instead of pyproject.toml
because pytest only started supporting the latter relatively recently.

Closes #112.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-08-12 14:46:47 -07:00
Omar Sandoval
ec3cb15bad drgn 0.0.14
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-08-12 11:57:07 -07:00
Omar Sandoval
861c61eda0 Update elfutils in manylinux wheels
Use the latest version of elfutils (0.185) and apply the fix "libdwfl:
fix potential NULL pointer dereference when reading link map" since that
hasn't been released yet and is needed to avoid crashing when debugging
userspace core dumps.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-08-12 11:53:22 -07:00
Peilin Ye
557b8152cc helpers: Add netdev_get_by_name()
Add a helper to get the network device ("struct net_device *") given an
interface name.  As an example:

    >>> netdev = netdev_get_by_name(prog["init_net"], "lo")
    >>> netdev.ifindex.value_()
    1

Or pass a "Program" as the first argument, and let the helper find in
the initial network namespace (i.e. "init_net"):

    >>> netdev = netdev_get_by_index(prog, "dummy0")
    >>> netdev.ifindex.value_()
    2

Also add a test for this new helper to tests/helpers/linux/test_net.py.

This helper simply does a linear search over the name hash table of the
network namespace, since implementing hashing in drgn is non-trivial.
It is obviously slower than net/core/dev.c:netdev_name_node_lookup() in
the kernel, but still useful.

Linux kernel commit ff92741270bf ("net: introduce name_node struct to be
used in hashlist") introduced struct netdev_name_node for name lookups.
Start by assuming that the kernel has this commit, and fall back to the
old path if that fails.

Signed-off-by: Peilin Ye <peilin.ye@bytedance.com>
2021-08-11 20:23:39 -07:00
Omar Sandoval
980d1c6418 helpers: fix annotation for type of entry helpers
All of these take a type which can also be a drgn.Type, not just a str.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-08-11 17:19:16 -07:00
Omar Sandoval
5541fad063 Fix some flake8 errors
Mainly unused imports, unused variables, unnecessary f-strings, and
regex literals missing the r prefix. I'm not adding it to the CI linter
because it's too noisy, though.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-08-11 14:52:44 -07:00
Omar Sandoval
65b65b27b0 helpers: fix drgn.helpers.linux.user.find_user() documented return type
And document that it returns NULL if the UID is not found.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-08-11 13:43:11 -07:00
Peilin Ye
e9915886f6 helpers: Add netdev_get_by_index()
Add a helper to find the corresponding "struct net_device *" object
given an interface index number.  As an example:

    >>> netdev = netdev_get_by_index(prog["init_net"], 1)
    >>> netdev.name.string_().decode()
    'lo'

Or pass a "Program" as the first argument, and let the helper find in
its initial network namespace (i.e. "init_net"):

    >>> netdev = netdev_get_by_index(prog, 3)
    >>> netdev.name.string_().decode()
    'enp0s3'

Also add a test for this new helper to tests/helpers/linux/test_net.py.

For now, a user may combine this new helper with socket.if_nametoindex()
to look up by interface name:

    >>> netdev = find_netdev_by_index(prog, socket.if_nametoindex("dummy0"))
    >>> netdev.name.string_().decode()
    'dummy0'

However, as mentioned by Cong, one should keep in mind that
socket.if_nametoindex() is based on system's current name-to-index
mapping, which may be different from that of e.g. a kdump.

Thus, as suggested by Omar, a better way to do name lookups would be
simply linear-searching the name hash table, which is slower, but less
erorr-prone.

Signed-off-by: Peilin Ye <peilin.ye@bytedance.com>
2021-08-11 13:36:32 -07:00
Omar Sandoval
51f63bb53b helpers: add node_state() to nodemask helpers
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-08-03 17:06:36 -07:00
Omar Sandoval
1213eb8f49 helpers: add bit operation helpers
Extract for_each_set_bit() that was added internally for the cpumask and
nodemask helpers, and add for_each_clear_bit() and test_bit() to go with
it.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-08-03 15:43:04 -07:00
Omar Sandoval
d6a47f8698 docs: improve stack trace documentation in user guide
The API reference has all of the details, but add a short example to the
user guide (and move it before symbols, as stack traces are probably
more interesting/important).

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-08-02 16:20:33 -07:00
Omar Sandoval
7382856a41 docs: improve quick start documentation
Add an example of stack traces and parameters/local variables and use
some more interesting helpers.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-08-02 16:20:30 -07:00
Omar Sandoval
39b76e8486 docs: update repr(drgn.Type) and type constructors in documentation
Commit a97f6c4fa2 ("Associate types with program") changed repr() for
drgn.Type to include a "prog." prefix, but it didn't update the
documentation to reflect that. It also forgot to update a global type
constructor to the new Program methods.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-08-02 15:59:43 -07:00
Qi Zheng
2f97cb4f75 helpers: add kernel nodemask helpers
Sometimes we want to traverse numa nodes in the system,
so add kernel nodemask helpers to support this.

Signed-off-by: Qi Zheng <zhengqi.arch@bytedance.com>
2021-07-29 19:28:59 -07:00
Omar Sandoval
dc0c0e05f8 setup.py: add 5.14 to vmtest kernels
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-07-29 17:52:58 -07:00
Omar Sandoval
df8da55a57 helpers: update task_state_to_char() for v5.14
Linux v5.14 renamed task_struct::state to task_struct::__state.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-07-29 17:40:49 -07:00
Omar Sandoval
50e3cf936a vmtest: add CONFIG_NUMA=y
We're adding NUMA node mask helpers in #107, so make sure we can run
them.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-07-29 17:04:52 -07:00
Omar Sandoval
7335df114c libdrgn: python: add Object.to_bytes_()
And the libdrgn implementation, drgn_object_read_bytes().

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-07-26 17:12:34 -07:00
Omar Sandoval
9c00552007 libdrgn: python: add Object.from_bytes_()
Add a way to create an object from raw bytes. One example where I've
wanted this is creating a struct pt_regs from a PRSTATUS note or other
source.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-07-26 17:06:58 -07:00
Omar Sandoval
ee0b8efc30 helpers: use correct size for for_each_cpu()
If the kernel is compiled with CONFIG_CPUMASK_OFFSTACK, then the full
struct cpumask::bits array may not be allocated. Use nr_cpu_ids as the
limit instead of the length of the array.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-07-26 14:26:24 -07:00
Omar Sandoval
a74716828d libdrgn: fix comment typo in serialize.h
s/grather/greater/g

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-07-21 20:32:53 -07:00
Omar Sandoval
a863f1e439 libdrgn: dwarf_index: print unknown forms in hexadecimal
The DWARF spec and dwarf.h list them in hexadecimal, so make it easier
to cross reference.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-07-09 01:52:08 -07:00
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