1 # Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 # Use of this source code is governed by a BSD-style license that can be
3 # found in the LICENSE file.
5 """GDB support for Chrome types.
7 Add this to your gdb by amending your ~/.gdbinit as follows:
10 sys.path.insert(0, "/path/to/tools/gdb/")
15 (gdb) p /r any_variable
16 to print |any_variable| without using any printers.
25 sys
.path
.insert(0, os
.path
.join(
26 os
.path
.dirname(os
.path
.abspath(__file__
)),
27 '..', '..', 'third_party', 'WebKit', 'Tools', 'gdb'))
33 # When debugging this module, set the below variable to True, and then use
34 # (gdb) python del sys.modules['gdb_chrome']
35 # (gdb) python import gdb_chrome
40 pp_set
= gdb
.printing
.RegexpCollectionPrettyPrinter("chromium")
44 """Prints a pointer along with its exact type.
46 By default, gdb would print just the address, which takes more
49 # Returning this as a cast expression surrounded by parentheses
50 # makes it easier to cut+paste inside of gdb.
51 return '((%s)%s)' % (ptr
.dynamic_type
, ptr
)
54 def yield_fields(val
):
55 """Use this in a printer's children() method to print an object's fields.
59 for result in yield_fields(self.val):
63 fields
= val
.type.target().fields()
65 fields
= val
.type.fields()
67 if field
.is_base_class
:
68 yield (field
.name
, val
.cast(gdb
.lookup_type(field
.name
)))
70 yield (field
.name
, val
[field
.name
])
73 class Printer(object):
74 def __init__(self
, val
):
78 class StringPrinter(Printer
):
79 def display_hint(self
):
83 class String16Printer(StringPrinter
):
85 return webkit
.ustring_to_string(self
.val
['_M_dataplus']['_M_p'])
88 '^string16|std::basic_string<(unsigned short|base::char16).*>$',
92 class GURLPrinter(StringPrinter
):
94 return self
.val
['spec_']
95 pp_set
.add_printer('GURL', '^GURL$', GURLPrinter
)
98 class FilePathPrinter(StringPrinter
):
100 return self
.val
['path_']['_M_dataplus']['_M_p']
101 pp_set
.add_printer('FilePath', '^FilePath$', FilePathPrinter
)
104 class SizePrinter(Printer
):
106 return '%sx%s' % (self
.val
['width_'], self
.val
['height_'])
107 pp_set
.add_printer('gfx::Size', '^gfx::(Size|SizeF|SizeBase<.*>)$', SizePrinter
)
110 class PointPrinter(Printer
):
112 return '%s,%s' % (self
.val
['x_'], self
.val
['y_'])
113 pp_set
.add_printer('gfx::Point', '^gfx::(Point|PointF|PointBase<.*>)$',
117 class RectPrinter(Printer
):
119 return '%s %s' % (self
.val
['origin_'], self
.val
['size_'])
120 pp_set
.add_printer('gfx::Rect', '^gfx::(Rect|RectF|RectBase<.*>)$',
124 class SmartPtrPrinter(Printer
):
126 return '%s%s' % (self
.typename
, typed_ptr(self
.ptr()))
129 class ScopedRefPtrPrinter(SmartPtrPrinter
):
130 typename
= 'scoped_refptr'
132 return self
.val
['ptr_']
133 pp_set
.add_printer('scoped_refptr', '^scoped_refptr<.*>$', ScopedRefPtrPrinter
)
136 class LinkedPtrPrinter(SmartPtrPrinter
):
137 typename
= 'linked_ptr'
139 return self
.val
['value_']
140 pp_set
.add_printer('linked_ptr', '^linked_ptr<.*>$', LinkedPtrPrinter
)
143 class WeakPtrPrinter(SmartPtrPrinter
):
144 typename
= 'base::WeakPtr'
146 flag
= ScopedRefPtrPrinter(self
.val
['ref_']['flag_']).ptr()
147 if flag
and flag
['is_valid_']:
148 return self
.val
['ptr_']
149 return gdb
.Value(0).cast(self
.val
['ptr_'].type)
150 pp_set
.add_printer('base::WeakPtr', '^base::WeakPtr<.*>$', WeakPtrPrinter
)
153 class CallbackPrinter(Printer
):
154 """Callbacks provide no usable information so reduce the space they take."""
157 pp_set
.add_printer('base::Callback', '^base::Callback<.*>$', CallbackPrinter
)
160 class LocationPrinter(Printer
):
162 return '%s()@%s:%s' % (self
.val
['function_name_'].string(),
163 self
.val
['file_name_'].string(),
164 self
.val
['line_number_'])
165 pp_set
.add_printer('tracked_objects::Location', '^tracked_objects::Location$',
169 class PendingTaskPrinter(Printer
):
171 return 'From %s' % (self
.val
['posted_from'],)
174 for result
in yield_fields(self
.val
):
175 if result
[0] not in ('task', 'posted_from'):
177 pp_set
.add_printer('base::PendingTask', '^base::PendingTask$',
181 class LockPrinter(Printer
):
184 if self
.val
['owned_by_thread_']:
185 return 'Locked by thread %s' % self
.val
['owning_thread_id_']
189 return 'Unknown state'
190 pp_set
.add_printer('base::Lock', '^base::Lock$', LockPrinter
)
193 class TimeDeltaPrinter(object):
194 def __init__(self
, val
):
195 self
._timedelta
= datetime
.timedelta(microseconds
=int(val
['delta_']))
198 return self
._timedelta
201 return str(self
._timedelta
)
202 pp_set
.add_printer('base::TimeDelta', '^base::TimeDelta$', TimeDeltaPrinter
)
205 class TimeTicksPrinter(TimeDeltaPrinter
):
206 def __init__(self
, val
):
207 self
._timedelta
= datetime
.timedelta(microseconds
=int(val
['ticks_']))
208 pp_set
.add_printer('base::TimeTicks', '^base::TimeTicks$', TimeTicksPrinter
)
211 class TimePrinter(object):
212 def __init__(self
, val
):
213 timet_offset
= gdb
.parse_and_eval(
214 'base::Time::kTimeTToMicrosecondsOffset')
215 self
._datetime
= (datetime
.datetime
.fromtimestamp(0) +
216 datetime
.timedelta(microseconds
=
217 int(val
['us_'] - timet_offset
)))
220 return self
._datetime
223 return str(self
._datetime
)
224 pp_set
.add_printer('base::Time', '^base::Time$', TimePrinter
)
227 class IpcMessagePrinter(Printer
):
229 return self
.val
['header_'].cast(
230 gdb
.lookup_type('IPC::Message::Header').pointer())
233 message_type
= self
.header()['type']
234 return '%s of kind %s line %s' % (
235 self
.val
.dynamic_type
,
236 (message_type
>> 16).cast(gdb
.lookup_type('IPCMessageStart')),
237 message_type
& 0xffff)
240 yield ('header_', self
.header().dereference())
241 yield ('capacity_after_header_', self
.val
['capacity_after_header_'])
242 for field
in self
.val
.type.fields():
243 if field
.is_base_class
:
245 yield (field
.name
, self
.val
[field
.name
])
246 pp_set
.add_printer('IPC::Message', '^IPC::Message$', IpcMessagePrinter
)
249 class NotificationRegistrarPrinter(Printer
):
252 registrations
= self
.val
['registered_']
253 vector_finish
= registrations
['_M_impl']['_M_finish']
254 vector_start
= registrations
['_M_impl']['_M_start']
255 if vector_start
== vector_finish
:
256 return 'Not watching notifications'
257 if vector_start
.dereference().type.sizeof
== 0:
258 # Incomplete type: b/8242773
259 return 'Watching some notifications'
260 return ('Watching %s notifications; '
261 'print %s->registered_ for details') % (
262 int(vector_finish
- vector_start
),
263 typed_ptr(self
.val
.address
))
265 return 'NotificationRegistrar'
266 pp_set
.add_printer('content::NotificationRegistrar',
267 '^content::NotificationRegistrar$',
268 NotificationRegistrarPrinter
)
271 class SiteInstanceImplPrinter(object):
272 def __init__(self
, val
):
273 self
.val
= val
.cast(val
.dynamic_type
)
276 return 'SiteInstanceImpl@%s for %s' % (
277 self
.val
.address
, self
.val
['site_'])
280 yield ('id_', self
.val
['id_'])
281 yield ('has_site_', self
.val
['has_site_'])
282 if self
.val
['browsing_instance_']['ptr_']:
283 yield ('browsing_instance_', self
.val
['browsing_instance_']['ptr_'])
284 if self
.val
['process_']:
285 yield ('process_', typed_ptr(self
.val
['process_']))
286 pp_set
.add_printer('content::SiteInstanceImpl', '^content::SiteInstanceImpl$',
287 SiteInstanceImplPrinter
)
290 class RenderProcessHostImplPrinter(object):
291 def __init__(self
, val
):
292 self
.val
= val
.cast(val
.dynamic_type
)
297 child_process_launcher_ptr
= (
298 self
.val
['child_process_launcher_']['impl_']['data_']['ptr'])
299 if child_process_launcher_ptr
:
300 context
= (child_process_launcher_ptr
['context_']['ptr_'])
302 pid
= ' PID %s' % str(context
['process_']['process_'])
304 # The definition of the Context type may not be available.
307 return 'RenderProcessHostImpl@%s%s' % (self
.val
.address
, pid
)
310 yield ('id_', self
.val
['id_'])
312 self
.val
['listeners_']['data_'])
313 yield ('worker_ref_count_', self
.val
['worker_ref_count_'])
314 yield ('fast_shutdown_started_', self
.val
['fast_shutdown_started_'])
315 yield ('deleting_soon_', self
.val
['deleting_soon_'])
316 yield ('pending_views_', self
.val
['pending_views_'])
317 yield ('visible_widgets_', self
.val
['visible_widgets_'])
318 yield ('backgrounded_', self
.val
['backgrounded_'])
319 yield ('widget_helper_', self
.val
['widget_helper_'])
320 yield ('is_initialized_', self
.val
['is_initialized_'])
321 yield ('browser_context_', typed_ptr(self
.val
['browser_context_']))
322 yield ('sudden_termination_allowed_',
323 self
.val
['sudden_termination_allowed_'])
324 yield ('ignore_input_events_', self
.val
['ignore_input_events_'])
325 yield ('is_guest_', self
.val
['is_guest_'])
326 pp_set
.add_printer('content::RenderProcessHostImpl',
327 '^content::RenderProcessHostImpl$',
328 RenderProcessHostImplPrinter
)
331 gdb
.printing
.register_pretty_printer(gdb
, pp_set
, replace
=_DEBUGGING
)