aboutsummaryrefslogtreecommitdiff
path: root/python/weenix/list.py
blob: 6f951ae1f3a386e2f6afdec9b0b93967d1abd1e0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import gdb
import weenix

_char_type = gdb.lookup_type("char")
_list_type = gdb.lookup_type("list_t")
_list_link_type = gdb.lookup_type("list_link_t")

class Link:

	def __init__(self, value, dtype=None, dmemb=None):
		self._value = value
		self._dtype = dtype
		self._dmemb = dmemb

	def value(self):
		return self._value

	def item(self, typ=None, memb=None):
		if (typ == None):
			typ = self._dtype
		if (memb == None):
			memb = self._dmemb
		if (typ == None or memb == None):
			raise RuntimeError("list reference requires "
							   "both type and member name")

		for field in gdb.lookup_type(typ).fields():
			if (field.name == memb):
				link = self._value.address.cast(_char_type.pointer())
				link -= (field.bitpos // 8)
				link = link.cast(gdb.lookup_type(typ).pointer())
				return link.dereference()
		raise weenix.WeenixError("no member {0} of {1}"
								 .format(memb, typ))

	def link_addr(self):
		return self._value.address

class List:

	def __init__(self, value, dtype=None, dmemb=None):
		self._value = value
		self._dtype = dtype
		self._dmemb = dmemb

	def __iter__(self):
		curr = self._value["l_next"].dereference()
		while (curr.address != self._value.address):
			yield Link(curr, self._dtype, self._dmemb)
			curr = curr["l_next"].dereference()
		raise StopIteration

	def __len__(self):
		try:
			return self.__count
		except AttributeError:
			self.__count = 0
			curr = self._value["l_next"].dereference()
			while (curr.address != self._value.address):
				curr = curr["l_next"].dereference()
				self.__count += 1
			return self.__count

	def __getitem__(self, key):
		if (type(key) != int):
			raise TypeError(key)

		for i, item in enumerate(self):
			if (i == key):
				return item
		raise IndexError(key)

def load(name, dtype=None, dmemb=None):
	weenix.assert_type(name, _list_type)

	if (dtype != None):
		try:
			if (not isinstance(dtype, gdb.Type)):
				typ = gdb.lookup_type(dtype)
			else:
				typ = dtype
		except RuntimeError:
			raise gdb.GdbError("no such type: {0}".format(dtype))
	
		found = False
		for field in typ.strip_typedefs().fields():
			if (field.name == dmemb):
				try:
					weenix.assert_type(field.type, _list_link_type)
				except gdb.GdbError as err:
					raise gdb.GdbError(
						"field '{0}' of type '{1}' has wrong type: {2}"
						.format(dmemb, dtype, str(err)))
				found = True
		if (not found):
			raise gdb.GdbError("'{0}' type does not contain field '{1}'"
							   .format(dtype, dmemb))

	value = name if isinstance(name, gdb.Value) else gdb.parse_and_eval(name)
	return List(value, dtype, dmemb)