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 253