class VectorCursorPrinter(PrettyPrinter): """Pretty-print Ada.Containers.Vectors.Cursor values.""" name = "Vector_Cursor" type_pattern = Match.TypeName( suffix=".cursor", pattern=Match.Struct( Match.Field("container", Match.Pointer(VectorPrinter.type_pattern)), Match.Field("index", Match.Integer()), ), ) def to_string(self): if self.value["container"]: vector = VectorPrinter(self.value["container"]) index = self.value["index"] try: element = str(vector.element(index)) except gdb.MemoryError: return "Cursor ([Invalid])" assoc = "{} => {}".format(index, element) else: assoc = "No_Element" return "Cursor ({})".format(assoc)
class VectorCursorPrinter(PrettyPrinter): """Pretty-print Ada.Containers.Vectors.Cursor values.""" name = 'Vector_Cursor' type_pattern = Match.TypeName( suffix='.cursor', pattern=Match.Struct( Match.Field('container', Match.Pointer(VectorPrinter.type_pattern)), Match.Field('index', Match.Integer()), )) def to_string(self): if self.value['container']: vector = VectorPrinter(self.value['container']) index = self.value['index'] try: element = str(vector.element(index)) except gdb.MemoryError: return 'Cursor ([Invalid])' assoc = '{} => {}'.format(index, element) else: assoc = 'No_Element' return 'Cursor ({})'.format(assoc)
class DoublyLinkedListCursorPrinter(PrettyPrinter): """Pretty-print Ada.Containers.Doubly_Linked_Lists.Cursor values.""" name = "Doubly_Linked_List_Cursor" type_pattern = Match.TypeName( suffix=".cursor", pattern=Match.Struct( Match.Field( "container", Match.Pointer(DoublyLinkedListPrinter.type_pattern), ), Match.Field("node", Match.Pointer()), ), ) def display_hint(self): return "array" def to_string(self): if self.value["container"]: try: assoc = "{}".format(self.value["node"]["element"]) except gdb.MemoryError: return "Cursor ([Invalid])" else: assoc = "No_Element" return "Cursor ({})".format(assoc)
class HashedMapCursorPrinter(PrettyPrinter): """Pretty-print Ada.Containers.Hashed_Maps.Cursor values.""" name = "Hashed_Map_Cursor" type_pattern = Match.TypeName( suffix=".cursor", pattern=Match.Struct( Match.Field("container", Match.Pointer(HashedMapPrinter.type_pattern)), Match.Field("node", Match.Pointer()), Match.Field("position", Match.TypeName(name="ada.containers.hash_type")), ), ) def to_string(self): if self.value["container"]: assoc = "{} => {}".format( self.value["node"]["key"], self.value["node"]["element"], ) else: assoc = "No_Element" return "Cursor ({})".format(assoc)
class HashedMapPrinter(BaseMapPrinter): """Pretty-print Ada.Containers.Hashed_Maps.Map values.""" name = "Hashed_Map" type_pattern = Match.TypeName( suffix=".map", pattern=Match.Struct( Match.Field("_parent"), Match.Field( "ht", get_htable_pattern( Match.Struct( Match.Field("key"), Match.Field("element"), Match.Field("next", Match.Pointer()), )), ), ), ) @property def length(self): return self.value["ht"]["length"] def get_node_iterator(self): return iterate(self.value["ht"])
class DoublyLinkedListCursorPrinter(PrettyPrinter): """Pretty-print Ada.Containers.Doubly_Linked_Lists.Cursor values.""" name = 'Doubly_Linked_List_Cursor' type_pattern = Match.TypeName( suffix='.cursor', pattern=Match.Struct( Match.Field('container', Match.Pointer(DoublyLinkedListPrinter.type_pattern)), Match.Field('node', Match.Pointer()), )) def display_hint(self): return 'array' def to_string(self): if self.value['container']: try: assoc = '{}'.format(self.value['node']['element']) except gdb.MemoryError: return 'Cursor ([Invalid])' else: assoc = 'No_Element' return 'Cursor ({})'.format(assoc)
class HashedMapPrinter(BaseMapPrinter): """Pretty-print Ada.Containers.Hashed_Maps.Map values.""" name = 'Hashed_Map' type_pattern = Match.TypeName(suffix='.map', pattern=Match.Struct( Match.Field('_parent'), Match.Field( 'ht', get_htable_pattern( Match.Struct( Match.Field('key'), Match.Field('element'), Match.Field( 'next', Match.Pointer()), ))), )) @property def length(self): return self.value['ht']['length'] def get_node_iterator(self): return iterate(self.value['ht'])
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 OrderedMapPrinter(BaseMapPrinter): """Pretty-print Ada.Containers.Ordered_Maps.Map values.""" name = 'Ordered_Map' type_pattern = Match.TypeName( suffix='.map', pattern=Match.Struct( Match.Field('_parent'), Match.Field( 'tree', get_rbtree_pattern( Match.Struct( Match.Field('parent', Match.Pointer()), Match.Field('left', Match.Pointer()), Match.Field('right', Match.Pointer()), Match.Field('color', Match.Enum()), Match.Field('key'), Match.Field('element'), ))), )) @property def length(self): return self.value['tree']['length'] def get_node_iterator(self): return dfs(self.value['tree'])
class OrderedMapPrinter(BaseMapPrinter): """Pretty-print Ada.Containers.Ordered_Maps.Map values.""" name = "Ordered_Map" type_pattern = Match.TypeName( suffix=".map", pattern=Match.Struct( Match.Field("_parent"), Match.Field( "tree", get_rbtree_pattern( Match.Struct( Match.Field("parent", Match.Pointer()), Match.Field("left", Match.Pointer()), Match.Field("right", Match.Pointer()), Match.Field("color", Match.Enum()), Match.Field("key"), Match.Field("element"), )), ), ), ) @property def length(self): return self.value["tree"]["length"] def get_node_iterator(self): return dfs(self.value["tree"])
class OrderedSetCursorPrinter(PrettyPrinter): """Pretty-print Ada.Containers.Ordered_Sets.Cursor values.""" name = 'Ordered_Set_Cursor' type_pattern = Match.TypeName( suffix='.cursor', pattern=Match.Struct( Match.Field('container', Match.Pointer(OrderedSetPrinter.type_pattern)), Match.Field('node', Match.Pointer()), )) def to_string(self): if self.value['container']: assoc = self.value['node']['element'] else: assoc = 'No_Element' return 'Cursor ({})'.format(assoc)
class OrderedSetCursorPrinter(PrettyPrinter): """Pretty-print Ada.Containers.Ordered_Sets.Cursor values.""" name = "Ordered_Set_Cursor" type_pattern = Match.TypeName( suffix=".cursor", pattern=Match.Struct( Match.Field("container", Match.Pointer(OrderedSetPrinter.type_pattern)), Match.Field("node", Match.Pointer()), ), ) def to_string(self): if self.value["container"]: assoc = self.value["node"]["element"] else: assoc = "No_Element" return "Cursor ({})".format(assoc)
class DoublyLinkedListPrinter(PrettyPrinter): """Pretty-print Ada.Containers.Doubly_Linked_Lists values.""" name = "Doubly_Linked_List" node_pattern = Match.TypeName( suffix=".node_type", pattern=Match.Struct( Match.Field("element"), Match.Field("next", Match.Pointer()), Match.Field("prev", Match.Pointer()), ), ) type_pattern = Match.TypeName( suffix=".list", pattern=Match.Struct( Match.Field("_parent"), Match.Field("first", Match.Pointer(node_pattern)), Match.Field("last", Match.Pointer(node_pattern)), Match.Field("length", Match.Integer()), Match.Field("tc"), ), ) def display_hint(self): return "array" @property def length(self): return self.value["length"] def children(self): if self.value["first"]: node = self.value["first"] for i in range(self.length): yield ("[{}]".format(i), node["element"]) node = node["next"] if node: raise gdb.MemoryError("The linked list seems invalid") def to_string(self): return "{} of length {}".format( pretty_typename(self.value.type), self.length, )
class HashedMapCursorPrinter(PrettyPrinter): """Pretty-print Ada.Containers.Hashed_Maps.Cursor values.""" name = 'Ordered_Map_Cursor' type_pattern = Match.TypeName( suffix='.cursor', pattern=Match.Struct( Match.Field('container', Match.Pointer(HashedMapPrinter.type_pattern)), Match.Field('node', Match.Pointer()), Match.Field('position', Match.TypeName(name='ada.containers.hash_type')), )) def to_string(self): if self.value['container']: assoc = '{} => {}'.format( self.value['node']['key'], self.value['node']['element'], ) else: assoc = 'No_Element' return 'Cursor ({})'.format(assoc)
class DoublyLinkedListPrinter(PrettyPrinter): """Pretty-print Ada.Containers.Doubly_Linked_Lists values.""" name = 'Doubly_Linked_List' node_pattern = Match.TypeName(suffix='.node_type', pattern=Match.Struct( Match.Field('element'), Match.Field('next', Match.Pointer()), Match.Field('prev', Match.Pointer()), )) type_pattern = Match.TypeName(suffix='.list', pattern=Match.Struct( Match.Field('_parent'), Match.Field('first', Match.Pointer(node_pattern)), Match.Field('last', Match.Pointer(node_pattern)), Match.Field('length', Match.Integer()), Match.Field('tc'), )) def display_hint(self): return 'array' @property def length(self): return self.value['length'] def children(self): if self.value['first']: node = self.value['first'] for i in range(self.length): yield ('[{}]'.format(i), node['element']) node = node['next'] if node: raise gdb.MemoryError('The linked list seems invalid') def to_string(self): return '{} of length {}'.format( pretty_typename(self.value.type), self.length, )
def get_rbtree_pattern(node_pattern): """ Return the type pattern for red-black trees used in GNAT's implementation of standard containers for nodes that match the given `node_pattern`. """ node_access_pattern = Match.Pointer(node_pattern) return Match.Struct( Match.Field("_tag"), Match.Field("first", node_access_pattern), Match.Field("last", node_access_pattern), Match.Field("root", node_access_pattern), Match.Field("length", Match.Integer()), Match.Field("tc"), )
def get_htable_pattern(node_pattern): """ Return the type pattern for hash tables used in GNAT's implementation of standard containers for nodes that match the given `node_pattern`. """ # TODO: unfortunately, due to the current state of DWARF/GDB, it is not # possible to reach `node_pattern` through hash table's value type. return Match.Struct( Match.Field('_tag'), # See below for the type of `buckets`. Match.Field( 'buckets', Match.Typedef( Match.Struct( Match.Field('P_ARRAY', Match.Pointer()), Match.Field('P_BOUNDS', Match.Pointer()), ))), Match.Field('length', Match.Integer()), Match.Field('tc'), )
import re from gnatdbg.generics import Match value = gdb.parse_and_eval('r') type_matcher = Match.Struct( Match.Field('i'), Match.Field('n', Match.TypeName(name='natural')), ) assert not type_matcher.match(value.type, debug=True)
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)
import re from gnatdbg.generics import Match nr = gdb.parse_and_eval('nr') r = gdb.parse_and_eval('r') i = gdb.parse_and_eval('i') # Only structs can match assert not Match.Struct().match(i.type) assert Match.Struct().match(nr.type) # The number of fields must match assert not Match.Struct(Match.Field('i')).match(nr.type) assert Match.Struct(Match.Field('i')).match(r.type) # The field names must match assert not Match.Struct(Match.Field('o')).match(r.type) assert Match.Struct(Match.Field('i')).match(r.type) # The field types must match assert not Match.Struct(Match.Field('i', Match.Char())).match(r.type) assert Match.Struct(Match.Field('i', Match.Integer())).match(r.type)
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)