Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Tools / gdb / webkit.py
1 # Copyright (C) 2010, Google 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 are
5 # met:
6 #
7 #     * Redistributions of source code must retain the above copyright
8 # notice, this list of conditions and the following disclaimer.
9 #     * Redistributions in binary form must reproduce the above
10 # copyright notice, this list of conditions and the following disclaimer
11 # in the documentation and/or other materials provided with the
12 # distribution.
13 #     * Neither the name of Google Inc. nor the names of its
14 # contributors may be used to endorse or promote products derived from
15 # this software without specific prior written permission.
16 #
17 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28
29 """GDB support for WebKit types.
30
31 Add this to your gdb by amending your ~/.gdbinit as follows:
32   python
33   import sys
34   sys.path.insert(0, "/path/to/tools/gdb/")
35   import webkit
36 """
37
38 from __future__ import print_function
39
40 import gdb
41 import re
42 import struct
43
44 def guess_string_length(ptr):
45     """Guess length of string pointed by ptr.
46
47     Returns a tuple of (length, an error message).
48     """
49     # Try to guess at the length.
50     for i in range(0, 2048):
51         try:
52             if int((ptr + i).dereference()) == 0:
53                 return i, ''
54         except RuntimeError:
55             # We indexed into inaccessible memory; give up.
56             return i, ' (gdb hit inaccessible memory)'
57     return 256, ' (gdb found no trailing NUL)'
58
59
60 def ustring_to_string(ptr, length=None):
61     """Convert a pointer to UTF-16 data into a Python string encoded with utf-8.
62
63     ptr and length are both gdb.Value objects.
64     If length is unspecified, will guess at the length."""
65     error_message = ''
66     if length is None:
67         length, error_message = guess_string_length(ptr)
68     else:
69         length = int(length)
70     char_vals = [int((ptr + i).dereference()) for i in range(length)]
71     string = struct.pack('H' * length, *char_vals).decode('utf-16', 'replace').encode('utf-8')
72     return string + error_message
73
74
75 def lstring_to_string(ptr, length=None):
76     """Convert a pointer to LChar* data into a Python (non-Unicode) string.
77
78     ptr and length are both gdb.Value objects.
79     If length is unspecified, will guess at the length."""
80     error_message = ''
81     if length is None:
82         length, error_message = guess_string_length(ptr)
83     else:
84         length = int(length)
85     string = ''.join([chr((ptr + i).dereference()) for i in range(length)])
86     return string + error_message
87
88
89 class StringPrinter(object):
90     "Shared code between different string-printing classes"
91     def __init__(self, val):
92         self.val = val
93
94     def display_hint(self):
95         return 'string'
96
97
98 class UCharStringPrinter(StringPrinter):
99     "Print a UChar*; we must guess at the length"
100     def to_string(self):
101         return ustring_to_string(self.val)
102
103
104 class LCharStringPrinter(StringPrinter):
105     "Print a LChar*; we must guess at the length"
106     def to_string(self):
107         return lstring_to_string(self.val)
108
109
110 class WTFAtomicStringPrinter(StringPrinter):
111     "Print a WTF::AtomicString"
112     def to_string(self):
113         return self.val['m_string']
114
115
116 class WTFCStringPrinter(StringPrinter):
117     "Print a WTF::CString"
118     def to_string(self):
119         # The CString holds a buffer, which is a refptr to a WTF::CStringBuffer.
120         data = self.val['m_buffer']['m_ptr']['m_data'].cast(gdb.lookup_type('char').pointer())
121         length = self.val['m_buffer']['m_ptr']['m_length']
122         return ''.join([chr((data + i).dereference()) for i in range(length)])
123
124
125 class WTFStringImplPrinter(StringPrinter):
126     "Print a WTF::StringImpl"
127     def get_length(self):
128         return self.val['m_length']
129
130     def to_string(self):
131         chars_start = self.val.address + 1
132         if self.is_8bit():
133             return lstring_to_string(chars_start.cast(gdb.lookup_type('char').pointer()),
134                                      self.get_length())
135         return ustring_to_string(chars_start.cast(gdb.lookup_type('UChar').pointer()),
136                                  self.get_length())
137
138     def is_8bit(self):
139         return self.val['m_is8Bit']
140
141
142 class WTFStringPrinter(StringPrinter):
143     "Print a WTF::String"
144     def stringimpl_ptr(self):
145         return self.val['m_impl']['m_ptr']
146
147     def get_length(self):
148         if not self.stringimpl_ptr():
149             return 0
150         return WTFStringImplPrinter(self.stringimpl_ptr().dereference()).get_length()
151
152     def to_string(self):
153         if not self.stringimpl_ptr():
154             return '(null)'
155         return self.stringimpl_ptr().dereference()
156
157
158
159 class blinkKURLPrinter(StringPrinter):
160     "Print a blink::KURL"
161     def to_string(self):
162         return WTFStringPrinter(self.val['m_string']).to_string()
163
164
165 class blinkLayoutUnitPrinter:
166     "Print a blink::LayoutUnit"
167     def __init__(self, val):
168         self.val = val
169
170     def to_string(self):
171         return "%gpx" % (self.val['m_value'] / 64.0)
172
173
174 class blinkLayoutSizePrinter:
175     "Print a blink::LayoutSize"
176     def __init__(self, val):
177         self.val = val
178
179     def to_string(self):
180         return 'LayoutSize(%s, %s)' % (blinkLayoutUnitPrinter(self.val['m_width']).to_string(), blinkLayoutUnitPrinter(self.val['m_height']).to_string())
181
182
183 class blinkLayoutPointPrinter:
184     "Print a blink::LayoutPoint"
185     def __init__(self, val):
186         self.val = val
187
188     def to_string(self):
189         return 'LayoutPoint(%s, %s)' % (blinkLayoutUnitPrinter(self.val['m_x']).to_string(), blinkLayoutUnitPrinter(self.val['m_y']).to_string())
190
191
192 class blinkQualifiedNamePrinter(StringPrinter):
193     "Print a blink::QualifiedName"
194
195     def __init__(self, val):
196         super(blinkQualifiedNamePrinter, self).__init__(val)
197         self.prefix_length = 0
198         self.length = 0
199         if self.val['m_impl']:
200             self.prefix_printer = WTFStringPrinter(
201                 self.val['m_impl']['m_ptr']['m_prefix']['m_string'])
202             self.local_name_printer = WTFStringPrinter(
203                 self.val['m_impl']['m_ptr']['m_localName']['m_string'])
204             self.prefix_length = self.prefix_printer.get_length()
205             if self.prefix_length > 0:
206                 self.length = (self.prefix_length + 1 +
207                     self.local_name_printer.get_length())
208             else:
209                 self.length = self.local_name_printer.get_length()
210
211     def get_length(self):
212         return self.length
213
214     def to_string(self):
215         if self.get_length() == 0:
216             return "(null)"
217         else:
218             if self.prefix_length > 0:
219                 return (self.prefix_printer.to_string() + ":" +
220                     self.local_name_printer.to_string())
221             else:
222                 return self.local_name_printer.to_string()
223
224
225 class WTFVectorPrinter:
226     """Pretty Printer for a WTF::Vector.
227
228     The output of this pretty printer is similar to the output of std::vector's
229     pretty printer, which is bundled in gcc.
230
231     Example gdb session should look like:
232     (gdb) p v
233     $3 = WTF::Vector of length 7, capacity 16 = {7, 17, 27, 37, 47, 57, 67}
234     (gdb) set print elements 3
235     (gdb) p v
236     $6 = WTF::Vector of length 7, capacity 16 = {7, 17, 27...}
237     (gdb) set print array
238     (gdb) p v
239     $7 = WTF::Vector of length 7, capacity 16 = {
240       7,
241       17,
242       27
243       ...
244     }
245     (gdb) set print elements 200
246     (gdb) p v
247     $8 = WTF::Vector of length 7, capacity 16 = {
248       7,
249       17,
250       27,
251       37,
252       47,
253       57,
254       67
255     }
256     """
257
258     class Iterator:
259         def __init__(self, start, finish):
260             self.item = start
261             self.finish = finish
262             self.count = 0
263
264         def __iter__(self):
265             return self
266
267         def next(self):
268             if self.item == self.finish:
269                 raise StopIteration
270             count = self.count
271             self.count += 1
272             element = self.item.dereference()
273             self.item += 1
274             return ('[%d]' % count, element)
275
276     def __init__(self, val):
277         self.val = val
278
279     def children(self):
280         start = self.val['m_buffer']
281         return self.Iterator(start, start + self.val['m_size'])
282
283     def to_string(self):
284         return ('%s of length %d, capacity %d'
285                 % ('WTF::Vector', self.val['m_size'], self.val['m_capacity']))
286
287     def display_hint(self):
288         return 'array'
289
290 def add_pretty_printers():
291     pretty_printers = (
292         (re.compile("^WTF::Vector<.*>$"), WTFVectorPrinter),
293         (re.compile("^WTF::AtomicString$"), WTFAtomicStringPrinter),
294         (re.compile("^WTF::CString$"), WTFCStringPrinter),
295         (re.compile("^WTF::String$"), WTFStringPrinter),
296         (re.compile("^WTF::StringImpl$"), WTFStringImplPrinter),
297         (re.compile("^blink::KURL$"), blinkKURLPrinter),
298         (re.compile("^blink::LayoutUnit$"), blinkLayoutUnitPrinter),
299         (re.compile("^blink::LayoutPoint$"), blinkLayoutPointPrinter),
300         (re.compile("^blink::LayoutSize$"), blinkLayoutSizePrinter),
301         (re.compile("^blink::QualifiedName$"), blinkQualifiedNamePrinter),
302     )
303
304     def lookup_function(val):
305         """Function used to load pretty printers; will be passed to GDB."""
306         type = val.type
307         if type.code == gdb.TYPE_CODE_REF:
308             type = type.target()
309         type = type.unqualified().strip_typedefs()
310         tag = type.tag
311         if tag:
312             for function, pretty_printer in pretty_printers:
313                 if function.search(tag):
314                     return pretty_printer(val)
315
316         if type.code == gdb.TYPE_CODE_PTR:
317             name = str(type.target().unqualified())
318             if name == 'UChar':
319                 return UCharStringPrinter(val)
320             if name == 'LChar':
321                 return LCharStringPrinter(val)
322         return None
323
324     gdb.pretty_printers.append(lookup_function)
325
326
327 add_pretty_printers()
328
329
330 class PrintPathToRootCommand(gdb.Command):
331     """Command for printing WebKit Node trees.
332
333     Usage: printpathtoroot variable_name"""
334
335     def __init__(self):
336         super(PrintPathToRootCommand, self).__init__("printpathtoroot",
337             gdb.COMMAND_SUPPORT,
338             gdb.COMPLETE_NONE)
339
340     def invoke(self, arg, from_tty):
341         element_type = gdb.lookup_type('blink::Element')
342         node_type = gdb.lookup_type('blink::Node')
343         frame = gdb.selected_frame()
344         try:
345             val = gdb.Frame.read_var(frame, arg)
346         except:
347             print("No such variable, or invalid type")
348             return
349
350         target_type = str(val.type.target().strip_typedefs())
351         if target_type == str(node_type):
352             stack = []
353             while val:
354                 stack.append([val,
355                     val.cast(element_type.pointer()).dereference()['m_tagName']])
356                 val = val.dereference()['m_parent']
357
358             padding = ''
359             while len(stack) > 0:
360                 pair = stack.pop()
361                 print(padding, pair[1], pair[0])
362                 padding = padding + '  '
363         else:
364             print('Sorry: I don\'t know how to deal with %s yet.' % target_type)
365
366
367 PrintPathToRootCommand()