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 struct
|
||||
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 (
|
||||
ArrayTypeName,
|
||||
BasicTypeName,
|
||||
@ -530,6 +541,28 @@ class CompoundType(Type):
|
||||
"""
|
||||
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:
|
||||
"""
|
||||
Return offsetof(type, member).
|
||||
@ -537,10 +570,7 @@ class CompoundType(Type):
|
||||
>>> print(prog['init_task'].fs.root.type_.offsetof('dentry'))
|
||||
8
|
||||
"""
|
||||
try:
|
||||
return self._members_by_name[member][0]
|
||||
except KeyError:
|
||||
raise ValueError(f'{str(self.type_name())!r} has no member {member!r}') from None
|
||||
return self._member(member)[1]
|
||||
|
||||
def typeof(self, member: str) -> Type:
|
||||
"""
|
||||
@ -549,10 +579,7 @@ class CompoundType(Type):
|
||||
>>> print(prog['init_task'].fs.root.type_.typeof('dentry'))
|
||||
struct dentry *
|
||||
"""
|
||||
try:
|
||||
return self._members_by_name[member][1]()
|
||||
except KeyError:
|
||||
raise ValueError(f'{str(self.type_name())!r} has no member {member!r}') from None
|
||||
return self._member(member)[0]
|
||||
|
||||
|
||||
class StructType(CompoundType):
|
||||
|
@ -67,6 +67,9 @@ line_segment_type = StructType('line_segment', 16, [
|
||||
('a', 0, 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)
|
||||
|
||||
|
||||
@ -212,6 +215,26 @@ struct line_segment {
|
||||
struct point a;
|
||||
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), """\
|
||||
struct {
|
||||
|
Loading…
Reference in New Issue
Block a user