summaryrefslogtreecommitdiff
path: root/gdb_plugins/mmio.py
blob: 5f2a2491535b311ceae8764ca426f4945ad123b8 (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
import gdb
import gdb.xmethod

class RefWorker(gdb.xmethod.XMethodWorker):
    def __init__(self, result_type):
        self.result_type = result_type

    def get_arg_types(self):
        return None

    def get_result_type(self, obj):
        return self.result_type.reference()
 
    def __call__(self, obj):
        return obj['p'].cast(self.result_type.pointer()).dereference()

class PtrWorker(gdb.xmethod.XMethodWorker):
    def __init__(self, result_type):
        self.result_type = result_type

    def get_arg_types(self):
        return None

    def get_result_type(self, obj):
        return self.result_type.pointer()
 
    def __call__(self, obj):
        return obj['p'].cast(self.result_type.pointer())

class SubscriptWorker(gdb.xmethod.XMethodWorker):
    def __init__(self, result_type):
        self.result_type = result_type

    def get_arg_types(self):
        return [gdb.lookup_type('std::size_t')]

    def get_result_type(self, obj, idx):
        return self.result_type.reference()
 
    def __call__(self, obj, idx):
        return obj['p'].cast(self.result_type.pointer())[idx]

class Method(gdb.xmethod.XMethod):
    def __init__(self, name, worker):
        gdb.xmethod.XMethod.__init__(self, name)
        self.worker = worker
 
class Matcher(gdb.xmethod.XMethodMatcher):
    def __init__(self):
        gdb.xmethod.XMethodMatcher.__init__(self, 'mmio_ptr matcher')

        self.methods = [
            Method('operator*', RefWorker),
            Method('operator->', PtrWorker),
            Method('operator[]', SubscriptWorker),
        ]
 
    def match(self, class_type, method_name):
        if not class_type.name.startswith('mmio_ptr<'):
            return
            
        ptr_type = class_type.template_argument(0)

        for method in self.methods:
            if method.enabled and method.name == method_name:
                return method.worker(ptr_type)

gdb.xmethod.register_xmethod_matcher(None, Matcher(), replace = True)

def get_mmio_ptr_type(pt):
    if pt.name.startswith('mmio_ptr<'):
        return pt.template_argument(0)

    for field in pt.fields():
        if not field.is_base_class:
            continue

        t = get_mmio_ptr_type(field.type)

        if t is not None:
            return t

    return None

class MMIOPtr(gdb.Function):
  """
  Usage is, for instance, p /x *$mmio_ptr(RCC)
  """
  def __init__(self):
    gdb.Function.__init__(self, 'mmio_ptr')

  def invoke(self, obj):
    t = get_mmio_ptr_type(obj.type)
    return obj['p'].cast(t.pointer())

MMIOPtr()