Skip to content

Commit

Permalink
Merge branch 'refs/heads/upstream-HEAD' into repo-HEAD
Browse files Browse the repository at this point in the history
  • Loading branch information
Delphix Engineering committed Mar 7, 2024
2 parents cc9f903 + a5da128 commit 705ee52
Show file tree
Hide file tree
Showing 14 changed files with 1,345 additions and 95 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ jobs:
strategy:
matrix:
python-version: ${{ (github.event_name == 'push' || inputs.test_all_python_versions)
&& fromJSON('["3.12", "3.11", "3.10", "3.9", "3.8", "3.7", "3.6"]')
&& fromJSON('["3.13", "3.12", "3.11", "3.10", "3.9", "3.8", "3.7", "3.6"]')
|| fromJSON('["3.12", "3.6"]')}}
cc: [gcc, clang]
fail-fast: false
Expand Down
23 changes: 20 additions & 3 deletions drgn/helpers/linux/idr.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,16 @@
"""

import operator
from typing import Iterator, Tuple
from typing import Iterator, Tuple, Union

from _drgn import _linux_helper_idr_find
from drgn import NULL, IntegerLike, Object, cast, sizeof
from drgn import NULL, IntegerLike, Object, Type, cast, sizeof
from drgn.helpers.linux.radixtree import radix_tree_for_each

__all__ = (
"idr_find",
"idr_for_each",
"idr_for_each_entry",
)

_IDR_BITS = 8
Expand Down Expand Up @@ -66,7 +67,7 @@ def idr_find(idr: Object, id: IntegerLike) -> Object:

def idr_for_each(idr: Object) -> Iterator[Tuple[int, Object]]:
"""
Iterate over all of the entries in an IDR.
Iterate over all of the pointers in an IDR.
:param idr: ``struct idr *``
:return: Iterator of (index, ``void *``) tuples.
Expand Down Expand Up @@ -97,3 +98,19 @@ def aux(p: Object, id: int, n: int) -> Iterator[Tuple[int, Object]]:
base = 0
for index, entry in radix_tree_for_each(idr_rt.address_of_()):
yield index + base, entry


def idr_for_each_entry(
idr: Object, type: Union[str, Type]
) -> Iterator[Tuple[int, Object]]:
"""
Iterate over all of the entries with the given type in an IDR.
:param idr: ``struct idr *``
:param type: Entry type.
:return: Iterator of (index, ``type *``) tuples.
"""
prog = idr.prog_
type = prog.pointer_type(prog.type(type))
for index, entry in idr_for_each(idr):
yield index, cast(type, entry)
99 changes: 99 additions & 0 deletions drgn/helpers/linux/plist.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
# Copyright (c) Meta Platforms, Inc. and affiliates.
# SPDX-License-Identifier: LGPL-2.1-or-later

"""
Priority-Sorted Lists
---------------------
The ``drgn.helpers.linux.plist`` module provides helpers for working with
descending-priority-sorted doubly-linked lists (``struct plist_head`` and
``struct plist_node``) from :linux:`include/linux/plist.h`.
"""

from typing import Iterator, Union

from drgn import Object, Type, container_of
from drgn.helpers.linux.list import list_empty, list_for_each_entry

__all__ = (
"plist_first_entry",
"plist_for_each",
"plist_for_each_entry",
"plist_head_empty",
"plist_last_entry",
"plist_node_empty",
)


def plist_head_empty(head: Object) -> bool:
"""
Return whether a plist is empty.
:param head: ``struct plist_head *``
"""
return list_empty(head.node_list.address_of_())


def plist_node_empty(node: Object) -> bool:
"""
Return whether a plist node is empty (i.e., not on a list).
:param node: ``struct plist_node *``
"""
return list_empty(node.node_list.address_of_())


def plist_first_entry(head: Object, type: Union[str, Type], member: str) -> Object:
"""
Return the first (highest priority) entry in a plist.
The list is assumed to be non-empty.
:param head: ``struct plist_head *``
:param type: Entry type.
:param member: Name of list node member in entry type.
:return: ``type *``
"""
return container_of(head.node_list.next, type, member + ".node_list")


def plist_last_entry(head: Object, type: Union[str, Type], member: str) -> Object:
"""
Return the last (lowest priority) entry in a plist.
The list is assumed to be non-empty.
:param head: ``struct plist_head *``
:param type: Entry type.
:param member: Name of list node member in entry type.
:return: ``type *``
"""
return container_of(head.node_list.prev, type, member + ".node_list")


def plist_for_each(head: Object) -> Iterator[Object]:
"""
Iterate over all of the nodes in a plist.
:param head: ``struct plist_head *``
:return: Iterator of ``struct plist_node *`` objects.
"""
return list_for_each_entry(
"struct plist_node", head.node_list.address_of_(), "node_list"
)


def plist_for_each_entry(
type: Union[str, Type], head: Object, member: str
) -> Iterator[Object]:
"""
Iterate over all of the entries in a plist.
:param type: Entry type.
:param head: ``struct plist_head *``
:param member: Name of plist node member in entry type.
:return: Iterator of ``type *`` objects.
"""
return list_for_each_entry(
type, head.node_list.address_of_(), member + ".node_list"
)
7 changes: 7 additions & 0 deletions libdrgn/python/object.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,12 @@ py_long_to_bytes_for_object_type(PyObject *value_obj,
PyErr_NoMemory();
return NULL;
}
#if PY_VERSION_HEX >= 0x030d00a4
Py_ssize_t r = PyLong_AsNativeBytes(long_obj, buf, size,
type->little_endian);
if (r < 0)
return NULL;
#else
// _PyLong_AsByteArray() still returns the least significant bytes on
// OverflowError unless the object is negative and is_signed is false.
// So, we always pass is_signed as true.
Expand All @@ -85,6 +91,7 @@ py_long_to_bytes_for_object_type(PyObject *value_obj,
return NULL;
}
}
#endif
return_ptr(buf);
}

Expand Down
Loading

0 comments on commit 705ee52

Please sign in to comment.