summaryrefslogtreecommitdiff
path: root/data/eo/eo_gdb.py
blob: 2f86fdc0f944527aa54076273f48aecb1ac4d150 (plain) (blame)
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
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
import gdb

"""
All of this script relies heavily on Eo internals and will break if they
change. Need to make sure this is always in sync.
"""

ptr_size = int(gdb.parse_and_eval('sizeof(void *)'))

if ptr_size == 4:
    # 32 bits
    BITS_MID_TABLE_ID = 5
    BITS_TABLE_ID = 5
    BITS_ENTRY_ID = 11
    BITS_GENERATION_COUNTER = 6
    BITS_DOMAIN = 2
    BITS_CLASS = 1
    REF_TAG_SHIFT = 30
    SUPER_TAG_SHIFT = 31
    DROPPED_TABLES = 0
    DROPPED_ENTRIES = 4
else:
    # 64 bits
    BITS_MID_TABLE_ID = 11
    BITS_TABLE_ID = 11
    BITS_ENTRY_ID = 11
    BITS_GENERATION_COUNTER = 26
    BITS_DOMAIN = 2
    BITS_CLASS = 1
    REF_TAG_SHIFT = 62
    SUPER_TAG_SHIFT = 63
    DROPPED_TABLES = 2
    DROPPED_ENTRIES = 3

# /* Shifts macros to manipulate the Eo id */
SHIFT_DOMAIN = (BITS_MID_TABLE_ID + BITS_TABLE_ID +
                BITS_ENTRY_ID + BITS_GENERATION_COUNTER)
SHIFT_MID_TABLE_ID = (BITS_TABLE_ID +
                      BITS_ENTRY_ID + BITS_GENERATION_COUNTER)
SHIFT_TABLE_ID = (BITS_ENTRY_ID + BITS_GENERATION_COUNTER)
SHIFT_ENTRY_ID = (BITS_GENERATION_COUNTER)

# /* Maximum ranges */
MAX_DOMAIN = (1 << BITS_DOMAIN)
MAX_MID_TABLE_ID = (1 << BITS_MID_TABLE_ID)
MAX_TABLE_ID = ((1 << BITS_TABLE_ID) - DROPPED_TABLES)
MAX_ENTRY_ID = ((1 << BITS_ENTRY_ID) - DROPPED_ENTRIES)
MAX_GENERATIONS = (1 << BITS_GENERATION_COUNTER)

# /* Masks */
MASK_DOMAIN = (MAX_DOMAIN - 1)
MASK_MID_TABLE_ID = (MAX_MID_TABLE_ID - 1)
MASK_TABLE_ID = ((1 << BITS_TABLE_ID) - 1)
MASK_ENTRY_ID = ((1 << BITS_ENTRY_ID) - 1)
MASK_GENERATIONS = (MAX_GENERATIONS - 1)
MASK_OBJ_TAG = (1 << (REF_TAG_SHIFT))


null_void_ptr = gdb.parse_and_eval('(_Eo_Object *) 0')
null_eo_object_ptr = gdb.parse_and_eval('(_Eo_Object *) 0')
zero_uintptr_t = gdb.parse_and_eval('(uintptr_t) 0')


class Eo_resolve(gdb.Function):
    def __init__(self):
        gdb.Function.__init__(self, 'eo_resolve')

    def invoke(self, arg):
        obj_id = int(str(arg.cast(zero_uintptr_t.type)), 0)

        mid_table_id = (obj_id >> SHIFT_MID_TABLE_ID) & MASK_MID_TABLE_ID
        table_id = (obj_id >> SHIFT_TABLE_ID) & MASK_TABLE_ID
        entry_id = (obj_id >> SHIFT_ENTRY_ID) & MASK_ENTRY_ID
        tag_bit = (obj_id) & MASK_OBJ_TAG
        generation = obj_id & MASK_GENERATIONS

        if (obj_id == 0) or (tag_bit == 0):
            gdb.write('Pointer is NULL or not a valid object.\n')
            return null_eo_object_ptr

        entries = gdb.parse_and_eval('_eo_gdb_main_domain->tables[0]->' +
                                     'eo_ids_tables[{0}]'.format(mid_table_id))

        if int(entries) == 0:
            gdb.write('Pointer is not a valid object.\n')
            return null_eo_object_ptr

        entry = entries[table_id]['entries'][entry_id]

        if (not entry['active']) or (int(entry['generation']) != generation):
            gdb.write('Pointer is no longer active.\n')
            return null_eo_object_ptr

        return entry['ptr']


Eo_resolve()


class Eo_data_get(gdb.Function):
    def __init__(self):
        gdb.Function.__init__(self, 'eo_data_get')

    def invoke(self, ptr, kls_name):
        ptr = ptr.cast(null_eo_object_ptr.type)  # Cast to correct type

        if int(ptr) == 0:
            gdb.write('Object is not a valid pointer (NULL).\n')
            return null_void_ptr

        kls_name = kls_name.string()
        extns = ptr['klass']['mro']
        kls = None

        i = 0
        while int(extns[i]) != 0:
            if extns[i]['desc']['name'].string() == kls_name:
                kls = extns[i]
            i += 1

        if kls is None:
            gdb.write('Class "{}" not found in the object mro.\n'
                      .format(kls_name))
            return null_void_ptr

        # Check if not mixin
        if int(kls['desc']['type'].cast(zero_uintptr_t.type)) != 3:
            return gdb.parse_and_eval('(void *) (((char *) {}) + {})'
                                      .format(ptr, kls['data_offset']))
        else:
            extn_off = ptr['klass']['extn_data_off']
            if int(extn_off) == 0:
                return null_void_ptr

            i = 0
            while int(extn_off[i]['klass']) != 0:
                kls = extn_off[i]['klass']
                if kls['desc']['name'].string() == kls_name:
                    return gdb.parse_and_eval('(void *) (((char *) {}) + {})'
                                              .format(ptr, kls['data_offset']))
                i += 1

        return null_void_ptr


Eo_data_get()