aboutsummaryrefslogtreecommitdiff
path: root/python/weenix/kmem.py
blob: 8f8a6f2f8fc42444b1931a1577a4d796ccc74343 (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
101
102
103
104
105
106
107
108
109
import gdb
import weenix

import weenix.list

PAGE_SIZE = 4096

_uint32_type = gdb.lookup_type("uint32_t")
_uintptr_type = gdb.lookup_type("uintptr_t")
_slab_type = gdb.lookup_type("struct slab")
_allocator_type = gdb.lookup_type("struct slab_allocator")
_bufctl_type = gdb.lookup_type("struct slab_bufctl")
_void_type = gdb.lookup_type("void")

# for Python 3 compatibility, where xrange is done away with
try:
    xrange
except NameError:
    xrange = range

class Slab:

	def __init__(self, alloc, val):
		self._alloc = alloc
		if (val.type.code == gdb.TYPE_CODE_PTR):
			self._value = val.cast(_slab_type.pointer()).dereference()
		else:
			self._value = val.cast(_slab_type)

	def objs(self, typ=None):
		next = self._value["s_addr"]
		for i in xrange(int(self._alloc["sa_slab_nobjs"])):
			bufctl = (next.cast(_uintptr_type)
					  + self._alloc["sa_objsize"]).cast(_bufctl_type.pointer())
			if (bufctl.dereference()["u"]["sb_slab"] == self._value.address):
				# if redzones are in effect we need to skip them
				if (int(next.cast(_uint32_type.pointer()).dereference()) == 0xdeadbeef):
					value = (next.cast(_uint32_type.pointer()) + 1).cast(_void_type.pointer())
				else:
					value = next

				if (typ != None):
					yield value.cast(typ.pointer())
				else:
					yield value
					
			next = (next.cast(_uintptr_type)
					+ self._alloc["sa_objsize"]
					+ _bufctl_type.sizeof).cast(_void_type.pointer())

class SlabAllocator:

	def __init__(self, val):
		if (val.type.code == gdb.TYPE_CODE_PTR):
			self._value = val.cast(_allocator_type.pointer()).dereference()
		else:
			self._value = val.cast(_allocator_type)

	def name(self):
		return self._value["sa_name"].string()

	def size(self):
		return int(self._value["sa_objsize"])

	def slabs(self):
		next = self._value["sa_slabs"]
		while (next != 0):
			yield Slab(self._value, next.dereference())
			next = next.dereference()["s_next"]

	def objs(self, typ=None):
		for slab in self.slabs():
			for obj in slab.objs(typ):
				yield obj

	def __str__(self):
		res =  "name:      {0}\n".format(self.name())
		res += "slabcount: {0}\n".format(len(list(self.slabs())))
		res += "objsize:   {0}\n".format(self.size())
		res += "objcount:  {0}".format(len(list(self.objs())))
		return res

def allocators():
	next = gdb.parse_and_eval("slab_allocators")
	while (next != 0):
		yield SlabAllocator(next.dereference())
		next = next.dereference()["sa_next"]

def allocator(name):
	for alloc in allocators():
		if name == alloc.name():
			return alloc
	raise KeyError(name)

def pagesize():
	return PAGE_SIZE

def freepages():
	freepages = dict()
	for pagegroup in weenix.list.load("pagegroup_list", "struct pagegroup", "pg_link"):
		freelist = pagegroup.item()["pg_freelist"]
		for order in xrange(freelist.type.sizeof // freelist.type.target().sizeof):
			psize = (1 << order) * PAGE_SIZE
			count = len(weenix.list.load(freelist[order]))
			if (order in freepages):
				freepages[order] += count
			else:
				freepages[order] = count
	return freepages