-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathrb_heap_structs.py
143 lines (117 loc) · 5.49 KB
/
rb_heap_structs.py
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