mirror of
https://github.com/JakeHillion/drgn.git
synced 2024-12-23 09:43:06 +00:00
4213bea149
Currently, looking up a type with template arguments results in an "invalid character" syntax error on the "<" character. The DWARF index includes template arguments in indexed names, so we need to do lookups including the template arguments. Full support for this would require parsing the template argument list syntax and normalizing it or looking it up as an AST in some way. For now, it's at least an improvement to pass the user's string verbatim. To do so, kludge it by adding a token containing everything from "<" to the matching ">" to the C++ lexer and appending that to the identifier. Co-authored-by: Omar Sandoval <osandov@osandov.com> Signed-off-by: Omar Sandoval <osandov@osandov.com> Signed-off-by: Kevin Svetlitski <svetlitski@meta.com>
285 lines
7.2 KiB
Python
285 lines
7.2 KiB
Python
# Copyright (c) Meta Platforms, Inc. and affiliates.
|
|
# SPDX-License-Identifier: LGPL-2.1-or-later
|
|
|
|
import ctypes
|
|
import enum
|
|
from enum import auto
|
|
import os
|
|
|
|
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),
|
|
]
|
|
|
|
|
|
class _drgn_c_family_lexer(ctypes.Structure):
|
|
_fields_ = [
|
|
("lexer", _drgn_lexer),
|
|
("cpp", ctypes.c_bool),
|
|
]
|
|
|
|
|
|
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_c_family_lexer_func = 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()
|
|
CLASS = auto()
|
|
ENUM = auto()
|
|
LPAREN = auto()
|
|
RPAREN = auto()
|
|
LBRACKET = auto()
|
|
RBRACKET = auto()
|
|
ASTERISK = auto()
|
|
DOT = auto()
|
|
NUMBER = auto()
|
|
IDENTIFIER = auto()
|
|
TEMPLATE_ARGUMENTS = 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, cpp=False):
|
|
self._c_family_lexer = _drgn_c_family_lexer()
|
|
self._lexer = self._c_family_lexer.lexer
|
|
self._func = func
|
|
self._str = str.encode()
|
|
self._c_family_lexer.cpp = cpp
|
|
_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
|
|
)
|