aboutsummaryrefslogtreecommitdiffstats
path: root/misc/lldb_rb/rb_heap_structs.py
blob: 86b38dbbbd502b0cb4f38b4da9ac5d863c946263 (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
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
import lldb
from lldb_rb.lldb_interface import LLDBInterface
from lldb_rb.constants import *

class HeapPage(LLDBInterface):
    def __init__(self, debugger, val):
        self.build_environment(debugger)
        self.page_type = self.target.FindFirstType("struct heap_page").GetPointerType()
        self.val = val

    def heap_page_body(self, command, ctx, result, internal_dict):
        process = self.target.GetProcess()
        thread = process.GetSelectedThread()
        frame = thread.GetSelectedFrame()

        val = frame.EvaluateExpression(command)
        page = self.get_page_body(val)
        print("Page body address: ", page.GetAddress(), file=result)
        print(page, file=result)

    def get_page_body(self, val):
        tHeapPageBody = self.target.FindFirstType("struct heap_page_body")
        addr = val.GetValueAsUnsigned()
        page_addr = addr & ~(HEAP_PAGE_ALIGN_MASK)
        address = lldb.SBAddress(page_addr, self.target)
        return self.target.CreateValueFromAddress("page", address, tHeapPageBody)

    def get_page_raw(self, val):
        body = self.get_page_body(val)
        return body.GetValueForExpressionPath("->header.page")

    def to_heap_page_struct(self):
        pagePtr = self.get_page_raw(self.val)
        return pagePtr.Cast(self.page_type)


class RbObject(LLDBInterface):
    def __init__(self, ptr, debugger, ruby_globals):
        self.build_environment(debugger)
        self.ruby_globals = ruby_globals

        self.flUser1 = self.ruby_globals["RUBY_FL_USER1"]
        self.flUser2 = self.ruby_globals["RUBY_FL_USER2"]
        self.flUser3 = self.ruby_globals["RUBY_FL_USER3"]
        self.flUser4 = self.ruby_globals["RUBY_FL_USER4"]
        self.flUser5 = self.ruby_globals["RUBY_FL_USER5"]
        self.flUser6 = self.ruby_globals["RUBY_FL_USER6"]
        self.flUser7 = self.ruby_globals["RUBY_FL_USER7"]
        self.flUser8 = self.ruby_globals["RUBY_FL_USER8"]
        self.flUser9 = self.ruby_globals["RUBY_FL_USER9"]
        self.flUshift = self.ruby_globals["RUBY_FL_USHIFT"]

        self.tRBasic = self.target.FindFirstType("struct RBasic").GetPointerType()
        self.tRValue = self.target.FindFirstType("struct RVALUE")

        self.val = ptr.Cast(self.tRBasic)
        self.page = HeapPage(self.debugger, self.val)
        self.flags = self.val.GetValueForExpressionPath("->flags").GetValueAsUnsigned()

        self.type = None
        self.type_name = ""

    def check_bits(self, bitmap_name, bitmap_index, bitmap_bit, v):
        page = self.page.to_heap_page_struct()
        bits = page.GetChildMemberWithName(bitmap_name)
        plane = bits.GetChildAtIndex(bitmap_index).GetValueAsUnsigned()
        if (plane & bitmap_bit) != 0:
            return v
        else:
            return ' '

    def dump_bits(self, result, end = "\n"):
        tRValue = self.target.FindFirstType("struct RVALUE")
        tUintPtr = self.target.FindFirstType("uintptr_t") # bits_t

        num_in_page = (self.val.GetValueAsUnsigned() & HEAP_PAGE_ALIGN_MASK) // tRValue.GetByteSize();
        bits_bitlength = tUintPtr.GetByteSize() * 8
        bitmap_index = num_in_page // bits_bitlength
        bitmap_offset = num_in_page & (bits_bitlength - 1)
        bitmap_bit = 1 << bitmap_offset

        page = self.page.to_heap_page_struct()
        print("bits: [%s%s%s%s%s]" % (
            self.check_bits("uncollectible_bits", bitmap_index, bitmap_bit, "L"),
            self.check_bits("mark_bits", bitmap_index, bitmap_bit, "M"),
            self.check_bits("pinned_bits", bitmap_index, bitmap_bit, "P"),
            self.check_bits("marking_bits", bitmap_index, bitmap_bit, "R"),
            self.check_bits("wb_unprotected_bits", bitmap_index, bitmap_bit, "U"),
            ), end=end, file=result)

    def promoted_p(self):
        rbFlPromoted = self.ruby_globals["RUBY_FL_PROMOTED"]
        return (self.flags & rbFlPromoted) == rbFlPromoted

    def frozen_p(self):
        rbFlFreeze = self.ruby_globals["RUBY_FL_FREEZE"]
        return (self.flags & rbFlFreeze) == rbFlFreeze

    def is_type(self, type_name):
        if self.type is None:
            flTMask = self.ruby_globals["RUBY_T_MASK"]
            flType = self.flags & flTMask
            self.type = flType

        if self.type == self.ruby_globals[type_name]:
            self.type_name = type_name
            return True
        else:
            return False

    def as_type(self, type_name):
        return self.val.Cast(self.tRValue.GetPointerType()).GetValueForExpressionPath("->as."+type_name)

    def ary_ptr(self):
        rval = self.as_type("array")
        if self.flags & self.ruby_globals["RUBY_FL_USER1"]:
            ptr = rval.GetValueForExpressionPath("->as.ary")
        else:
            ptr = rval.GetValueForExpressionPath("->as.heap.ptr")
        return ptr

    def ary_len(self):
        if self.flags & self.flUser1:
            len = ((self.flags &
              (self.flUser3 | self.flUser4 | self.flUser5 | self.flUser6 |
               self.flUser7 | self.flUser8 | self.flUser9)
              ) >> (self.flUshift + 3))
        else:
            rval = self.as_type("array")
            len = rval.GetValueForExpressionPath("->as.heap.len").GetValueAsSigned()

        return len

    def bignum_len(self):
        if self.flags & self.flUser2:
            len = ((self.flags &
              (self.flUser3 | self.flUser4 | self.flUser5)
              ) >> (self.flUshift + 3))
        else:
            len = (self.as_type("bignum").GetValueForExpressionPath("->as.heap.len").
                   GetValueAsUnsigned())

        return len