Commit Graph

1101 Commits

Author SHA1 Message Date
Jay Kamat
8bf26fafbb dwarf_index.c: lazily allocate shards to save memory on unused ns
Previously shards were allocated as soon as a namespace was
encountered, which means that we had a large array sitting around for
every ns we saw. By allocating them lazily, we can reduce this usage.

Signed-off-by: Jay Kamat <jaygkamat@gmail.com>
2021-10-26 02:07:26 -07:00
Omar Sandoval
1339dc6a2f libdrgn: hash_table: move entry_to_key to DEFINE_HASH_TABLE_FUNCTIONS()
DEFINE_HASH_TABLE_TYPE() doesn't actually need to know the key type.
Move that argument (and some of the derived constants) to
DEFINE_HASH_TABLE_FUNCTIONS(). This will allow recursive hash table
types. As a nice side effect, it also reduces the size of common header
files.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-10-23 00:52:23 -07:00
Omar Sandoval
802d6cc9ff libdrgn: rename drgn_program::_dbinfo to dbinfo
The underscore was meant to discourage direct access in favor of using
drgn_program_get_dbinfo(), but it turns out that it's more normal to
access it directly.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-10-23 00:52:23 -07:00
Omar Sandoval
c1e16ae3ec libdrgn: fold drgn_program_get_dbinfo() into only caller
The only time that we want to create the drgn_debug_info is when we're
loading debugging information. Everywhere else, we fail fast if there is
no debugging information.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-10-23 00:40:57 -07:00
Omar Sandoval
1d4dbc2b69 libdrgn: python: remove unused declaration
drgnpy_linux_helper_task_state_to_char() was removed by commit
ff96c75da0 ("helpers: translate task_state_to_char() to Python"), but
I left behind the declaration.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-10-12 18:01:42 -07:00
Omar Sandoval
734cbe5c7b libdrgn: dwarf_index: free pending DIEs after indexing namespace
Once we've cleared the pending DIEs vector, we won't use the vector
again (unless we load more debugging information), so we can free it.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-09-28 13:56:52 -07:00
Omar Sandoval
b4a82c30ab Add GitHub action to check for DCO sign-off on pull requests
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-09-28 12:32:15 -07:00
Jake Hillion
b0ae2867d5 splay_tree.c: Rename splay_tree to avoid conflicts with splay-tree.h
When linking libdrgn as a static library, the name 'splay_tree' can
conflict with splay-tree.h in libiberty (namely splay_tree_splay).

Rename relevant functions to have a 'drgn_' prefix

Signed-off-by: Jake Hillion <jakehillion@fb.com>
2021-09-27 12:56:47 -07:00
Jay Kamat
2baee6fe16 dwarf_index.c: Shrink abbrev tables before saving them in CUs
In larger binaries, there can be a large number of CUs, and since we
store an abbrev table for each CU the extra space starts to add up.
The simplest way to mitigate this is to shrink the vectors before
saving them.

On a large binary, I noticed a memory reduction from 20.4G RES to
18.6G RES (on initial load-in).
2021-09-27 12:08:25 -07:00
Omar Sandoval
c64d87e41a setup.py: add 5.15 to vmtest kernels
Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-09-13 09:59:22 -07:00
Omar Sandoval
801f9d645c tests: improve cgroup helper tests
These haven't been running in vmtest since they were added. Enable
cgroup2 in vmtest and rework the cgroup tests to create cgroups that we
can test with.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-09-02 16:05:46 -07:00
Peilin Ye
f82273749d helpers: Add qdisc_lookup()
Add a helper, qdisc_lookup(), to get a Qdisc (struct Qdisc *) from a
network device and a major handle number.  As an example:

	>>> eth0 = netdev_get_by_name(prog, "eth0")
	>>> tbf = qdisc_lookup(eth0, 0x20)
	>>> tbf.ops.id.string_().decode()
	tbf
	>>> ingress = qdisc_lookup(eth0, 0xffff)
	>>> ingress.ops.id.string_().decode()
	ingress

Testing depends on pyroute2.  `TestTc` is skipped if pyroute2 is not
found; test_qdisc_lookup() is skipped if the kernel is not built with the
following options:

	CONFIG_DUMMY
	CONFIG_NET_SCH_PRIO
	CONFIG_NET_SCH_SFQ
	CONFIG_NET_SCH_TBF
	CONFIG_NET_SCH_INGRESS

Suggested-by: Cong Wang <cong.wang@bytedance.com>
Signed-off-by: Peilin Ye <peilin.ye@bytedance.com>
2021-09-02 11:03:00 -07:00
Peilin Ye
a01131483d helpers: Add netdev_for_each_tx_queue()
Add a helper, netdev_for_each_tx_queue(), to iterate over all TX queues of
a network device.  As an example:

	>>> eth0 = netdev_get_by_name(prog, "eth0")
	>>> for txq in netdev_for_each_tx_queue(eth0):
	...     print(txq.qdisc.ops.id.string_().decode())
	...
	sfq
	tbf
	prio
	pfifo_fast

Set up `net` in setUpClass(), since now several tests use it.  Also use
it in test_netdev_get_by_{index,name}(), instead of assuming `init_net`.

Signed-off-by: Peilin Ye <peilin.ye@bytedance.com>
2021-09-02 11:03:00 -07:00
Omar Sandoval
62efd2aab3 vmtest: use virtio-rng
Now that the kernel module is enabled, let's enable the device and load
the module.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-09-02 09:31:47 -07:00
Omar Sandoval
ce845ad340 vmtest: add virtio-rng and cgroup Kconfig options
We're seeing some hangs waiting for entropy when running tests, so let's
enable the virtio-rng module. While we're doing a rebuild, we might as
well enable cgroups so that we can finally run those tests.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
2021-09-02 09:12:19 -07:00
Omar Sandoval
3c68b25215 CI: install pyroute2
This is needed to test #117.

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