mirror of
https://github.com/JakeHillion/drgn.git
synced 2024-12-26 02:25:36 +00:00
660276a0b8
I'm not a fan of 100% of the Black coding style, but I've spent too much time manually formatting Python code, so let's just pull the trigger.
273 lines
6.9 KiB
Python
273 lines
6.9 KiB
Python
import ctypes
|
|
import enum
|
|
from enum import auto
|
|
import os
|
|
|
|
import drgn
|
|
import _drgn
|
|
|
|
|
|
_drgn_pydll = ctypes.PyDLL(_drgn.__file__)
|
|
_drgn_cdll = ctypes.CDLL(_drgn.__file__)
|
|
|
|
|
|
class _drgn_error(ctypes.Structure):
|
|
_fields_ = [
|
|
("code", ctypes.c_uint),
|
|
("errnum", ctypes.c_int),
|
|
("path", ctypes.c_char_p),
|
|
("msg", ctypes.c_char_p),
|
|
]
|
|
|
|
|
|
_drgn_pydll.set_drgn_error.restype = ctypes.c_void_p
|
|
_drgn_pydll.set_drgn_error.argtypes = [ctypes.POINTER(_drgn_error)]
|
|
|
|
|
|
def _check_err(err):
|
|
if err:
|
|
_drgn_pydll.set_drgn_error(err)
|
|
|
|
|
|
class _path_iterator_component(ctypes.Structure):
|
|
_fields_ = [
|
|
("path", ctypes.c_char_p),
|
|
("len", ctypes.c_size_t),
|
|
]
|
|
|
|
|
|
class _path_iterator(ctypes.Structure):
|
|
_fields_ = [
|
|
("components", ctypes.POINTER(_path_iterator_component)),
|
|
("num_components", ctypes.c_size_t),
|
|
("dot_dot", ctypes.c_size_t),
|
|
]
|
|
|
|
|
|
_drgn_cdll.drgn_test_path_iterator_next.restype = ctypes.c_bool
|
|
_drgn_cdll.drgn_test_path_iterator_next.argtypes = [
|
|
ctypes.POINTER(_path_iterator),
|
|
ctypes.POINTER(ctypes.POINTER(ctypes.c_char)),
|
|
ctypes.POINTER(ctypes.c_size_t),
|
|
]
|
|
|
|
|
|
class PathIterator:
|
|
def __init__(self, *paths):
|
|
components = (_path_iterator_component * len(paths))()
|
|
for i, path in enumerate(paths):
|
|
path = os.fsencode(path)
|
|
components[i].path = path
|
|
components[i].len = len(path)
|
|
self._it = _path_iterator(components, len(paths))
|
|
|
|
def __iter__(self):
|
|
return self
|
|
|
|
def __next__(self):
|
|
component = ctypes.POINTER(ctypes.c_char)()
|
|
component_len = ctypes.c_size_t()
|
|
if _drgn_cdll.drgn_test_path_iterator_next(
|
|
ctypes.pointer(self._it),
|
|
ctypes.pointer(component),
|
|
ctypes.pointer(component_len),
|
|
):
|
|
return os.fsdecode(ctypes.string_at(component, component_len.value))
|
|
else:
|
|
raise StopIteration()
|
|
|
|
|
|
_drgn_cdll.drgn_test_path_ends_with.restype = ctypes.c_bool
|
|
_drgn_cdll.drgn_test_path_ends_with.argtypes = [
|
|
ctypes.POINTER(_path_iterator),
|
|
ctypes.POINTER(_path_iterator),
|
|
]
|
|
|
|
|
|
def path_ends_with(path1: PathIterator, path2: PathIterator):
|
|
return _drgn_cdll.drgn_test_path_ends_with(
|
|
ctypes.pointer(path1._it), ctypes.pointer(path2._it)
|
|
)
|
|
|
|
|
|
class _drgn_type(ctypes.Structure):
|
|
pass
|
|
|
|
|
|
class _drgn_qualified_type(ctypes.Structure):
|
|
_fields_ = [
|
|
("type", ctypes.POINTER(_drgn_type)),
|
|
("qualifiers", ctypes.c_uint),
|
|
]
|
|
|
|
|
|
class _drgn_token(ctypes.Structure):
|
|
_fields_ = [
|
|
("kind", ctypes.c_int),
|
|
("value", ctypes.c_void_p),
|
|
("len", ctypes.c_size_t),
|
|
]
|
|
|
|
|
|
class _drgn_lexer(ctypes.Structure):
|
|
_fields_ = [
|
|
("func", ctypes.c_void_p),
|
|
("p", ctypes.c_void_p),
|
|
("stack", ctypes.POINTER(_drgn_token)),
|
|
("stack_len", ctypes.c_size_t),
|
|
("stack_capacity", ctypes.c_size_t),
|
|
]
|
|
|
|
|
|
drgn_lexer_func = ctypes.CFUNCTYPE(
|
|
ctypes.POINTER(_drgn_error),
|
|
ctypes.POINTER(_drgn_lexer),
|
|
ctypes.POINTER(_drgn_token),
|
|
)
|
|
|
|
|
|
_drgn_cdll.drgn_test_lexer_init.restype = None
|
|
_drgn_cdll.drgn_test_lexer_init.argtypes = [
|
|
ctypes.POINTER(_drgn_lexer),
|
|
ctypes.POINTER(drgn_lexer_func),
|
|
ctypes.c_char_p,
|
|
]
|
|
_drgn_cdll.drgn_test_lexer_deinit.restype = None
|
|
_drgn_cdll.drgn_test_lexer_deinit.argtypes = [ctypes.POINTER(_drgn_lexer)]
|
|
_drgn_cdll.drgn_test_lexer_pop.restype = ctypes.POINTER(_drgn_error)
|
|
_drgn_cdll.drgn_test_lexer_pop.argtypes = [
|
|
ctypes.POINTER(_drgn_lexer),
|
|
ctypes.POINTER(_drgn_token),
|
|
]
|
|
_drgn_cdll.drgn_test_lexer_push.restype = ctypes.POINTER(_drgn_error)
|
|
_drgn_cdll.drgn_test_lexer_push.argtypes = [
|
|
ctypes.POINTER(_drgn_lexer),
|
|
ctypes.POINTER(_drgn_token),
|
|
]
|
|
_drgn_cdll.drgn_test_lexer_peek.restype = ctypes.POINTER(_drgn_error)
|
|
_drgn_cdll.drgn_test_lexer_peek.argtypes = [
|
|
ctypes.POINTER(_drgn_lexer),
|
|
ctypes.POINTER(_drgn_token),
|
|
]
|
|
|
|
|
|
drgn_lexer_c = drgn_lexer_func.in_dll(_drgn_cdll, "drgn_test_lexer_c")
|
|
drgn_test_lexer_func = drgn_lexer_func.in_dll(_drgn_cdll, "drgn_test_lexer_func")
|
|
|
|
|
|
class C_TOKEN(enum.IntEnum):
|
|
EOF = -1
|
|
VOID = auto()
|
|
CHAR = auto()
|
|
SHORT = auto()
|
|
INT = auto()
|
|
LONG = auto()
|
|
SIGNED = auto()
|
|
UNSIGNED = auto()
|
|
BOOL = auto()
|
|
FLOAT = auto()
|
|
DOUBLE = auto()
|
|
COMPLEX = auto()
|
|
CONST = auto()
|
|
RESTRICT = auto()
|
|
VOLATILE = auto()
|
|
ATOMIC = auto()
|
|
STRUCT = auto()
|
|
UNION = auto()
|
|
ENUM = auto()
|
|
LPAREN = auto()
|
|
RPAREN = auto()
|
|
LBRACKET = auto()
|
|
RBRACKET = auto()
|
|
ASTERISK = auto()
|
|
DOT = auto()
|
|
NUMBER = auto()
|
|
IDENTIFIER = auto()
|
|
|
|
|
|
class Token:
|
|
def __init__(self, token):
|
|
self._token = token
|
|
|
|
@property
|
|
def kind(self):
|
|
return self._token.kind
|
|
|
|
@property
|
|
def value(self):
|
|
return ctypes.string_at(self._token.value, self._token.len).decode()
|
|
|
|
def __repr__(self):
|
|
return f"Token({self.kind}, {self.value!r})"
|
|
|
|
|
|
class Lexer:
|
|
def __init__(self, func, str):
|
|
self._lexer = _drgn_lexer()
|
|
self._func = func
|
|
self._str = str.encode()
|
|
_drgn_cdll.drgn_test_lexer_init(
|
|
ctypes.pointer(self._lexer), self._func, self._str
|
|
)
|
|
|
|
def __del__(self):
|
|
_drgn_cdll.drgn_test_lexer_deinit(ctypes.pointer(self._lexer))
|
|
|
|
def pop(self):
|
|
token = _drgn_token()
|
|
_check_err(
|
|
_drgn_cdll.drgn_test_lexer_pop(
|
|
ctypes.pointer(self._lexer), ctypes.pointer(token)
|
|
)
|
|
)
|
|
return Token(token)
|
|
|
|
def push(self, token):
|
|
_check_err(
|
|
_drgn_cdll.drgn_test_lexer_push(
|
|
ctypes.pointer(self._lexer), ctypes.pointer(token._token)
|
|
)
|
|
)
|
|
|
|
def peek(self):
|
|
token = _drgn_token()
|
|
_check_err(
|
|
_drgn_cdll.drgn_test_lexer_peek(
|
|
ctypes.pointer(self._lexer), ctypes.pointer(token)
|
|
)
|
|
)
|
|
return Token(token)
|
|
|
|
|
|
_drgn_cdll.drgn_test_serialize_bits.restype = None
|
|
_drgn_cdll.drgn_test_serialize_bits.argtypes = [
|
|
ctypes.c_void_p,
|
|
ctypes.c_uint64,
|
|
ctypes.c_uint64,
|
|
ctypes.c_uint8,
|
|
ctypes.c_bool,
|
|
]
|
|
_drgn_cdll.drgn_test_deserialize_bits.restype = ctypes.c_uint64
|
|
_drgn_cdll.drgn_test_deserialize_bits.argtypes = [
|
|
ctypes.c_void_p,
|
|
ctypes.c_uint64,
|
|
ctypes.c_uint8,
|
|
ctypes.c_bool,
|
|
]
|
|
|
|
|
|
def serialize_bits(buf, bit_offset, uvalue, bit_size, little_endian):
|
|
assert (bit_offset + bit_size + 7) // 8 <= len(buf)
|
|
c_buf = (ctypes.c_char * len(buf)).from_buffer(buf)
|
|
return _drgn_cdll.drgn_test_serialize_bits(
|
|
c_buf, bit_offset, uvalue, bit_size, little_endian
|
|
)
|
|
|
|
|
|
def deserialize_bits(buf, bit_offset, bit_size, little_endian):
|
|
assert (bit_offset + bit_size + 7) // 8 <= len(buf)
|
|
c_buf = (ctypes.c_char * len(buf)).from_buffer_copy(buf)
|
|
return _drgn_cdll.drgn_test_deserialize_bits(
|
|
c_buf, bit_offset, bit_size, little_endian
|
|
)
|