1 # Copyright (C) 2010, Google Inc. All rights reserved.
3 # Redistribution and use in source and binary forms, with or without
4 # modification, are permitted provided that the following conditions are
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
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.
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.
29 """GDB support for WebKit types.
31 Add this to your gdb by amending your ~/.gdbinit as follows:
34 sys.path.insert(0, "/path/to/tools/gdb/")
38 from __future__ import print_function
44 def guess_string_length(ptr):
45 """Guess length of string pointed by ptr.
47 Returns a tuple of (length, an error message).
49 # Try to guess at the length.
50 for i in range(0, 2048):
52 if int((ptr + i).dereference()) == 0:
55 # We indexed into inaccessible memory; give up.
56 return i, ' (gdb hit inaccessible memory)'
57 return 256, ' (gdb found no trailing NUL)'
60 def ustring_to_string(ptr, length=None):
61 """Convert a pointer to UTF-16 data into a Python string encoded with utf-8.
63 ptr and length are both gdb.Value objects.
64 If length is unspecified, will guess at the length."""
67 length, error_message = guess_string_length(ptr)
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
75 def lstring_to_string(ptr, length=None):
76 """Convert a pointer to LChar* data into a Python (non-Unicode) string.
78 ptr and length are both gdb.Value objects.
79 If length is unspecified, will guess at the length."""
82 length, error_message = guess_string_length(ptr)
85 string = ''.join([chr((ptr + i).dereference()) for i in range(length)])
86 return string + error_message
89 class StringPrinter(object):
90 "Shared code between different string-printing classes"
91 def __init__(self, val):
94 def display_hint(self):
98 class UCharStringPrinter(StringPrinter):
99 "Print a UChar*; we must guess at the length"
101 return ustring_to_string(self.val)
104 class LCharStringPrinter(StringPrinter):
105 "Print a LChar*; we must guess at the length"
107 return lstring_to_string(self.val)
110 class WTFAtomicStringPrinter(StringPrinter):
111 "Print a WTF::AtomicString"
113 return self.val['m_string']
116 class WTFCStringPrinter(StringPrinter):
117 "Print a WTF::CString"
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)])
125 class WTFStringImplPrinter(StringPrinter):
126 "Print a WTF::StringImpl"
127 def get_length(self):
128 return self.val['m_length']
131 chars_start = self.val.address + 1
133 return lstring_to_string(chars_start.cast(gdb.lookup_type('char').pointer()),
135 return ustring_to_string(chars_start.cast(gdb.lookup_type('UChar').pointer()),
139 return self.val['m_is8Bit']
142 class WTFStringPrinter(StringPrinter):
143 "Print a WTF::String"
144 def stringimpl_ptr(self):
145 return self.val['m_impl']['m_ptr']
147 def get_length(self):
148 if not self.stringimpl_ptr():
150 return WTFStringImplPrinter(self.stringimpl_ptr().dereference()).get_length()
153 if not self.stringimpl_ptr():
155 return self.stringimpl_ptr().dereference()
159 class blinkKURLPrinter(StringPrinter):
160 "Print a blink::KURL"
162 return WTFStringPrinter(self.val['m_string']).to_string()
165 class blinkLayoutUnitPrinter:
166 "Print a blink::LayoutUnit"
167 def __init__(self, val):
171 return "%gpx" % (self.val['m_value'] / 64.0)
174 class blinkLayoutSizePrinter:
175 "Print a blink::LayoutSize"
176 def __init__(self, val):
180 return 'LayoutSize(%s, %s)' % (blinkLayoutUnitPrinter(self.val['m_width']).to_string(), blinkLayoutUnitPrinter(self.val['m_height']).to_string())
183 class blinkLayoutPointPrinter:
184 "Print a blink::LayoutPoint"
185 def __init__(self, val):
189 return 'LayoutPoint(%s, %s)' % (blinkLayoutUnitPrinter(self.val['m_x']).to_string(), blinkLayoutUnitPrinter(self.val['m_y']).to_string())
192 class blinkQualifiedNamePrinter(StringPrinter):
193 "Print a blink::QualifiedName"
195 def __init__(self, val):
196 super(blinkQualifiedNamePrinter, self).__init__(val)
197 self.prefix_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())
209 self.length = self.local_name_printer.get_length()
211 def get_length(self):
215 if self.get_length() == 0:
218 if self.prefix_length > 0:
219 return (self.prefix_printer.to_string() + ":" +
220 self.local_name_printer.to_string())
222 return self.local_name_printer.to_string()
225 class WTFVectorPrinter:
226 """Pretty Printer for a WTF::Vector.
228 The output of this pretty printer is similar to the output of std::vector's
229 pretty printer, which is bundled in gcc.
231 Example gdb session should look like:
233 $3 = WTF::Vector of length 7, capacity 16 = {7, 17, 27, 37, 47, 57, 67}
234 (gdb) set print elements 3
236 $6 = WTF::Vector of length 7, capacity 16 = {7, 17, 27...}
237 (gdb) set print array
239 $7 = WTF::Vector of length 7, capacity 16 = {
245 (gdb) set print elements 200
247 $8 = WTF::Vector of length 7, capacity 16 = {
259 def __init__(self, start, finish):
268 if self.item == self.finish:
272 element = self.item.dereference()
274 return ('[%d]' % count, element)
276 def __init__(self, val):
280 start = self.val['m_buffer']
281 return self.Iterator(start, start + self.val['m_size'])
284 return ('%s of length %d, capacity %d'
285 % ('WTF::Vector', self.val['m_size'], self.val['m_capacity']))
287 def display_hint(self):
290 def add_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),
304 def lookup_function(val):
305 """Function used to load pretty printers; will be passed to GDB."""
307 if type.code == gdb.TYPE_CODE_REF:
309 type = type.unqualified().strip_typedefs()
312 for function, pretty_printer in pretty_printers:
313 if function.search(tag):
314 return pretty_printer(val)
316 if type.code == gdb.TYPE_CODE_PTR:
317 name = str(type.target().unqualified())
319 return UCharStringPrinter(val)
321 return LCharStringPrinter(val)
324 gdb.pretty_printers.append(lookup_function)
327 add_pretty_printers()
330 class PrintPathToRootCommand(gdb.Command):
331 """Command for printing WebKit Node trees.
333 Usage: printpathtoroot variable_name"""
336 super(PrintPathToRootCommand, self).__init__("printpathtoroot",
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()
345 val = gdb.Frame.read_var(frame, arg)
347 print("No such variable, or invalid type")
350 target_type = str(val.type.target().strip_typedefs())
351 if target_type == str(node_type):
355 val.cast(element_type.pointer()).dereference()['m_tagName']])
356 val = val.dereference()['m_parent']
359 while len(stack) > 0:
361 print(padding, pair[1], pair[0])
362 padding = padding + ' '
364 print('Sorry: I don\'t know how to deal with %s yet.' % target_type)
367 PrintPathToRootCommand()