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/")
14 This module relies on the WebKit gdb module already existing in
18 (gdb) p /r any_variable
19 to print |any_variable| without using any printers.
27 # When debugging this module, set the below variable to True, and then use
28 # (gdb) python del sys.modules['gdb_chrome']
29 # (gdb) python import gdb_chrome
34 pp_set
= gdb
.printing
.RegexpCollectionPrettyPrinter("chromium")
38 """Prints a pointer along with its exact type.
40 By default, gdb would print just the address, which takes more
43 # Returning this as a cast expression surrounded by parentheses
44 # makes it easier to cut+paste inside of gdb.
45 return '((%s)%s)' % (ptr
.dynamic_type
, ptr
)
48 def yield_fields(val
):
49 """Use this in a printer's children() method to print an object's fields.
53 for result in yield_fields(self.val):
57 fields
= val
.type.target().fields()
59 fields
= val
.type.fields()
61 if field
.is_base_class
:
62 yield (field
.name
, val
.cast(gdb
.lookup_type(field
.name
)))
64 yield (field
.name
, val
[field
.name
])
67 class Printer(object):
68 def __init__(self
, val
):
72 class StringPrinter(Printer
):
73 def display_hint(self
):
77 class String16Printer(StringPrinter
):
79 return webkit
.ustring_to_string(self
.val
['_M_dataplus']['_M_p'])
82 '^string16|std::basic_string<(unsigned short|base::char16).*>$',
86 class GURLPrinter(StringPrinter
):
88 return self
.val
['spec_']
89 pp_set
.add_printer('GURL', '^GURL$', GURLPrinter
)
92 class FilePathPrinter(StringPrinter
):
94 return self
.val
['path_']['_M_dataplus']['_M_p']
95 pp_set
.add_printer('FilePath', '^FilePath$', FilePathPrinter
)
98 class SizePrinter(Printer
):
100 return '%sx%s' % (self
.val
['width_'], self
.val
['height_'])
101 pp_set
.add_printer('gfx::Size', '^gfx::(Size|SizeF|SizeBase<.*>)$', SizePrinter
)
104 class PointPrinter(Printer
):
106 return '%s,%s' % (self
.val
['x_'], self
.val
['y_'])
107 pp_set
.add_printer('gfx::Point', '^gfx::(Point|PointF|PointBase<.*>)$',
111 class RectPrinter(Printer
):
113 return '%s %s' % (self
.val
['origin_'], self
.val
['size_'])
114 pp_set
.add_printer('gfx::Rect', '^gfx::(Rect|RectF|RectBase<.*>)$',
118 class SmartPtrPrinter(Printer
):
120 return '%s%s' % (self
.typename
, typed_ptr(self
.ptr()))
123 class ScopedRefPtrPrinter(SmartPtrPrinter
):
124 typename
= 'scoped_refptr'
126 return self
.val
['ptr_']
127 pp_set
.add_printer('scoped_refptr', '^scoped_refptr<.*>$', ScopedRefPtrPrinter
)
130 class LinkedPtrPrinter(SmartPtrPrinter
):
131 typename
= 'linked_ptr'
133 return self
.val
['value_']
134 pp_set
.add_printer('linked_ptr', '^linked_ptr<.*>$', LinkedPtrPrinter
)
137 class WeakPtrPrinter(SmartPtrPrinter
):
138 typename
= 'base::WeakPtr'
140 flag
= ScopedRefPtrPrinter(self
.val
['ref_']['flag_']).ptr()
141 if flag
and flag
['is_valid_']:
142 return self
.val
['ptr_']
143 return gdb
.Value(0).cast(self
.val
['ptr_'].type)
144 pp_set
.add_printer('base::WeakPtr', '^base::WeakPtr<.*>$', WeakPtrPrinter
)
147 class CallbackPrinter(Printer
):
148 """Callbacks provide no usable information so reduce the space they take."""
151 pp_set
.add_printer('base::Callback', '^base::Callback<.*>$', CallbackPrinter
)
154 class LocationPrinter(Printer
):
156 return '%s()@%s:%s' % (self
.val
['function_name_'].string(),
157 self
.val
['file_name_'].string(),
158 self
.val
['line_number_'])
159 pp_set
.add_printer('tracked_objects::Location', '^tracked_objects::Location$',
163 class PendingTaskPrinter(Printer
):
165 return 'From %s' % (self
.val
['posted_from'],)
168 for result
in yield_fields(self
.val
):
169 if result
[0] not in ('task', 'posted_from'):
171 pp_set
.add_printer('base::PendingTask', '^base::PendingTask$',
175 class LockPrinter(Printer
):
178 if self
.val
['owned_by_thread_']:
179 return 'Locked by thread %s' % self
.val
['owning_thread_id_']
183 return 'Unknown state'
184 pp_set
.add_printer('base::Lock', '^base::Lock$', LockPrinter
)
187 class TimeDeltaPrinter(object):
188 def __init__(self
, val
):
189 self
._timedelta
= datetime
.timedelta(microseconds
=int(val
['delta_']))
192 return self
._timedelta
195 return str(self
._timedelta
)
196 pp_set
.add_printer('base::TimeDelta', '^base::TimeDelta$', TimeDeltaPrinter
)
199 class TimeTicksPrinter(TimeDeltaPrinter
):
200 def __init__(self
, val
):
201 self
._timedelta
= datetime
.timedelta(microseconds
=int(val
['ticks_']))
202 pp_set
.add_printer('base::TimeTicks', '^base::TimeTicks$', TimeTicksPrinter
)
205 class TimePrinter(object):
206 def __init__(self
, val
):
207 timet_offset
= gdb
.parse_and_eval(
208 'base::Time::kTimeTToMicrosecondsOffset')
209 self
._datetime
= (datetime
.datetime
.fromtimestamp(0) +
210 datetime
.timedelta(microseconds
=
211 int(val
['us_'] - timet_offset
)))
214 return self
._datetime
217 return str(self
._datetime
)
218 pp_set
.add_printer('base::Time', '^base::Time$', TimePrinter
)
221 class IpcMessagePrinter(Printer
):
223 return self
.val
['header_'].cast(
224 gdb
.lookup_type('IPC::Message::Header').pointer())
227 message_type
= self
.header()['type']
228 return '%s of kind %s line %s' % (
229 self
.val
.dynamic_type
,
230 (message_type
>> 16).cast(gdb
.lookup_type('IPCMessageStart')),
231 message_type
& 0xffff)
234 yield ('header_', self
.header().dereference())
235 yield ('capacity_after_header_', self
.val
['capacity_after_header_'])
236 for field
in self
.val
.type.fields():
237 if field
.is_base_class
:
239 yield (field
.name
, self
.val
[field
.name
])
240 pp_set
.add_printer('IPC::Message', '^IPC::Message$', IpcMessagePrinter
)
243 class NotificationRegistrarPrinter(Printer
):
246 registrations
= self
.val
['registered_']
247 vector_finish
= registrations
['_M_impl']['_M_finish']
248 vector_start
= registrations
['_M_impl']['_M_start']
249 if vector_start
== vector_finish
:
250 return 'Not watching notifications'
251 if vector_start
.dereference().type.sizeof
== 0:
252 # Incomplete type: b/8242773
253 return 'Watching some notifications'
254 return ('Watching %s notifications; '
255 'print %s->registered_ for details') % (
256 int(vector_finish
- vector_start
),
257 typed_ptr(self
.val
.address
))
259 return 'NotificationRegistrar'
260 pp_set
.add_printer('content::NotificationRegistrar',
261 '^content::NotificationRegistrar$',
262 NotificationRegistrarPrinter
)
265 class SiteInstanceImplPrinter(object):
266 def __init__(self
, val
):
267 self
.val
= val
.cast(val
.dynamic_type
)
270 return 'SiteInstanceImpl@%s for %s' % (
271 self
.val
.address
, self
.val
['site_'])
274 yield ('id_', self
.val
['id_'])
275 yield ('has_site_', self
.val
['has_site_'])
276 if self
.val
['browsing_instance_']['ptr_']:
277 yield ('browsing_instance_', self
.val
['browsing_instance_']['ptr_'])
278 if self
.val
['process_']:
279 yield ('process_', typed_ptr(self
.val
['process_']))
280 if self
.val
['render_process_host_factory_']:
281 yield ('render_process_host_factory_',
282 self
.val
['render_process_host_factory_'])
283 pp_set
.add_printer('content::SiteInstanceImpl', '^content::SiteInstanceImpl$',
284 SiteInstanceImplPrinter
)
287 class RenderProcessHostImplPrinter(object):
288 def __init__(self
, val
):
289 self
.val
= val
.cast(val
.dynamic_type
)
294 child_process_launcher_ptr
= (
295 self
.val
['child_process_launcher_']['impl_']['data_']['ptr'])
296 if child_process_launcher_ptr
:
297 context
= (child_process_launcher_ptr
['context_']['ptr_'])
299 pid
= ' PID %s' % str(context
['process_']['process_'])
301 # The definition of the Context type may not be available.
304 return 'RenderProcessHostImpl@%s%s' % (self
.val
.address
, pid
)
307 yield ('id_', self
.val
['id_'])
309 self
.val
['listeners_']['data_'])
310 yield ('worker_ref_count_', self
.val
['worker_ref_count_'])
311 yield ('fast_shutdown_started_', self
.val
['fast_shutdown_started_'])
312 yield ('deleting_soon_', self
.val
['deleting_soon_'])
313 yield ('pending_views_', self
.val
['pending_views_'])
314 yield ('visible_widgets_', self
.val
['visible_widgets_'])
315 yield ('backgrounded_', self
.val
['backgrounded_'])
316 yield ('widget_helper_', self
.val
['widget_helper_'])
317 yield ('is_initialized_', self
.val
['is_initialized_'])
318 yield ('browser_context_', typed_ptr(self
.val
['browser_context_']))
319 yield ('sudden_termination_allowed_',
320 self
.val
['sudden_termination_allowed_'])
321 yield ('ignore_input_events_', self
.val
['ignore_input_events_'])
322 yield ('is_guest_', self
.val
['is_guest_'])
323 pp_set
.add_printer('content::RenderProcessHostImpl',
324 '^content::RenderProcessHostImpl$',
325 RenderProcessHostImplPrinter
)
328 gdb
.printing
.register_pretty_printer(gdb
, pp_set
, replace
=_DEBUGGING
)