coredump: add rvalue objects

Sometimes it's useful to have a computed object that does not exist in
the coredump itself (e.g., when doing pointer arithmetic). Introduce the
notion of "rvalues", which have an explicit value instead of an address.
This commit is contained in:
Omar Sandoval 2018-04-09 21:14:23 -07:00
parent 366a706a96
commit d5ba112e36

View File

@ -7,17 +7,18 @@ from drgn.type import (
)
from drgn.type import TypeName
import itertools
from typing import Any, Callable, Iterable, Tuple, Union
from typing import Any, Callable, Iterable, Optional, Tuple, Union
class CoredumpObject:
"""
CoredumpObject(coredump, address, type) -> new object
CoredumpObject(coredump, address, type, value=None) -> new object
A CoredumpObject represents an object in the memory of a program. It has
three members: coredump_, the program this object is from; address_, the
location in memory where this object resides in the program; and type_, the
type of this object in the program.
A CoredumpObject either represents an object in the memory of a program (an
"lvalue") or a temporary computed value (an "rvalue"). It has three
members: coredump_, the program this object is from; address_, the location
in memory where this object resides in the program (or None if it is not an
lvalue); and type_, the type of this object in the program.
CoredumpObjects try to behave transparently like the object they represent
in C. E.g., structure members can be accessed with the dot (".") operator
@ -33,13 +34,19 @@ class CoredumpObject:
conflict.
"""
def __init__(self, coredump: 'Coredump', address: int, type: Type) -> None:
def __init__(self, coredump: 'Coredump', address: Optional[int],
type: Type, value: Any = None) -> None:
if address is not None and value is not None:
raise ValueError('object cannot have address and value')
if address is None and value is None:
raise ValueError('object must have either address or value')
self.coredump_ = coredump
self.address_ = address
self.type_ = type
while isinstance(type, TypedefType):
type = type.type
self._real_type = type
self._value = value
def __getattr__(self, name: str) -> 'CoredumpObject':
"""Implement self.name. Shortcurt for self.member_(name)"""
@ -72,7 +79,19 @@ class CoredumpObject:
return CoredumpObject(self.coredump_, address + offset, type_)
def __repr__(self) -> str:
return f'CoredumpObject(address=0x{self.address_:x}, type=<{self.type_.type_name()}>)'
parts = [
'CoredumpObject(address=',
'None' if self.address_ is None else hex(self.address_), ', ',
'type=<', str(self.type_.type_name()), '>',
]
if self._value is not None:
parts.append(', value=')
if isinstance(self._real_type, PointerType):
parts.append(hex(self._value))
else:
parts.append(repr(self._value))
parts.append(')')
return ''.join(parts)
def __str__(self) -> str:
"""
@ -88,9 +107,12 @@ class CoredumpObject:
For basic types (int, bool, etc.), this returns an object of the
directly corresponding Python type. For pointers, this returns the
address value of the pointer. For enums, this returns an enum.IntEnum
object. For structures and unions, this returns an OrderedDict of
members. For arrays, this returns a list of values.
object or an int. For structures and unions, this returns an
OrderedDict of members. For arrays, this returns a list of values.
"""
if self._value is not None:
return self._value
assert self.address_ is not None
buffer = self.coredump_.read(self.address_, self._real_type.sizeof())
return self._real_type.read(buffer)
@ -148,7 +170,7 @@ class CoredumpObject:
"""
if not isinstance(type, Type):
type = self.coredump_.type(type)
return CoredumpObject(self.coredump_, self.address_, type)
return CoredumpObject(self.coredump_, self.address_, type, self._value)
def container_of_(self, type: Union[str, Type, TypeName],
member: str) -> 'CoredumpObject':
@ -167,7 +189,10 @@ class CoredumpObject:
if not isinstance(self._real_type, PointerType):
raise ValueError('container_of is only valid on pointers')
address = self.value_() - type.offsetof(member)
return CoredumpObject(self.coredump_, address, type)
return CoredumpObject(self.coredump_, None,
PointerType(self._real_type.size, type,
self._real_type.qualifiers),
address)
class Coredump:
@ -192,14 +217,15 @@ class Coredump:
"""
return self.variable(name)
def object(self, address: int, type: Union[str, Type, TypeName]) -> CoredumpObject:
def object(self, address: int, type: Union[str, Type, TypeName],
value: Any = None) -> CoredumpObject:
"""
Return a CoredumpObject with the given address of the given type. The
type can be a string, Type object, or TypeName object.
"""
if not isinstance(type, Type):
type = self.type(type)
return CoredumpObject(self, address, type)
return CoredumpObject(self, address, type, value)
def read(self, address: int, size: int) -> bytes:
"""