Unreviewed, rolling out r242825.
[WebKit-https.git] / Tools / lldb / lldb_webkit.py
1 # Copyright (C) 2012-2018 Apple Inc. 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 import string
34 import struct
35
36
37 def addSummaryAndSyntheticFormattersForRawBitmaskType(debugger, type_name, enumerator_value_to_name_map):
38     class GeneratedRawBitmaskProvider(RawBitmaskProviderBase):
39         ENUMERATOR_VALUE_TO_NAME_MAP = enumerator_value_to_name_map.copy()
40
41     def raw_bitmask_summary_provider(valobj, dict):
42         provider = GeneratedRawBitmaskProvider(valobj, dict)
43         return "{ size = %d }" % provider.size
44
45     # Add the provider class and summary function to the global scope so that LLDB
46     # can find them.
47     synthetic_provider_class_name = type_name + 'Provider'
48     summary_provider_function_name = type_name + '_SummaryProvider'
49     globals()[synthetic_provider_class_name] = GeneratedRawBitmaskProvider
50     globals()[summary_provider_function_name] = raw_bitmask_summary_provider
51
52     debugger.HandleCommand('type summary add --expand -F lldb_webkit.%s "%s"' % (summary_provider_function_name, type_name))
53     debugger.HandleCommand('type synthetic add %s --python-class lldb_webkit.%s' % (type_name, synthetic_provider_class_name))
54
55
56 def __lldb_init_module(debugger, dict):
57     debugger.HandleCommand('command script add -f lldb_webkit.btjs btjs')
58     debugger.HandleCommand('type summary add --expand -F lldb_webkit.WTFString_SummaryProvider WTF::String')
59     debugger.HandleCommand('type summary add --expand -F lldb_webkit.WTFStringImpl_SummaryProvider WTF::StringImpl')
60     debugger.HandleCommand('type summary add --expand -F lldb_webkit.WTFStringView_SummaryProvider WTF::StringView')
61     debugger.HandleCommand('type summary add --expand -F lldb_webkit.WTFAtomicString_SummaryProvider WTF::AtomicString')
62     debugger.HandleCommand('type summary add --expand -F lldb_webkit.WTFVector_SummaryProvider -x "^WTF::Vector<.+>$"')
63     debugger.HandleCommand('type summary add --expand -F lldb_webkit.WTFHashTable_SummaryProvider -x "^WTF::HashTable<.+>$"')
64     debugger.HandleCommand('type summary add --expand -F lldb_webkit.WTFHashMap_SummaryProvider -x "^WTF::HashMap<.+>$"')
65     debugger.HandleCommand('type summary add --expand -F lldb_webkit.WTFHashSet_SummaryProvider -x "^WTF::HashSet<.+>$"')
66     debugger.HandleCommand('type summary add --expand -F lldb_webkit.WTFMediaTime_SummaryProvider WTF::MediaTime')
67     debugger.HandleCommand('type summary add --expand -F lldb_webkit.WTFOptionSet_SummaryProvider -x "^WTF::OptionSet<.+>$"')
68
69     debugger.HandleCommand('type summary add -F lldb_webkit.WTFURL_SummaryProvider WTF::URL')
70     debugger.HandleCommand('type summary add -F lldb_webkit.WebCoreColor_SummaryProvider WebCore::Color')
71
72     debugger.HandleCommand('type summary add -F lldb_webkit.WebCoreLayoutUnit_SummaryProvider WebCore::LayoutUnit')
73     debugger.HandleCommand('type summary add -F lldb_webkit.WebCoreLayoutSize_SummaryProvider WebCore::LayoutSize')
74     debugger.HandleCommand('type summary add -F lldb_webkit.WebCoreLayoutPoint_SummaryProvider WebCore::LayoutPoint')
75     debugger.HandleCommand('type summary add -F lldb_webkit.WebCoreLayoutRect_SummaryProvider WebCore::LayoutRect')
76
77     debugger.HandleCommand('type summary add -F lldb_webkit.WebCoreIntSize_SummaryProvider WebCore::IntSize')
78     debugger.HandleCommand('type summary add -F lldb_webkit.WebCoreIntPoint_SummaryProvider WebCore::IntPoint')
79     debugger.HandleCommand('type summary add -F lldb_webkit.WebCoreIntRect_SummaryProvider WebCore::IntRect')
80
81     debugger.HandleCommand('type summary add -F lldb_webkit.WebCoreFloatSize_SummaryProvider WebCore::FloatSize')
82     debugger.HandleCommand('type summary add -F lldb_webkit.WebCoreFloatPoint_SummaryProvider WebCore::FloatPoint')
83     debugger.HandleCommand('type summary add -F lldb_webkit.WebCoreFloatRect_SummaryProvider WebCore::FloatRect')
84
85     debugger.HandleCommand('type summary add -F lldb_webkit.WebCoreSecurityOrigin_SummaryProvider WebCore::SecurityOrigin')
86     debugger.HandleCommand('type summary add -F lldb_webkit.WebCoreFrame_SummaryProvider WebCore::Frame')
87     debugger.HandleCommand('type summary add -F lldb_webkit.WebCoreDocument_SummaryProvider WebCore::Document')
88
89     # synthetic types (see <https://lldb.llvm.org/varformats.html>)
90     debugger.HandleCommand('type synthetic add -x "^WTF::Vector<.+>$" --python-class lldb_webkit.WTFVectorProvider')
91     debugger.HandleCommand('type synthetic add -x "^WTF::HashTable<.+>$" --python-class lldb_webkit.WTFHashTableProvider')
92     debugger.HandleCommand('type synthetic add -x "^WTF::OptionSet<.+>$" --python-class lldb_webkit.WTFOptionSetProvider')
93
94     addSummaryAndSyntheticFormattersForRawBitmaskType(debugger, "WebEventFlags", {
95         0x00010000: "WebEventFlagMaskLeftCommandKey",
96         0x00020000: "WebEventFlagMaskLeftShiftKey",
97         0x00040000: "WebEventFlagMaskLeftCapsLockKey",
98         0x00080000: "WebEventFlagMaskLeftOptionKey",
99         0x00100000: "WebEventFlagMaskLeftControlKey",
100         0x00800000: "WebEventFlagMaskRightControlKey",
101         0x00200000: "WebEventFlagMaskRightShiftKey",
102         0x00400000: "WebEventFlagMaskRightOptionKey",
103         0x01000000: "WebEventFlagMaskRightCommandKey",
104     })
105
106
107 def WTFString_SummaryProvider(valobj, dict):
108     provider = WTFStringProvider(valobj, dict)
109     return "{ length = %d, contents = '%s' }" % (provider.get_length(), provider.to_string())
110
111
112 def WTFStringImpl_SummaryProvider(valobj, dict):
113     provider = WTFStringImplProvider(valobj, dict)
114     if not provider.is_initialized():
115         return ""
116     return "{ length = %d, is8bit = %d, contents = '%s' }" % (provider.get_length(), provider.is_8bit(), provider.to_string())
117
118
119 def WTFStringView_SummaryProvider(valobj, dict):
120     provider = WTFStringViewProvider(valobj, dict)
121     return "{ length = %d, contents = '%s' }" % (provider.get_length(), provider.to_string())
122
123
124 def WTFAtomicString_SummaryProvider(valobj, dict):
125     return WTFString_SummaryProvider(valobj.GetChildMemberWithName('m_string'), dict)
126
127
128 def WTFVector_SummaryProvider(valobj, dict):
129     provider = WTFVectorProvider(valobj, dict)
130     return "{ size = %d, capacity = %d }" % (provider.size, provider.capacity)
131
132
133 def WTFHashTable_SummaryProvider(valobj, dict):
134     provider = WTFHashTableProvider(valobj, dict)
135     return "{ tableSize = %d, keyCount = %d }" % (provider.tableSize(), provider.keyCount())
136
137
138 def WTFHashMap_SummaryProvider(valobj, dict):
139     provider = WTFHashMapProvider(valobj, dict)
140     return "{ tableSize = %d, keyCount = %d }" % (provider.tableSize(), provider.keyCount())
141
142
143 def WTFHashSet_SummaryProvider(valobj, dict):
144     provider = WTFHashSetProvider(valobj, dict)
145     return "{ tableSize = %d, keyCount = %d }" % (provider.tableSize(), provider.keyCount())
146
147
148 def WTFOptionSet_SummaryProvider(valobj, dict):
149     provider = WTFOptionSetProvider(valobj, dict)
150     return "{ size = %d }" % provider.size
151
152
153 def WTFMediaTime_SummaryProvider(valobj, dict):
154     provider = WTFMediaTimeProvider(valobj, dict)
155     if provider.isInvalid():
156         return "{ Invalid }"
157     if provider.isPositiveInfinity():
158         return "{ +Infinity }"
159     if provider.isNegativeInfinity():
160         return "{ -Infinity }"
161     if provider.isIndefinite():
162         return "{ Indefinite }"
163     if provider.hasDoubleValue():
164         return "{ %f }" % (provider.timeValueAsDouble())
165     return "{ %d/%d, %f }" % (provider.timeValue(), provider.timeScale(), float(provider.timeValue()) / provider.timeScale())
166
167
168 def WebCoreColor_SummaryProvider(valobj, dict):
169     provider = WebCoreColorProvider(valobj, dict)
170     return "{ %s }" % provider.to_string()
171
172
173 def WTFURL_SummaryProvider(valobj, dict):
174     provider = WTFURLProvider(valobj, dict)
175     return "{ %s }" % provider.to_string()
176
177
178 def WebCoreLayoutUnit_SummaryProvider(valobj, dict):
179     provider = WebCoreLayoutUnitProvider(valobj, dict)
180     return "{ %s }" % provider.to_string()
181
182
183 def WebCoreLayoutSize_SummaryProvider(valobj, dict):
184     provider = WebCoreLayoutSizeProvider(valobj, dict)
185     return "{ width = %s, height = %s }" % (provider.get_width(), provider.get_height())
186
187
188 def WebCoreLayoutPoint_SummaryProvider(valobj, dict):
189     provider = WebCoreLayoutPointProvider(valobj, dict)
190     return "{ x = %s, y = %s }" % (provider.get_x(), provider.get_y())
191
192
193 def WebCoreLayoutRect_SummaryProvider(valobj, dict):
194     provider = WebCoreLayoutRectProvider(valobj, dict)
195     return "{ x = %s, y = %s, width = %s, height = %s }" % (provider.get_x(), provider.get_y(), provider.get_width(), provider.get_height())
196
197
198 def WebCoreIntSize_SummaryProvider(valobj, dict):
199     provider = WebCoreIntSizeProvider(valobj, dict)
200     return "{ width = %s, height = %s }" % (provider.get_width(), provider.get_height())
201
202
203 def WebCoreIntPoint_SummaryProvider(valobj, dict):
204     provider = WebCoreIntPointProvider(valobj, dict)
205     return "{ x = %s, y = %s }" % (provider.get_x(), provider.get_y())
206
207
208 def WebCoreFloatSize_SummaryProvider(valobj, dict):
209     provider = WebCoreFloatSizeProvider(valobj, dict)
210     return "{ width = %s, height = %s }" % (provider.get_width(), provider.get_height())
211
212
213 def WebCoreFloatPoint_SummaryProvider(valobj, dict):
214     provider = WebCoreFloatPointProvider(valobj, dict)
215     return "{ x = %s, y = %s }" % (provider.get_x(), provider.get_y())
216
217
218 def WebCoreIntRect_SummaryProvider(valobj, dict):
219     provider = WebCoreIntRectProvider(valobj, dict)
220     return "{ x = %s, y = %s, width = %s, height = %s }" % (provider.get_x(), provider.get_y(), provider.get_width(), provider.get_height())
221
222
223 def WebCoreFloatRect_SummaryProvider(valobj, dict):
224     provider = WebCoreFloatRectProvider(valobj, dict)
225     return "{ x = %s, y = %s, width = %s, height = %s }" % (provider.get_x(), provider.get_y(), provider.get_width(), provider.get_height())
226
227
228 def WebCoreSecurityOrigin_SummaryProvider(valobj, dict):
229     provider = WebCoreSecurityOriginProvider(valobj, dict)
230     return '{ %s, domain = %s, hasUniversalAccess = %d }' % (provider.to_string(), provider.domain(), provider.has_universal_access())
231
232
233 def WebCoreFrame_SummaryProvider(valobj, dict):
234     provider = WebCoreFrameProvider(valobj, dict)
235     document = provider.document()
236     if document:
237         origin = document.origin()
238         url = document.url()
239         pageCacheState = document.page_cache_state()
240     else:
241         origin = ''
242         url = ''
243         pageCacheState = ''
244     return '{ origin = %s, url = %s, isMainFrame = %d, pageCacheState = %s }' % (origin, url, provider.is_main_frame(), pageCacheState)
245
246
247 def WebCoreDocument_SummaryProvider(valobj, dict):
248     provider = WebCoreDocumentProvider(valobj, dict)
249     frame = provider.frame()
250     in_main_frame = '%d' % frame.is_main_frame() if frame else 'Detached'
251     return '{ origin = %s, url = %s, inMainFrame = %s, pageCacheState = %s }' % (provider.origin(), provider.url(), in_main_frame, provider.page_cache_state())
252
253
254 def btjs(debugger, command, result, internal_dict):
255     '''Prints a stack trace of current thread with JavaScript frames decoded.  Takes optional frame count argument'''
256
257     target = debugger.GetSelectedTarget()
258     addressFormat = '#0{width}x'.format(width=target.GetAddressByteSize() * 2 + 2)
259     process = target.GetProcess()
260     thread = process.GetSelectedThread()
261
262     if target.FindFunctions("JSC::ExecState::describeFrame").GetSize() or target.FindFunctions("_ZN3JSC9ExecState13describeFrameEv").GetSize():
263         annotateJSFrames = True
264     else:
265         annotateJSFrames = False
266
267     if not annotateJSFrames:
268         print("Warning: Can't find JSC::ExecState::describeFrame() in executable to annotate JavaScript frames")
269
270     backtraceDepth = thread.GetNumFrames()
271
272     if len(command) > 0:
273         try:
274             backtraceDepth = int(command)
275         except ValueError:
276             return
277
278     threadFormat = '* thread #{num}: tid = {tid:#x}, {pcAddr:' + addressFormat + '}, queue = \'{queueName}, stop reason = {stopReason}'
279     print(threadFormat.format(num=thread.GetIndexID(), tid=thread.GetThreadID(), pcAddr=thread.GetFrameAtIndex(0).GetPC(), queueName=thread.GetQueueName(), stopReason=thread.GetStopDescription(30)))
280
281     for frame in thread:
282         if backtraceDepth < 1:
283             break
284
285         backtraceDepth = backtraceDepth - 1
286
287         function = frame.GetFunction()
288
289         if annotateJSFrames and not frame or not frame.GetSymbol() or frame.GetSymbol().GetName() == "llint_entry":
290             callFrame = frame.GetSP()
291             JSFrameDescription = frame.EvaluateExpression("((JSC::ExecState*)0x%x)->describeFrame()" % frame.GetFP()).GetSummary()
292             if not JSFrameDescription:
293                 JSFrameDescription = frame.EvaluateExpression("((JSC::CallFrame*)0x%x)->describeFrame()" % frame.GetFP()).GetSummary()
294             if not JSFrameDescription:
295                 JSFrameDescription = frame.EvaluateExpression("(char*)_ZN3JSC9ExecState13describeFrameEv(0x%x)" % frame.GetFP()).GetSummary()
296             if JSFrameDescription:
297                 JSFrameDescription = string.strip(JSFrameDescription, '"')
298                 frameFormat = '    frame #{num}: {addr:' + addressFormat + '} {desc}'
299                 print(frameFormat.format(num=frame.GetFrameID(), addr=frame.GetPC(), desc=JSFrameDescription))
300                 continue
301         print('    %s' % frame)
302
303 # FIXME: Provide support for the following types:
304 # def WTFVector_SummaryProvider(valobj, dict):
305 # def WTFCString_SummaryProvider(valobj, dict):
306 # def WebCoreQualifiedName_SummaryProvider(valobj, dict):
307 # def JSCIdentifier_SummaryProvider(valobj, dict):
308 # def JSCJSString_SummaryProvider(valobj, dict):
309
310
311 def guess_string_length(valobj, charSize, error):
312     if not valobj.GetValue():
313         return 0
314
315     maxLength = 256
316
317     pointer = valobj.GetValueAsUnsigned()
318     contents = valobj.GetProcess().ReadMemory(pointer, maxLength * charSize, lldb.SBError())
319     format = 'B' if charSize == 1 else 'H'
320
321     for i in xrange(0, maxLength):
322         if not struct.unpack_from(format, contents, i * charSize)[0]:
323             return i
324
325     return maxLength
326
327 def ustring_to_string(valobj, error, length=None):
328     if length is None:
329         length = guess_string_length(valobj, 2, error)
330     else:
331         length = int(length)
332
333     if length == 0:
334         return ""
335
336     pointer = valobj.GetValueAsUnsigned()
337     contents = valobj.GetProcess().ReadMemory(pointer, length * 2, lldb.SBError())
338
339     # lldb does not (currently) support returning unicode from python summary providers,
340     # so potentially convert this to ascii by escaping
341     string = contents.decode('utf16')
342     try:
343         return str(string)
344     except:
345         return string.encode('unicode_escape')
346
347 def lstring_to_string(valobj, error, length=None):
348     if length is None:
349         length = guess_string_length(valobj, 1, error)
350     else:
351         length = int(length)
352
353     if length == 0:
354         return ""
355
356     pointer = valobj.GetValueAsUnsigned()
357     contents = valobj.GetProcess().ReadMemory(pointer, length, lldb.SBError())
358
359     # lldb does not (currently) support returning unicode from python summary providers,
360     # so potentially convert this to ascii by escaping
361     string = contents.decode('utf8')
362     try:
363         return str(string)
364     except:
365         return string.encode('unicode_escape')
366
367 class WTFStringImplProvider:
368     def __init__(self, valobj, dict):
369         # FIXME: For some reason lldb(1) sometimes has an issue accessing members of WTF::StringImplShape
370         # via a WTF::StringImpl pointer (why?). As a workaround we explicitly cast to WTF::StringImplShape*.
371         string_impl_shape_ptr_type = valobj.GetTarget().FindFirstType('WTF::StringImplShape').GetPointerType()
372         self.valobj = valobj.Cast(string_impl_shape_ptr_type)
373
374     def get_length(self):
375         return self.valobj.GetChildMemberWithName('m_length').GetValueAsUnsigned(0)
376
377     def get_data8(self):
378         return self.valobj.GetChildAtIndex(2).GetChildMemberWithName('m_data8')
379
380     def get_data16(self):
381         return self.valobj.GetChildAtIndex(2).GetChildMemberWithName('m_data16')
382
383     def to_string(self):
384         error = lldb.SBError()
385
386         if not self.is_initialized():
387             return u""
388
389         if self.is_8bit():
390             return lstring_to_string(self.get_data8(), error, self.get_length())
391         return ustring_to_string(self.get_data16(), error, self.get_length())
392
393     def is_8bit(self):
394         # FIXME: find a way to access WTF::StringImpl::s_hashFlag8BitBuffer
395         return bool(self.valobj.GetChildMemberWithName('m_hashAndFlags').GetValueAsUnsigned(0) \
396             & 1 << 2)
397
398     def is_initialized(self):
399         return self.valobj.GetValueAsUnsigned() != 0
400
401
402 class WTFStringViewProvider:
403     def __init__(self, valobj, dict):
404         self.valobj = valobj
405
406     def is_8bit(self):
407         return bool(self.valobj.GetChildMemberWithName('m_is8Bit').GetValueAsUnsigned(0))
408
409     def get_length(self):
410         return self.valobj.GetChildMemberWithName('m_length').GetValueAsUnsigned(0)
411
412     def get_characters(self):
413         return self.valobj.GetChildMemberWithName('m_characters')
414
415     def to_string(self):
416         error = lldb.SBError()
417
418         if not self.get_characters() or not self.get_length():
419             return u""
420
421         if self.is_8bit():
422             return lstring_to_string(self.get_characters(), error, self.get_length())
423         return ustring_to_string(self.get_characters(), error, self.get_length())
424
425
426 class WTFStringProvider:
427     def __init__(self, valobj, dict):
428         self.valobj = valobj
429
430     def stringimpl(self):
431         impl_ptr = self.valobj.GetChildMemberWithName('m_impl').GetChildMemberWithName('m_ptr')
432         return WTFStringImplProvider(impl_ptr, dict)
433
434     def get_length(self):
435         impl = self.stringimpl()
436         if not impl:
437             return 0
438         return impl.get_length()
439
440     def to_string(self):
441         impl = self.stringimpl()
442         if not impl:
443             return u""
444         return impl.to_string()
445
446
447 class WebCoreColorProvider:
448     "Print a WebCore::Color"
449     def __init__(self, valobj, dict):
450         self.valobj = valobj
451
452     def _is_extended(self, rgba_and_flags):
453         return not bool(rgba_and_flags & 0x1)
454
455     def _is_valid(self, rgba_and_flags):
456         # Assumes not extended.
457         return bool(rgba_and_flags & 0x2)
458
459     def _is_semantic(self, rgba_and_flags):
460         # Assumes not extended.
461         return bool(rgba_and_flags & 0x4)
462
463     def _to_string_extended(self):
464         extended_color = self.valobj.GetChildMemberWithName('m_colorData').GetChildMemberWithName('extendedColor').Dereference()
465         profile = extended_color.GetChildMemberWithName('m_colorSpace').GetValue()
466         if profile == 'ColorSpaceSRGB':
467             profile = 'srgb'
468         elif profile == 'ColorSpaceDisplayP3':
469             profile = 'display-p3'
470         else:
471             profile = 'unknown'
472         red = float(extended_color.GetChildMemberWithName('m_red').GetValue())
473         green = float(extended_color.GetChildMemberWithName('m_green').GetValue())
474         blue = float(extended_color.GetChildMemberWithName('m_blue').GetValue())
475         alpha = float(extended_color.GetChildMemberWithName('m_alpha').GetValue())
476         return "color(%s %1.2f %1.2f %1.2f / %1.2f)" % (profile, red, green, blue, alpha)
477
478     def to_string(self):
479         rgba_and_flags = self.valobj.GetChildMemberWithName('m_colorData').GetChildMemberWithName('rgbaAndFlags').GetValueAsUnsigned(0)
480
481         if self._is_extended(rgba_and_flags):
482             return self._to_string_extended()
483
484         if not self._is_valid(rgba_and_flags):
485             return 'invalid'
486
487         color = rgba_and_flags >> 32
488         red = (color >> 16) & 0xFF
489         green = (color >> 8) & 0xFF
490         blue = color & 0xFF
491         alpha = ((color >> 24) & 0xFF) / 255.0
492
493         semantic = ' semantic' if self._is_semantic(rgba_and_flags) else ""
494
495         result = 'rgba(%d, %d, %d, %1.2f)%s' % (red, green, blue, alpha, semantic)
496         return result
497
498
499 class WebCoreLayoutUnitProvider:
500     "Print a WebCore::LayoutUnit"
501     def __init__(self, valobj, dict):
502         self.valobj = valobj
503
504     def to_string(self):
505         layoutUnitValue = self.valobj.GetChildMemberWithName('m_value').GetValueAsSigned(0)
506         return "%gpx (%d)" % (float(layoutUnitValue) / 64, layoutUnitValue)
507
508
509 class WebCoreLayoutSizeProvider:
510     "Print a WebCore::LayoutSize"
511     def __init__(self, valobj, dict):
512         self.valobj = valobj
513
514     def get_width(self):
515         return WebCoreLayoutUnitProvider(self.valobj.GetChildMemberWithName('m_width'), dict).to_string()
516
517     def get_height(self):
518         return WebCoreLayoutUnitProvider(self.valobj.GetChildMemberWithName('m_height'), dict).to_string()
519
520
521 class WebCoreLayoutPointProvider:
522     "Print a WebCore::LayoutPoint"
523     def __init__(self, valobj, dict):
524         self.valobj = valobj
525
526     def get_x(self):
527         return WebCoreLayoutUnitProvider(self.valobj.GetChildMemberWithName('m_x'), dict).to_string()
528
529     def get_y(self):
530         return WebCoreLayoutUnitProvider(self.valobj.GetChildMemberWithName('m_y'), dict).to_string()
531
532
533 class WebCoreLayoutRectProvider:
534     "Print a WebCore::LayoutRect"
535     def __init__(self, valobj, dict):
536         self.valobj = valobj
537
538     def get_x(self):
539         return WebCoreLayoutPointProvider(self.valobj.GetChildMemberWithName('m_location'), dict).get_x()
540
541     def get_y(self):
542         return WebCoreLayoutPointProvider(self.valobj.GetChildMemberWithName('m_location'), dict).get_y()
543
544     def get_width(self):
545         return WebCoreLayoutSizeProvider(self.valobj.GetChildMemberWithName('m_size'), dict).get_width()
546
547     def get_height(self):
548         return WebCoreLayoutSizeProvider(self.valobj.GetChildMemberWithName('m_size'), dict).get_height()
549
550
551 class WebCoreIntPointProvider:
552     "Print a WebCore::IntPoint"
553     def __init__(self, valobj, dict):
554         self.valobj = valobj
555
556     def get_x(self):
557         return self.valobj.GetChildMemberWithName('m_x').GetValueAsSigned()
558
559     def get_y(self):
560         return self.valobj.GetChildMemberWithName('m_y').GetValueAsSigned()
561
562
563 class WebCoreIntSizeProvider:
564     "Print a WebCore::IntSize"
565     def __init__(self, valobj, dict):
566         self.valobj = valobj
567
568     def get_width(self):
569         return self.valobj.GetChildMemberWithName('m_width').GetValueAsSigned()
570
571     def get_height(self):
572         return self.valobj.GetChildMemberWithName('m_height').GetValueAsSigned()
573
574
575 class WebCoreIntRectProvider:
576     "Print a WebCore::IntRect"
577     def __init__(self, valobj, dict):
578         self.valobj = valobj
579
580     def get_x(self):
581         return WebCoreIntPointProvider(self.valobj.GetChildMemberWithName('m_location'), dict).get_x()
582
583     def get_y(self):
584         return WebCoreIntPointProvider(self.valobj.GetChildMemberWithName('m_location'), dict).get_y()
585
586     def get_width(self):
587         return WebCoreIntSizeProvider(self.valobj.GetChildMemberWithName('m_size'), dict).get_width()
588
589     def get_height(self):
590         return WebCoreIntSizeProvider(self.valobj.GetChildMemberWithName('m_size'), dict).get_height()
591
592
593 class WebCoreFloatPointProvider:
594     "Print a WebCore::FloatPoint"
595     def __init__(self, valobj, dict):
596         self.valobj = valobj
597
598     def get_x(self):
599         return float(self.valobj.GetChildMemberWithName('m_x').GetValue())
600
601     def get_y(self):
602         return float(self.valobj.GetChildMemberWithName('m_y').GetValue())
603
604
605 class WebCoreFloatSizeProvider:
606     "Print a WebCore::FloatSize"
607     def __init__(self, valobj, dict):
608         self.valobj = valobj
609
610     def get_width(self):
611         return float(self.valobj.GetChildMemberWithName('m_width').GetValue())
612
613     def get_height(self):
614         return float(self.valobj.GetChildMemberWithName('m_height').GetValue())
615
616
617 class WebCoreFloatRectProvider:
618     "Print a WebCore::FloatRect"
619     def __init__(self, valobj, dict):
620         self.valobj = valobj
621
622     def get_x(self):
623         return WebCoreFloatPointProvider(self.valobj.GetChildMemberWithName('m_location'), dict).get_x()
624
625     def get_y(self):
626         return WebCoreFloatPointProvider(self.valobj.GetChildMemberWithName('m_location'), dict).get_y()
627
628     def get_width(self):
629         return WebCoreFloatSizeProvider(self.valobj.GetChildMemberWithName('m_size'), dict).get_width()
630
631     def get_height(self):
632         return WebCoreFloatSizeProvider(self.valobj.GetChildMemberWithName('m_size'), dict).get_height()
633
634
635 class WTFURLProvider:
636     "Print a WTF::URL"
637     def __init__(self, valobj, dict):
638         self.valobj = valobj
639
640     def to_string(self):
641         return WTFStringProvider(self.valobj.GetChildMemberWithName('m_string'), dict).to_string()
642
643
644 class StdOptionalWrapper:
645     def __init__(self, valobj, internal_dict):
646         self.valobj = valobj
647
648     def has_value(self):
649         return bool(self.valobj.GetChildMemberWithName('init_').GetValueAsUnsigned(0))
650
651     def value(self):
652         return self.valobj.GetChildMemberWithName('storage_').GetChildMemberWithName('value_')
653
654
655 class WebCoreSecurityOriginProvider:
656     def __init__(self, valobj, internal_dict):
657         self.valobj = valobj
658         self._data_ptr = self.valobj.GetChildMemberWithName('m_data')
659
660     def is_unique(self):
661         return bool(self.valobj.GetChildMemberWithName('m_isUnique').GetValueAsUnsigned(0))
662
663     def scheme(self):
664         return WTFStringProvider(self._data_ptr.GetChildMemberWithName('protocol'), dict()).to_string()
665
666     def host(self):
667         return WTFStringProvider(self._data_ptr.GetChildMemberWithName('host'), dict()).to_string()
668
669     def port(self):
670         optional_port = StdOptionalWrapper(self._data_ptr.GetChildMemberWithName('port'), dict())
671         if not optional_port.has_value():
672             return None
673         return optional_port.value().GetValueAsUnsigned(0)
674
675     def domain(self):
676         return WTFStringProvider(self.valobj.GetChildMemberWithName('m_domain'), dict()).to_string()
677
678     def has_universal_access(self):
679         return bool(self.valobj.GetChildMemberWithName('m_universalAccess').GetValueAsUnsigned(0))
680
681     def to_string(self):
682         if self.is_unique():
683             return 'Unique'
684         scheme = self.scheme()
685         host = self.host()
686         port = self.port()
687         if not scheme and not host and not port:
688             return ''
689         if scheme == 'file:':
690             return 'file://'
691         result = '{}://{}'.format(scheme, host)
692         if port:
693             result += ':' + port
694         return result
695
696
697 class WebCoreFrameProvider:
698     def __init__(self, valobj, internal_dict):
699         self.valobj = valobj
700
701     def is_main_frame(self):
702         return self.valobj.GetAddress().GetFileAddress() == self.valobj.GetChildMemberWithName('m_mainFrame').GetAddress().GetFileAddress()
703
704     def document(self):
705         document_ptr = self.valobj.GetChildMemberWithName('m_doc').GetChildMemberWithName('m_ptr')
706         if not document_ptr or not bool(document_ptr.GetValueAsUnsigned(0)):
707             return None
708         return WebCoreDocumentProvider(document_ptr, dict())
709
710
711 class WebCoreDocumentProvider:
712     def __init__(self, valobj, internal_dict):
713         self.valobj = valobj
714
715     def url(self):
716         return WTFURLProvider(self.valobj.GetChildMemberWithName('m_url'), dict()).to_string()
717
718     def origin(self):
719         security_origin_ptr = self.valobj.GetChildMemberWithName('m_securityOriginPolicy').GetChildMemberWithName('m_ptr').GetChildMemberWithName('m_securityOrigin').GetChildMemberWithName('m_ptr')
720         return WebCoreSecurityOriginProvider(security_origin_ptr, dict()).to_string()
721
722     def page_cache_state(self):
723         return self.valobj.GetChildMemberWithName('m_pageCacheState').GetValue()
724
725     def frame(self):
726         frame_ptr = self.valobj.GetChildMemberWithName('m_frame')
727         if not frame_ptr or not bool(frame_ptr.GetValueAsUnsigned(0)):
728             return None
729         return WebCoreFrameProvider(frame_ptr, dict())
730
731
732 class FlagEnumerationProvider(object):
733     def __init__(self, valobj, internal_dict):
734         self.valobj = valobj
735         self.update()
736
737     # Subclasses must override this to return a dictionary that maps emumerator values to names.
738     def _enumerator_value_to_name_map(self):
739         pass
740
741     # Subclasses must override this to return the bitmask.
742     def _bitmask(self):
743         pass
744
745     # Subclasses can override this to perform any computations when LLDB needs to refresh
746     # this provider.
747     def _update(self):
748         pass
749
750     def has_children(self):
751         return bool(self._elements)
752
753     def num_children(self):
754         return len(self._elements)
755
756     def get_child_index(self, name):
757         try:
758             return int(name.lstrip('[').rstrip(']'))
759         except:
760             return None
761
762     def get_child_at_index(self, index):
763         if index < 0 or not self.valobj.IsValid():
764             return None
765         if index < len(self._elements):
766             (name, value) = self._elements[index]
767             return self.valobj.CreateValueFromExpression(name, str(value))
768         return None
769
770     def update(self):
771         self._update()
772
773         self._elements = []
774         self.size = 0
775
776         enumerator_value_to_name_map = self._enumerator_value_to_name_map()
777         if not enumerator_value_to_name_map:
778             return
779
780         bitmask_with_all_options_set = sum(enumerator_value_to_name_map)
781         bitmask = self._bitmask()
782         if bitmask > bitmask_with_all_options_set:
783             return  # Since this is an invalid value, return so the raw hex form is written out.
784
785         # self.valobj looks like it contains a valid value.
786         # Iterate from least significant bit to most significant bit.
787         elements = []
788         while bitmask > 0:
789             current = bitmask & -bitmask  # Isolate the rightmost set bit.
790             elements.append((enumerator_value_to_name_map[current], current))  # e.g. ('Spelling', 4)
791             bitmask = bitmask & (bitmask - 1)  # Turn off the rightmost set bit.
792         self._elements = elements
793         self.size = len(elements)
794
795
796 class WTFOptionSetProvider(FlagEnumerationProvider):
797     def _enumerator_value_to_name_map(self):
798         template_argument_sbType = self.valobj.GetType().GetTemplateArgumentType(0)
799         enumerator_value_to_name_map = {}
800         for sbTypeEnumMember in template_argument_sbType.get_enum_members_array():
801             enumerator_value = sbTypeEnumMember.GetValueAsUnsigned()
802             if enumerator_value not in enumerator_value_to_name_map:
803                 enumerator_value_to_name_map[enumerator_value] = sbTypeEnumMember.GetName()
804         return enumerator_value_to_name_map
805
806     def _bitmask(self):
807         return self.storage.GetValueAsUnsigned(0)
808
809     def _update(self):
810         self.storage = self.valobj.GetChildMemberWithName('m_storage')  # May be an invalid value.
811
812
813 class RawBitmaskProviderBase(FlagEnumerationProvider):
814     ENUMERATOR_VALUE_TO_NAME_MAP = {}
815
816     def _enumerator_value_to_name_map(self):
817         return self.ENUMERATOR_VALUE_TO_NAME_MAP
818
819     def _bitmask(self):
820         return self.valobj.GetValueAsUnsigned(0)
821
822
823 class WTFVectorProvider:
824     def __init__(self, valobj, internal_dict):
825         self.valobj = valobj
826         self.update()
827
828     def num_children(self):
829         return self.size + 3
830
831     def get_child_index(self, name):
832         if name == "m_size":
833             return self.size
834         elif name == "m_capacity":
835             return self.size + 1
836         elif name == "m_buffer":
837             return self.size + 2
838         else:
839             return int(name.lstrip('[').rstrip(']'))
840
841     def get_child_at_index(self, index):
842         if index == self.size:
843             return self.valobj.GetChildMemberWithName("m_size")
844         elif index == self.size + 1:
845             return self.valobj.GetChildMemberWithName("m_capacity")
846         elif index == self.size + 2:
847             return self.buffer
848         elif index < self.size:
849             offset = index * self.data_size
850             child = self.buffer.CreateChildAtOffset('[' + str(index) + ']', offset, self.data_type)
851             return child
852         else:
853             return None
854
855     def update(self):
856         self.buffer = self.valobj.GetChildMemberWithName('m_buffer')
857         self.size = self.valobj.GetChildMemberWithName('m_size').GetValueAsUnsigned(0)
858         self.capacity = self.valobj.GetChildMemberWithName('m_capacity').GetValueAsUnsigned(0)
859         self.data_type = self.buffer.GetType().GetPointeeType()
860         self.data_size = self.data_type.GetByteSize()
861
862     def has_children(self):
863         return True
864
865
866 class WTFHashMapProvider:
867     def __init__(self, valobj, internal_dict):
868         self.valobj = valobj
869         impl_ptr = self.valobj.GetChildMemberWithName('m_impl')
870         self._hash_table_provider = WTFHashTableProvider(impl_ptr, dict)
871
872     def tableSize(self):
873         return self._hash_table_provider.tableSize()
874
875     def keyCount(self):
876         return self._hash_table_provider.keyCount()
877
878
879 class WTFHashSetProvider:
880     def __init__(self, valobj, internal_dict):
881         self.valobj = valobj
882         impl_ptr = self.valobj.GetChildMemberWithName('m_impl')
883         self._hash_table_provider = WTFHashTableProvider(impl_ptr, dict)
884
885     def tableSize(self):
886         return self._hash_table_provider.tableSize()
887
888     def keyCount(self):
889         return self._hash_table_provider.keyCount()
890
891
892 class WTFHashTableProvider:
893     def __init__(self, valobj, internal_dict):
894         self.valobj = valobj
895         self.update()
896
897     def tableSize(self):
898         return self.valobj.GetChildMemberWithName('m_tableSize').GetValueAsUnsigned(0)
899
900     def keyCount(self):
901         return self.valobj.GetChildMemberWithName('m_keyCount').GetValueAsUnsigned(0)
902
903     # Synthetic children provider methods.
904     def num_children(self):
905         return self.tableSize() + 5
906
907     def get_child_index(self, name):
908         if name == "m_table":
909             return self.tableSize()
910         elif name == "m_tableSize":
911             return self.tableSize() + 1
912         elif name == "m_tableSizeMask":
913             return self.tableSize() + 2
914         elif name == "m_keyCount":
915             return self.tableSize() + 3
916         elif name == "m_deletedCount":
917             return self.tableSize() + 4
918         else:
919             return int(name.lstrip('[').rstrip(']'))
920
921     def get_child_at_index(self, index):
922         if index == self.tableSize():
923             return self.valobj.GetChildMemberWithName('m_table')
924         elif index == self.tableSize() + 1:
925             return self.valobj.GetChildMemberWithName('m_tableSize')
926         elif index == self.tableSize() + 2:
927             return self.valobj.GetChildMemberWithName('m_tableSizeMask')
928         elif index == self.tableSize() + 3:
929             return self.valobj.GetChildMemberWithName('m_keyCount')
930         elif index == self.tableSize() + 4:
931             return self.valobj.GetChildMemberWithName('m_deletedCount')
932         elif index < self.tableSize():
933             table = self.valobj.GetChildMemberWithName('m_table')
934             return table.CreateChildAtOffset('[' + str(index) + ']', index * self.data_size, self.data_type)
935         else:
936             return None
937
938     def update(self):
939         self.data_type = self.valobj.GetType().GetTemplateArgumentType(1)
940         self.data_size = self.data_type.GetByteSize()
941
942     def has_children(self):
943         return True
944
945
946 class WTFMediaTimeProvider:
947     def __init__(self, valobj, internal_dict):
948         self.valobj = valobj
949
950     def timeValue(self):
951         return self.valobj.GetChildMemberWithName('m_timeValue').GetValueAsSigned(0)
952
953     def timeValueAsDouble(self):
954         error = lldb.SBError()
955         return self.valobj.GetChildMemberWithName('m_timeValueAsDouble').GetData().GetDouble(error, 0)
956
957     def timeScale(self):
958         return self.valobj.GetChildMemberWithName('m_timeScale').GetValueAsSigned(0)
959
960     def isInvalid(self):
961         return not self.valobj.GetChildMemberWithName('m_timeFlags').GetValueAsSigned(0) & (1 << 0)
962
963     def isPositiveInfinity(self):
964         return self.valobj.GetChildMemberWithName('m_timeFlags').GetValueAsSigned(0) & (1 << 2)
965
966     def isNegativeInfinity(self):
967         return self.valobj.GetChildMemberWithName('m_timeFlags').GetValueAsSigned(0) & (1 << 3)
968
969     def isIndefinite(self):
970         return self.valobj.GetChildMemberWithName('m_timeFlags').GetValueAsSigned(0) & (1 << 4)
971
972     def hasDoubleValue(self):
973         return self.valobj.GetChildMemberWithName('m_timeFlags').GetValueAsSigned(0) & (1 << 5)