LLDB: add synthetic provider for WTF::HashTable
[WebKit-https.git] / Tools / lldb / lldb_webkit.py
1 # Copyright (C) 2012 Apple. All rights reserved.
2 #
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions
5 # are met:
6 # 1.  Redistributions of source code must retain the above copyright
7 #     notice, this list of conditions and the following disclaimer.
8 # 2.  Redistributions in binary form must reproduce the above copyright
9 #     notice, this list of conditions and the following disclaimer in the
10 #     documentation and/or other materials provided with the distribution.
11 #
12 # THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND ANY
13 # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
14 # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
15 # DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY
16 # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
17 # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
18 # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
19 # ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
21 # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
22
23 """
24     LLDB Support for WebKit Types
25
26     Add the following to your .lldbinit file to add WebKit Type summaries in LLDB and Xcode:
27
28     command script import {Path to WebKit Root}/Tools/lldb/lldb_webkit.py
29
30 """
31
32 import lldb
33
34
35 def __lldb_init_module(debugger, dict):
36     debugger.HandleCommand('type summary add --expand -F lldb_webkit.WTFString_SummaryProvider WTF::String')
37     debugger.HandleCommand('type summary add --expand -F lldb_webkit.WTFStringImpl_SummaryProvider WTF::StringImpl')
38     debugger.HandleCommand('type summary add --expand -F lldb_webkit.WTFAtomicString_SummaryProvider WTF::AtomicString')
39     debugger.HandleCommand('type summary add --expand -F lldb_webkit.WTFVector_SummaryProvider -x "WTF::Vector<.+>$"')
40     debugger.HandleCommand('type summary add --expand -F lldb_webkit.WTFHashTable_SummaryProvider -x "WTF::HashTable<.+>$"')
41     debugger.HandleCommand('type synthetic add -x "WTF::Vector<.+>$" --python-class lldb_webkit.WTFVectorProvider')
42     debugger.HandleCommand('type synthetic add -x "WTF::HashTable<.+>$" --python-class lldb_webkit.WTFHashTableProvider')
43
44
45 def WTFString_SummaryProvider(valobj, dict):
46     provider = WTFStringProvider(valobj, dict)
47     return "{ length = %d, contents = '%s' }" % (provider.get_length(), provider.to_string())
48
49
50 def WTFStringImpl_SummaryProvider(valobj, dict):
51     provider = WTFStringImplProvider(valobj, dict)
52     return "{ length = %d, is8bit = %d, contents = '%s' }" % (provider.get_length(), provider.is_8bit(), provider.to_string())
53
54
55 def WTFAtomicString_SummaryProvider(valobj, dict):
56     return WTFString_SummaryProvider(valobj.GetChildMemberWithName('m_string'), dict)
57
58
59 def WTFVector_SummaryProvider(valobj, dict):
60     provider = WTFVectorProvider(valobj, dict)
61     return "{ size = %d, capacity = %d }" % (provider.size, provider.capacity)
62
63
64 def WTFHashTable_SummaryProvider(valobj, dict):
65     provider = WTFHashTableProvider(valobj, dict)
66     return "{ tableSize = %d, keyCount = %d }" % (provider.tableSize(), provider.keyCount())
67
68 # FIXME: Provide support for the following types:
69 # def WTFVector_SummaryProvider(valobj, dict):
70 # def WTFCString_SummaryProvider(valobj, dict):
71 # def WebCoreKURLGooglePrivate_SummaryProvider(valobj, dict):
72 # def WebCoreQualifiedName_SummaryProvider(valobj, dict):
73 # def JSCIdentifier_SummaryProvider(valobj, dict):
74 # def JSCJSString_SummaryProvider(valobj, dict):
75
76
77 def guess_string_length(valobj, error):
78     if not valobj.GetValue():
79         return 0
80
81     for i in xrange(0, 2048):
82         if valobj.GetPointeeData(i, 1).GetUnsignedInt16(error, 0) == 0:
83             return i
84
85     return 256
86
87
88 def ustring_to_string(valobj, error, length=None):
89     if length is None:
90         length = guess_string_length(valobj, error)
91     else:
92         length = int(length)
93
94     out_string = u""
95     for i in xrange(0, length):
96         char_value = valobj.GetPointeeData(i, 1).GetUnsignedInt16(error, 0)
97         out_string = out_string + unichr(char_value)
98
99     return out_string.encode('utf-8')
100
101
102 def lstring_to_string(valobj, error, length=None):
103     if length is None:
104         length = guess_string_length(valobj, error)
105     else:
106         length = int(length)
107
108     out_string = u""
109     for i in xrange(0, length):
110         char_value = valobj.GetPointeeData(i, 1).GetUnsignedInt8(error, 0)
111         out_string = out_string + unichr(char_value)
112
113     return out_string.encode('utf-8')
114
115
116 class WTFStringImplProvider:
117     def __init__(self, valobj, dict):
118         self.valobj = valobj
119
120     def get_length(self):
121         return self.valobj.GetChildMemberWithName('m_length').GetValueAsUnsigned(0)
122
123     def get_data8(self):
124         return self.valobj.GetChildAtIndex(2).GetChildMemberWithName('m_data8')
125
126     def get_data16(self):
127         return self.valobj.GetChildAtIndex(2).GetChildMemberWithName('m_data16')
128
129     def to_string(self):
130         error = lldb.SBError()
131         if self.is_8bit():
132             return lstring_to_string(self.get_data8(), error, self.get_length())
133         return ustring_to_string(self.get_data16(), error, self.get_length())
134
135     def is_8bit(self):
136         # FIXME: find a way to access WTF::StringImpl::s_hashFlag8BitBuffer
137         return bool(self.valobj.GetChildMemberWithName('m_hashAndFlags').GetValueAsUnsigned(0) \
138             & 1 << 6)
139
140
141 class WTFStringProvider:
142     def __init__(self, valobj, dict):
143         self.valobj = valobj
144
145     def stringimpl(self):
146         impl_ptr = self.valobj.GetChildMemberWithName('m_impl').GetChildMemberWithName('m_ptr')
147         return WTFStringImplProvider(impl_ptr, dict)
148
149     def get_length(self):
150         impl = self.stringimpl()
151         if not impl:
152             return 0
153         return impl.get_length()
154
155     def to_string(self):
156         impl = self.stringimpl()
157         if not impl:
158             return u""
159         return impl.to_string()
160
161
162 class WTFVectorProvider:
163     def __init__(self, valobj, internal_dict):
164         self.valobj = valobj
165         self.update()
166
167     def num_children(self):
168         return self.size + 2
169
170     def get_child_index(self, name):
171         if name == "m_size":
172             return self.size
173         elif name == "m_buffer":
174             return self.size + 1
175         else:
176             return int(name.lstrip('[').rstrip(']'))
177
178     def get_child_at_index(self, index):
179         if index == self.size:
180             return self.valobj.GetChildMemberWithName("m_size")
181         elif index == self.size + 1:
182             return self.vector_buffer
183         elif index < self.size:
184             offset = index * self.data_size
185             child = self.buffer.CreateChildAtOffset('[' + str(index) + ']', offset, self.data_type)
186             return child
187         else:
188             return None
189
190     def update(self):
191         self.vector_buffer = self.valobj.GetChildMemberWithName('m_buffer')
192         self.buffer = self.vector_buffer.GetChildMemberWithName('m_buffer')
193         self.size = self.valobj.GetChildMemberWithName('m_size').GetValueAsUnsigned(0)
194         self.capacity = self.vector_buffer.GetChildMemberWithName('m_capacity').GetValueAsUnsigned(0)
195         self.data_type = self.buffer.GetType().GetPointeeType()
196         self.data_size = self.data_type.GetByteSize()
197
198     def has_children(self):
199         return True
200
201
202 class WTFHashTableProvider:
203     def __init__(self, valobj, internal_dict):
204         self.valobj = valobj
205         self.update()
206
207     def num_children(self):
208         return self.tableSize() + 5
209
210     def get_child_index(self, name):
211         if name == "m_table":
212             return self.tableSize()
213         elif name == "m_tableSize":
214             return self.tableSize() + 1
215         elif name == "m_tableSizeMask":
216             return self.tableSize() + 2
217         elif name == "m_keyCount":
218             return self.tableSize() + 3
219         elif name == "m_deletedCount":
220             return self.tableSize() + 4
221         else:
222             return int(name.lstrip('[').rstrip(']'))
223
224     def get_child_at_index(self, index):
225         if index == self.tableSize():
226             return self.valobj.GetChildMemberWithName('m_table')
227         elif index == self.tableSize() + 1:
228             return self.valobj.GetChildMemberWithName('m_tableSize')
229         elif index == self.tableSize() + 2:
230             return self.valobj.GetChildMemberWithName('m_tableSizeMask')
231         elif index == self.tableSize() + 3:
232             return self.valobj.GetChildMemberWithName('m_keyCount')
233         elif index == self.tableSize() + 4:
234             return self.valobj.GetChildMemberWithName('m_deletedCount')
235         elif index < self.tableSize():
236             table = self.valobj.GetChildMemberWithName('m_table')
237             return table.CreateChildAtOffset('[' + str(index) + ']', index * self.data_size, self.data_type)
238         else:
239             return None
240
241     def tableSize(self):
242         return self.valobj.GetChildMemberWithName('m_tableSize').GetValueAsUnsigned(0)
243
244     def keyCount(self):
245         return self.valobj.GetChildMemberWithName('m_keyCount').GetValueAsUnsigned(0)
246
247     def update(self):
248         self.data_type = self.valobj.GetType().GetTemplateArgumentType(0)
249         self.data_size = self.data_type.GetByteSize()
250
251     def has_children(self):
252         return True