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.
26 # When debugging this module, set the below variable to True, and then use
27 # (gdb) python del sys.modules['gdb_chrome']
28 # (gdb) python import gdb_chrome
33 pp_set
= gdb
.printing
.RegexpCollectionPrettyPrinter("chromium")
37 """Prints a pointer along with its exact type.
39 By default, gdb would print just the address, which takes more
42 # Returning this as a cast expression surrounded by parentheses
43 # makes it easier to cut+paste inside of gdb.
44 return '((%s)%s)' % (ptr
.dynamic_type
, ptr
)
47 class Printer(object):
48 def __init__(self
, val
):
52 class StringPrinter(Printer
):
53 def display_hint(self
):
57 class String16Printer(StringPrinter
):
59 return webkit
.ustring_to_string(self
.val
['_M_dataplus']['_M_p'])
60 pp_set
.add_printer('string16',
61 '^string16|std::basic_string<(unsigned short|char16).*>$',
65 class GURLPrinter(StringPrinter
):
67 return self
.val
['spec_']
68 pp_set
.add_printer('GURL', '^GURL$', GURLPrinter
)
71 class FilePathPrinter(StringPrinter
):
73 return self
.val
['path_']['_M_dataplus']['_M_p']
74 pp_set
.add_printer('FilePath', '^FilePath$', FilePathPrinter
)
77 class SizePrinter(Printer
):
79 return '%sx%s' % (self
.val
['width_'], self
.val
['height_'])
80 pp_set
.add_printer('gfx::Size', '^gfx::(Size|SizeF|SizeBase<.*>)$', SizePrinter
)
83 class PointPrinter(Printer
):
85 return '%s,%s' % (self
.val
['x_'], self
.val
['y_'])
86 pp_set
.add_printer('gfx::Point', '^gfx::(Point|PointF|PointBase<.*>)$',
90 class RectPrinter(Printer
):
92 return '%s %s' % (self
.val
['origin_'], self
.val
['size_'])
93 pp_set
.add_printer('gfx::Rect', '^gfx::(Rect|RectF|RectBase<.*>)$',
97 class SmartPtrPrinter(Printer
):
99 return '%s%s' % (self
.typename
, typed_ptr(self
.ptr()))
102 class ScopedRefPtrPrinter(SmartPtrPrinter
):
103 typename
= 'scoped_refptr'
105 return self
.val
['ptr_']
106 pp_set
.add_printer('scoped_refptr', '^scoped_refptr<.*>$', ScopedRefPtrPrinter
)
109 class LinkedPtrPrinter(SmartPtrPrinter
):
110 typename
= 'linked_ptr'
112 return self
.val
['value_']
113 pp_set
.add_printer('linked_ptr', '^linked_ptr<.*>$', LinkedPtrPrinter
)
116 class WeakPtrPrinter(SmartPtrPrinter
):
117 typename
= 'base::WeakPtr'
119 flag
= ScopedRefPtrPrinter(self
.val
['ref_']['flag_']).ptr()
120 if flag
and flag
['is_valid_']:
121 return self
.val
['ptr_']
122 return gdb
.Value(0).cast(self
.val
['ptr_'].type)
123 pp_set
.add_printer('base::WeakPtr', '^base::WeakPtr<.*>$', WeakPtrPrinter
)
126 class CallbackPrinter(Printer
):
127 """Callbacks provide no usable information so reduce the space they take."""
130 pp_set
.add_printer('base::Callback', '^base::Callback<.*>$', CallbackPrinter
)
133 class LockPrinter(Printer
):
136 if self
.val
['owned_by_thread_']:
137 return 'Locked by thread %s' % self
.val
['owning_thread_id_']
141 return 'Unknown state'
142 pp_set
.add_printer('base::Lock', '^base::Lock$', LockPrinter
)
145 class TimeDeltaPrinter(object):
146 def __init__(self
, val
):
147 self
._timedelta
= datetime
.timedelta(microseconds
=int(val
['delta_']))
150 return self
._timedelta
153 return str(self
._timedelta
)
154 pp_set
.add_printer('base::TimeDelta', '^base::TimeDelta$', TimeDeltaPrinter
)
157 class TimeTicksPrinter(TimeDeltaPrinter
):
158 def __init__(self
, val
):
159 self
._timedelta
= datetime
.timedelta(microseconds
=int(val
['ticks_']))
160 pp_set
.add_printer('base::TimeTicks', '^base::TimeTicks$', TimeTicksPrinter
)
163 class TimePrinter(object):
164 def __init__(self
, val
):
165 timet_offset
= gdb
.parse_and_eval(
166 'base::Time::kTimeTToMicrosecondsOffset')
167 self
._datetime
= (datetime
.datetime
.fromtimestamp(0) +
168 datetime
.timedelta(microseconds
=
169 int(val
['us_'] - timet_offset
)))
172 return self
._datetime
175 return str(self
._datetime
)
176 pp_set
.add_printer('base::Time', '^base::Time$', TimePrinter
)
179 class NotificationRegistrarPrinter(Printer
):
182 registrations
= self
.val
['registered_']
183 vector_finish
= registrations
['_M_impl']['_M_finish']
184 vector_start
= registrations
['_M_impl']['_M_start']
185 if vector_start
== vector_finish
:
186 return 'Not watching notifications'
187 if vector_start
.dereference().type.sizeof
== 0:
188 # Incomplete type: b/8242773
189 return 'Watching some notifications'
190 return ('Watching %s notifications; '
191 'print %s->registered_ for details') % (
192 int(vector_finish
- vector_start
),
193 typed_ptr(self
.val
.address
))
195 return 'NotificationRegistrar'
196 pp_set
.add_printer('content::NotificationRegistrar',
197 '^content::NotificationRegistrar$',
198 NotificationRegistrarPrinter
)
201 class SiteInstanceImplPrinter(object):
202 def __init__(self
, val
):
203 self
.val
= val
.cast(val
.dynamic_type
)
206 return 'SiteInstanceImpl@%s for %s' % (
207 self
.val
.address
, self
.val
['site_'])
210 yield ('id_', self
.val
['id_'])
211 yield ('has_site_', self
.val
['has_site_'])
212 if self
.val
['browsing_instance_']['ptr_']:
213 yield ('browsing_instance_', self
.val
['browsing_instance_']['ptr_'])
214 if self
.val
['process_']:
215 yield ('process_', typed_ptr(self
.val
['process_']))
216 if self
.val
['render_process_host_factory_']:
217 yield ('render_process_host_factory_',
218 self
.val
['render_process_host_factory_'])
219 pp_set
.add_printer('content::SiteInstanceImpl', '^content::SiteInstanceImpl$',
220 SiteInstanceImplPrinter
)
223 class RenderProcessHostImplPrinter(object):
224 def __init__(self
, val
):
225 self
.val
= val
.cast(val
.dynamic_type
)
230 child_process_launcher_ptr
= (
231 self
.val
['child_process_launcher_']['impl_']['data_']['ptr'])
232 if child_process_launcher_ptr
:
233 context
= (child_process_launcher_ptr
['context_']['ptr_'])
235 pid
= ' PID %s' % str(context
['process_']['process_'])
237 # The definition of the Context type may not be available.
240 return 'RenderProcessHostImpl@%s%s' % (self
.val
.address
, pid
)
243 yield ('id_', self
.val
['id_'])
244 yield ('render_widget_hosts_',
245 self
.val
['render_widget_hosts_']['data_'])
246 yield ('fast_shutdown_started_', self
.val
['fast_shutdown_started_'])
247 yield ('deleting_soon_', self
.val
['deleting_soon_'])
248 yield ('pending_views_', self
.val
['pending_views_'])
249 yield ('visible_widgets_', self
.val
['visible_widgets_'])
250 yield ('backgrounded_', self
.val
['backgrounded_'])
251 yield ('widget_helper_', self
.val
['widget_helper_'])
252 yield ('is_initialized_', self
.val
['is_initialized_'])
253 yield ('browser_context_', typed_ptr(self
.val
['browser_context_']))
254 yield ('sudden_termination_allowed_',
255 self
.val
['sudden_termination_allowed_'])
256 yield ('ignore_input_events_', self
.val
['ignore_input_events_'])
257 yield ('is_guest_', self
.val
['is_guest_'])
258 pp_set
.add_printer('content::RenderProcessHostImpl',
259 '^content::RenderProcessHostImpl$',
260 RenderProcessHostImplPrinter
)
263 gdb
.printing
.register_pretty_printer(gdb
, pp_set
, replace
=_DEBUGGING
)