mirror of
https://github.com/JakeHillion/drgn.git
synced 2024-12-23 09:43:06 +00:00
type: make offsetof() and typeof() accept arbitrary member designators
Instead of only accepting an identifier.
This commit is contained in:
parent
8f46673649
commit
1916528f5d
45
drgn/type.py
45
drgn/type.py
@ -19,8 +19,19 @@ import numbers
|
|||||||
import re
|
import re
|
||||||
import struct
|
import struct
|
||||||
import sys
|
import sys
|
||||||
from typing import Any, Callable, Dict, FrozenSet, List, Optional, Tuple, Union
|
from typing import (
|
||||||
|
Any,
|
||||||
|
Callable,
|
||||||
|
Dict,
|
||||||
|
FrozenSet,
|
||||||
|
List,
|
||||||
|
Optional,
|
||||||
|
Tuple,
|
||||||
|
Union,
|
||||||
|
cast,
|
||||||
|
)
|
||||||
|
|
||||||
|
from drgn.memberdesignator import parse_member_designator
|
||||||
from drgn.typename import (
|
from drgn.typename import (
|
||||||
ArrayTypeName,
|
ArrayTypeName,
|
||||||
BasicTypeName,
|
BasicTypeName,
|
||||||
@ -530,6 +541,28 @@ class CompoundType(Type):
|
|||||||
"""
|
"""
|
||||||
return list(self._members_by_name)
|
return list(self._members_by_name)
|
||||||
|
|
||||||
|
def _member(self, member: str) -> Tuple[Type, int]:
|
||||||
|
designator = parse_member_designator(member)
|
||||||
|
type_: Type = self
|
||||||
|
offset = 0
|
||||||
|
for op, value in designator:
|
||||||
|
real_type = type_.real_type()
|
||||||
|
if op == '.':
|
||||||
|
if not isinstance(real_type, CompoundType):
|
||||||
|
raise ValueError('{str(type_.type_name())!r} is not a struct or union')
|
||||||
|
try:
|
||||||
|
member_offset, type_thunk = real_type._members_by_name[cast(str, value)]
|
||||||
|
except KeyError:
|
||||||
|
raise ValueError(f'{str(type_.type_name())!r} has no member {value!r}') from None
|
||||||
|
type_ = type_thunk()
|
||||||
|
offset += member_offset
|
||||||
|
else: # op == '[]'
|
||||||
|
if not isinstance(real_type, ArrayType):
|
||||||
|
raise ValueError('{str(type_.type_name())!r} is not an array')
|
||||||
|
type_ = real_type.type
|
||||||
|
offset += cast(int, value) * type_.sizeof()
|
||||||
|
return type_, offset
|
||||||
|
|
||||||
def offsetof(self, member: str) -> int:
|
def offsetof(self, member: str) -> int:
|
||||||
"""
|
"""
|
||||||
Return offsetof(type, member).
|
Return offsetof(type, member).
|
||||||
@ -537,10 +570,7 @@ class CompoundType(Type):
|
|||||||
>>> print(prog['init_task'].fs.root.type_.offsetof('dentry'))
|
>>> print(prog['init_task'].fs.root.type_.offsetof('dentry'))
|
||||||
8
|
8
|
||||||
"""
|
"""
|
||||||
try:
|
return self._member(member)[1]
|
||||||
return self._members_by_name[member][0]
|
|
||||||
except KeyError:
|
|
||||||
raise ValueError(f'{str(self.type_name())!r} has no member {member!r}') from None
|
|
||||||
|
|
||||||
def typeof(self, member: str) -> Type:
|
def typeof(self, member: str) -> Type:
|
||||||
"""
|
"""
|
||||||
@ -549,10 +579,7 @@ class CompoundType(Type):
|
|||||||
>>> print(prog['init_task'].fs.root.type_.typeof('dentry'))
|
>>> print(prog['init_task'].fs.root.type_.typeof('dentry'))
|
||||||
struct dentry *
|
struct dentry *
|
||||||
"""
|
"""
|
||||||
try:
|
return self._member(member)[0]
|
||||||
return self._members_by_name[member][1]()
|
|
||||||
except KeyError:
|
|
||||||
raise ValueError(f'{str(self.type_name())!r} has no member {member!r}') from None
|
|
||||||
|
|
||||||
|
|
||||||
class StructType(CompoundType):
|
class StructType(CompoundType):
|
||||||
|
@ -67,6 +67,9 @@ line_segment_type = StructType('line_segment', 16, [
|
|||||||
('a', 0, lambda: point_type),
|
('a', 0, lambda: point_type),
|
||||||
('b', 8, lambda: point_type),
|
('b', 8, lambda: point_type),
|
||||||
])
|
])
|
||||||
|
quadrilateral_type = StructType('quadrilateral', 16, [
|
||||||
|
('points', 0, lambda: ArrayType(point_type, 4)),
|
||||||
|
])
|
||||||
pointer_size = ctypes.sizeof(ctypes.c_void_p)
|
pointer_size = ctypes.sizeof(ctypes.c_void_p)
|
||||||
|
|
||||||
|
|
||||||
@ -212,6 +215,26 @@ struct line_segment {
|
|||||||
struct point a;
|
struct point a;
|
||||||
struct point b;
|
struct point b;
|
||||||
}""")
|
}""")
|
||||||
|
self.assertEqual(line_segment_type.offsetof('a.x'), 0)
|
||||||
|
self.assertEqual(line_segment_type.offsetof('a.y'), 4)
|
||||||
|
self.assertEqual(line_segment_type.offsetof('b.x'), 8)
|
||||||
|
self.assertEqual(line_segment_type.offsetof('b.y'), 12)
|
||||||
|
self.assertRaisesRegex(ValueError, 'no member',
|
||||||
|
line_segment_type.offsetof, 'c')
|
||||||
|
self.assertRaisesRegex(ValueError, 'not a struct or union',
|
||||||
|
line_segment_type.offsetof, 'a.x.z')
|
||||||
|
self.assertRaisesRegex(ValueError, 'not an array',
|
||||||
|
line_segment_type.offsetof, 'a[0]')
|
||||||
|
|
||||||
|
self.assertEqual(str(quadrilateral_type), """\
|
||||||
|
struct quadrilateral {
|
||||||
|
struct point points[4];
|
||||||
|
}""")
|
||||||
|
for i in range(5):
|
||||||
|
self.assertEqual(quadrilateral_type.offsetof(f'points[{i}].x'),
|
||||||
|
8 * i)
|
||||||
|
self.assertEqual(quadrilateral_type.offsetof(f'points[{i}].y'),
|
||||||
|
8 * i + 4)
|
||||||
|
|
||||||
self.assertEqual(str(anonymous_point_type), """\
|
self.assertEqual(str(anonymous_point_type), """\
|
||||||
struct {
|
struct {
|
||||||
|
Loading…
Reference in New Issue
Block a user