Home | History | Annotate | Download | only in lldb
      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