Fix dereference of NULL host in VersionUpdater::Create.
[chromium-blink-merge.git] / tools / gdb / gdb_chrome.py
blob2ba7ce8b1daff0ee6496f24c7abb9bcdb2270915
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:
8 python
9 import sys
10 sys.path.insert(0, "/path/to/tools/gdb/")
11 import gdb_chrome
12 end
14 Use
15 (gdb) p /r any_variable
16 to print |any_variable| without using any printers.
17 """
19 import datetime
20 import gdb
21 import gdb.printing
22 import os
23 import sys
25 sys.path.insert(0, os.path.join(
26 os.path.dirname(os.path.abspath(__file__)),
27 '..', '..', 'third_party', 'WebKit', 'Tools', 'gdb'))
28 try:
29 import webkit
30 finally:
31 sys.path.pop(0)
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
36 # to reload.
37 _DEBUGGING = False
40 pp_set = gdb.printing.RegexpCollectionPrettyPrinter("chromium")
43 def typed_ptr(ptr):
44 """Prints a pointer along with its exact type.
46 By default, gdb would print just the address, which takes more
47 steps to interpret.
48 """
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.
57 e.g.
58 def children():
59 for result in yield_fields(self.val):
60 yield result
61 """
62 try:
63 fields = val.type.target().fields()
64 except:
65 fields = val.type.fields()
66 for field in fields:
67 if field.is_base_class:
68 yield (field.name, val.cast(gdb.lookup_type(field.name)))
69 else:
70 yield (field.name, val[field.name])
73 class Printer(object):
74 def __init__(self, val):
75 self.val = val
78 class StringPrinter(Printer):
79 def display_hint(self):
80 return 'string'
83 class String16Printer(StringPrinter):
84 def to_string(self):
85 return webkit.ustring_to_string(self.val['_M_dataplus']['_M_p'])
86 pp_set.add_printer(
87 'string16',
88 '^string16|std::basic_string<(unsigned short|base::char16).*>$',
89 String16Printer);
92 class GURLPrinter(StringPrinter):
93 def to_string(self):
94 return self.val['spec_']
95 pp_set.add_printer('GURL', '^GURL$', GURLPrinter)
98 class FilePathPrinter(StringPrinter):
99 def to_string(self):
100 return self.val['path_']['_M_dataplus']['_M_p']
101 pp_set.add_printer('FilePath', '^FilePath$', FilePathPrinter)
104 class SizePrinter(Printer):
105 def to_string(self):
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):
111 def to_string(self):
112 return '%s,%s' % (self.val['x_'], self.val['y_'])
113 pp_set.add_printer('gfx::Point', '^gfx::(Point|PointF|PointBase<.*>)$',
114 PointPrinter)
117 class RectPrinter(Printer):
118 def to_string(self):
119 return '%s %s' % (self.val['origin_'], self.val['size_'])
120 pp_set.add_printer('gfx::Rect', '^gfx::(Rect|RectF|RectBase<.*>)$',
121 RectPrinter)
124 class SmartPtrPrinter(Printer):
125 def to_string(self):
126 return '%s%s' % (self.typename, typed_ptr(self.ptr()))
129 class ScopedRefPtrPrinter(SmartPtrPrinter):
130 typename = 'scoped_refptr'
131 def ptr(self):
132 return self.val['ptr_']
133 pp_set.add_printer('scoped_refptr', '^scoped_refptr<.*>$', ScopedRefPtrPrinter)
136 class LinkedPtrPrinter(SmartPtrPrinter):
137 typename = 'linked_ptr'
138 def ptr(self):
139 return self.val['value_']
140 pp_set.add_printer('linked_ptr', '^linked_ptr<.*>$', LinkedPtrPrinter)
143 class WeakPtrPrinter(SmartPtrPrinter):
144 typename = 'base::WeakPtr'
145 def ptr(self):
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."""
155 def to_string(self):
156 return '...'
157 pp_set.add_printer('base::Callback', '^base::Callback<.*>$', CallbackPrinter)
160 class LocationPrinter(Printer):
161 def to_string(self):
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$',
166 LocationPrinter)
169 class PendingTaskPrinter(Printer):
170 def to_string(self):
171 return 'From %s' % (self.val['posted_from'],)
173 def children(self):
174 for result in yield_fields(self.val):
175 if result[0] not in ('task', 'posted_from'):
176 yield result
177 pp_set.add_printer('base::PendingTask', '^base::PendingTask$',
178 PendingTaskPrinter)
181 class LockPrinter(Printer):
182 def to_string(self):
183 try:
184 if self.val['owned_by_thread_']:
185 return 'Locked by thread %s' % self.val['owning_thread_id_']
186 else:
187 return 'Unlocked'
188 except gdb.error:
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_']))
197 def timedelta(self):
198 return self._timedelta
200 def to_string(self):
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)))
219 def datetime(self):
220 return self._datetime
222 def to_string(self):
223 return str(self._datetime)
224 pp_set.add_printer('base::Time', '^base::Time$', TimePrinter)
227 class IpcMessagePrinter(Printer):
228 def header(self):
229 return self.val['header_'].cast(
230 gdb.lookup_type('IPC::Message::Header').pointer())
232 def to_string(self):
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)
239 def children(self):
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:
244 continue
245 yield (field.name, self.val[field.name])
246 pp_set.add_printer('IPC::Message', '^IPC::Message$', IpcMessagePrinter)
249 class NotificationRegistrarPrinter(Printer):
250 def to_string(self):
251 try:
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))
264 except gdb.error:
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)
275 def to_string(self):
276 return 'SiteInstanceImpl@%s for %s' % (
277 self.val.address, self.val['site_'])
279 def children(self):
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)
294 def to_string(self):
295 pid = ''
296 try:
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_'])
301 if context:
302 pid = ' PID %s' % str(context['process_']['process_'])
303 except gdb.error:
304 # The definition of the Context type may not be available.
305 # b/8242773
306 pass
307 return 'RenderProcessHostImpl@%s%s' % (self.val.address, pid)
309 def children(self):
310 yield ('id_', self.val['id_'])
311 yield ('listeners_',
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)