class StringAccess(object): """ Helper class to inspect String accesses. """ type_pattern = Match.Typedef( Match.Struct( Match.Field('P_ARRAY', Match.Pointer(Match.Array(element=Match.Char(), ))), Match.Field('P_BOUNDS'), )) default_encodings = { 1: None, 2: 'utf-16', 4: 'utf-32', } def __init__(self, value): if not self.matches(value): raise TypeError('Input is not an access to string') self.value = value @classmethod def matches(cls, value): """ Return whether `value` is a string access. :param gdb.Value value: Value to test. :rtype: bool """ return cls.type_pattern.match(value.type) @property def bounds(self): """ Return the bounds of the accessed string. :rtype: (int, int) """ struct = self.value['P_BOUNDS'] return (int(struct['LB0']), int(struct['UB0'])) @property def length(self): lb, ub = self.bounds return 0 if lb > ub else (ub - lb + 1) def get_string(self, encoding=None, errors=None): """ Return the accessed string. :rtype: str """ return _fetch_string(self.value['P_ARRAY'], self.length, encoding, errors)
class StringAccess(object): """ Helper class to inspect String accesses. """ type_pattern = Match.Typedef( Match.Struct( Match.Field( "P_ARRAY", Match.Pointer( Match.Array( element=Match.Char(), ) ), ), Match.Field("P_BOUNDS"), ) ) def __init__(self, value): if not self.matches(value): raise TypeError("Input is not an access to string") self.value = value @classmethod def matches(cls, value): """ Return whether `value` is a string access. :param gdb.Value value: Value to test. :rtype: bool """ return cls.type_pattern.match(value.type) @property def bounds(self): """ Return the bounds of the accessed string. :rtype: (int, int) """ struct = self.value["P_BOUNDS"] return (int(struct["LB0"]), int(struct["UB0"])) @property def length(self): lb, ub = self.bounds return 0 if lb > ub else (ub - lb + 1) def _ptr(self): """Return the string pointer for this value.""" access = self.value["P_ARRAY"] ptr_to_elt_type = access.type.target().target().pointer() return access.cast(ptr_to_elt_type) @property def is_valid(self): """Return True if the string is valid (has non-zero address).""" return self._ptr() != 0 def get_string(self): """ Return the accessed string. :rtype: str """ return self._ptr().lazy_string(length=self.length)
class VectorPrinter(PrettyPrinter): """Pretty-print Ada.Containers.Vectors.Vector values.""" name = 'Vector' type_pattern = Match.TypeName( suffix='.vector', pattern=Match.Struct( Match.Field('_parent'), Match.Field( 'elements', Match.Pointer( Match.Struct( Match.Field('last', Match.Integer()), Match.Field('ea', Match.Array()), ))), Match.Field('last', Match.Integer()), Match.Field('tc'), )) def display_hint(self): return 'array' @property def array_bounds(self): elements = self.value['elements'] if not elements: return (1, 0) array_type = elements['ea'].type first_index, _ = array_type.range() last_index = int(self.value['last']) return (first_index, last_index) @property def length(self): first, last = self.array_bounds if first <= last: return last - first + 1 else: return 0 @property def array_elements(self): first, last = self.array_bounds if first <= last: base_value = self.value['elements']['ea'] return base_value.cast(base_value.type.target().array(first, last)) else: return None def element(self, index): first, last = self.array_bounds if first <= index and index <= last: return self.array_elements[index] else: raise gdb.MemoryError( 'Out of bound vector access ({} not in {} .. {})'.format( index, first, last)) def children(self): elements = self.array_elements if elements: first_index, last_index = elements.type.range() for i in range(first_index, last_index + 1): elt = elements[i] elt.fetch_lazy() yield ('[{}]'.format(i), elt) def to_string(self): return '{} of length {}'.format(pretty_typename(self.value.type), self.length)
class VectorPrinter(PrettyPrinter): """Pretty-print Ada.Containers.Vectors.Vector values.""" name = "Vector" type_pattern = Match.TypeName( suffix=".vector", pattern=Match.Struct( Match.Field("_parent"), Match.Field( "elements", Match.Pointer( Match.Struct( Match.Field("last", Match.Integer()), Match.Field("ea", Match.Array()), )), ), Match.Field("last", Match.Integer()), Match.Field("tc"), ), ) def display_hint(self): return "array" @property def array_bounds(self): elements = self.value["elements"] if not elements: return (1, 0) array_type = elements["ea"].type first_index, _ = array_type.range() last_index = int(self.value["last"]) return (first_index, last_index) @property def length(self): first, last = self.array_bounds if first <= last: return last - first + 1 else: return 0 @property def array_elements(self): first, last = self.array_bounds if first <= last: base_value = self.value["elements"]["ea"] return base_value.cast(base_value.type.target().array(first, last)) else: return None def element(self, index): first, last = self.array_bounds if first <= index and index <= last: return self.array_elements[index] else: raise gdb.MemoryError( "Out of bound vector access ({} not in {} .. {})".format( index, first, last)) def children(self): elements = self.array_elements if elements: first_index, last_index = elements.type.range() for i in range(first_index, last_index + 1): elt = elements[i] elt.fetch_lazy() yield ("[{}]".format(i), elt) def to_string(self): return "{} of length {}".format(pretty_typename(self.value.type), self.length)
import re from gnatdbg.generics import Match s = gdb.parse_and_eval('s') char_type = s.type.target() # Only arrays can match assert not Match.Array().match(s.type.target()) assert Match.Array().match(s.type) # The element type must match assert not Match.Array(element=Match.Array()).match(s.type) assert Match.Array(element=Match.Char()).match(s.type) # The first bound must match assert not Match.Array(first=2).match(s.type) assert Match.Array(first=1).match(s.type) # The last bound must match assert not Match.Array(last=1).match(s.type) assert Match.Array(last=2).match(s.type)