drgn/tests/libdrgn.py
Omar Sandoval a98445c277 libdrgn: make type index pluggable with callbacks
Similar to "libdrgn: make memory reader pluggable with callbacks", we
want to support custom type indexes (imagine, e.g., using drgn to parse
a binary format). For now, this disables the dwarf index tests; we'll
have a better way to test them later, so let's not bother adding more
test scaffolding.
2019-05-06 14:55:34 -07:00

250 lines
7.3 KiB
Python

import ctypes
import enum
from enum import auto
import os
from typing import BinaryIO, NamedTuple, Optional, Sequence, Union
import drgn
from drgn.internal.mock import MockType
from tests import _drgn_pydll, _drgn_cdll
from tests.libelf import _Elf, Elf
from tests.libdw import _Dwarf_Die, Die
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.py_object
_drgn_pydll.set_drgn_error.argtypes = [ctypes.POINTER(_drgn_error)]
def _check_err(err):
if err:
return _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),
]
_drgn_pydll.DrgnType_wrap.restype = ctypes.py_object
_drgn_pydll.DrgnType_wrap.argtypes = [_drgn_qualified_type, ctypes.py_object]
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)