- add sources.
[platform/framework/web/crosswalk.git] / src / tools / gdb / gdb_chrome.py
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.
4
5 """GDB support for Chrome types.
6
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
13
14 This module relies on the WebKit gdb module already existing in
15 your Python path.
16
17 Use
18   (gdb) p /r any_variable
19 to print |any_variable| without using any printers.
20 """
21
22 import datetime
23 import gdb
24 import webkit
25
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
29 # to reload.
30 _DEBUGGING = False
31
32
33 pp_set = gdb.printing.RegexpCollectionPrettyPrinter("chromium")
34
35
36 def typed_ptr(ptr):
37     """Prints a pointer along with its exact type.
38
39     By default, gdb would print just the address, which takes more
40     steps to interpret.
41     """
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)
45
46
47 class Printer(object):
48     def __init__(self, val):
49         self.val = val
50
51
52 class StringPrinter(Printer):
53     def display_hint(self):
54         return 'string'
55
56
57 class String16Printer(StringPrinter):
58     def to_string(self):
59         return webkit.ustring_to_string(self.val['_M_dataplus']['_M_p'])
60 pp_set.add_printer(
61     'string16',
62     '^string16|std::basic_string<(unsigned short|char16|base::char16).*>$',
63     String16Printer);
64
65
66 class GURLPrinter(StringPrinter):
67     def to_string(self):
68         return self.val['spec_']
69 pp_set.add_printer('GURL', '^GURL$', GURLPrinter)
70
71
72 class FilePathPrinter(StringPrinter):
73     def to_string(self):
74         return self.val['path_']['_M_dataplus']['_M_p']
75 pp_set.add_printer('FilePath', '^FilePath$', FilePathPrinter)
76
77
78 class SizePrinter(Printer):
79     def to_string(self):
80         return '%sx%s' % (self.val['width_'], self.val['height_'])
81 pp_set.add_printer('gfx::Size', '^gfx::(Size|SizeF|SizeBase<.*>)$', SizePrinter)
82
83
84 class PointPrinter(Printer):
85     def to_string(self):
86         return '%s,%s' % (self.val['x_'], self.val['y_'])
87 pp_set.add_printer('gfx::Point', '^gfx::(Point|PointF|PointBase<.*>)$',
88                    PointPrinter)
89
90
91 class RectPrinter(Printer):
92     def to_string(self):
93         return '%s %s' % (self.val['origin_'], self.val['size_'])
94 pp_set.add_printer('gfx::Rect', '^gfx::(Rect|RectF|RectBase<.*>)$',
95                    RectPrinter)
96
97
98 class SmartPtrPrinter(Printer):
99     def to_string(self):
100         return '%s%s' % (self.typename, typed_ptr(self.ptr()))
101
102
103 class ScopedRefPtrPrinter(SmartPtrPrinter):
104     typename = 'scoped_refptr'
105     def ptr(self):
106         return self.val['ptr_']
107 pp_set.add_printer('scoped_refptr', '^scoped_refptr<.*>$', ScopedRefPtrPrinter)
108
109
110 class LinkedPtrPrinter(SmartPtrPrinter):
111     typename = 'linked_ptr'
112     def ptr(self):
113         return self.val['value_']
114 pp_set.add_printer('linked_ptr', '^linked_ptr<.*>$', LinkedPtrPrinter)
115
116
117 class WeakPtrPrinter(SmartPtrPrinter):
118     typename = 'base::WeakPtr'
119     def ptr(self):
120         flag = ScopedRefPtrPrinter(self.val['ref_']['flag_']).ptr()
121         if flag and flag['is_valid_']:
122             return self.val['ptr_']
123         return gdb.Value(0).cast(self.val['ptr_'].type)
124 pp_set.add_printer('base::WeakPtr', '^base::WeakPtr<.*>$', WeakPtrPrinter)
125
126
127 class CallbackPrinter(Printer):
128     """Callbacks provide no usable information so reduce the space they take."""
129     def to_string(self):
130         return '...'
131 pp_set.add_printer('base::Callback', '^base::Callback<.*>$', CallbackPrinter)
132
133
134 class LocationPrinter(Printer):
135     def to_string(self):
136         return '%s()@%s:%s' % (self.val['function_name_'].string(),
137                                self.val['file_name_'].string(),
138                                self.val['line_number_'])
139 pp_set.add_printer('tracked_objects::Location', '^tracked_objects::Location$',
140                    LocationPrinter)
141
142
143 class LockPrinter(Printer):
144     def to_string(self):
145         try:
146             if self.val['owned_by_thread_']:
147                 return 'Locked by thread %s' % self.val['owning_thread_id_']
148             else:
149                 return 'Unlocked'
150         except gdb.error:
151             return 'Unknown state'
152 pp_set.add_printer('base::Lock', '^base::Lock$', LockPrinter)
153
154
155 class TimeDeltaPrinter(object):
156     def __init__(self, val):
157         self._timedelta = datetime.timedelta(microseconds=int(val['delta_']))
158
159     def timedelta(self):
160         return self._timedelta
161
162     def to_string(self):
163         return str(self._timedelta)
164 pp_set.add_printer('base::TimeDelta', '^base::TimeDelta$', TimeDeltaPrinter)
165
166
167 class TimeTicksPrinter(TimeDeltaPrinter):
168     def __init__(self, val):
169         self._timedelta = datetime.timedelta(microseconds=int(val['ticks_']))
170 pp_set.add_printer('base::TimeTicks', '^base::TimeTicks$', TimeTicksPrinter)
171
172
173 class TimePrinter(object):
174     def __init__(self, val):
175         timet_offset = gdb.parse_and_eval(
176             'base::Time::kTimeTToMicrosecondsOffset')
177         self._datetime = (datetime.datetime.fromtimestamp(0) +
178                           datetime.timedelta(microseconds=
179                                              int(val['us_'] - timet_offset)))
180
181     def datetime(self):
182         return self._datetime
183
184     def to_string(self):
185         return str(self._datetime)
186 pp_set.add_printer('base::Time', '^base::Time$', TimePrinter)
187
188
189 class IpcMessagePrinter(Printer):
190     def header(self):
191         return self.val['header_'].cast(
192             gdb.lookup_type('IPC::Message::Header').pointer())
193
194     def to_string(self):
195         message_type = self.header()['type']
196         return '%s of kind %s line %s' % (
197             self.val.dynamic_type,
198             (message_type >> 16).cast(gdb.lookup_type('IPCMessageStart')),
199             message_type & 0xffff)
200
201     def children(self):
202         yield ('header_', self.header().dereference())
203         yield ('capacity_', self.val['capacity_'])
204         yield ('variable_buffer_offset_', self.val['variable_buffer_offset_'])
205         for field in self.val.type.fields():
206             if field.is_base_class:
207                 continue
208             yield (field.name, self.val[field.name])
209 pp_set.add_printer('IPC::Message', '^IPC::Message$', IpcMessagePrinter)
210
211
212 class NotificationRegistrarPrinter(Printer):
213     def to_string(self):
214         try:
215             registrations = self.val['registered_']
216             vector_finish = registrations['_M_impl']['_M_finish']
217             vector_start = registrations['_M_impl']['_M_start']
218             if vector_start == vector_finish:
219                 return 'Not watching notifications'
220             if vector_start.dereference().type.sizeof == 0:
221                 # Incomplete type: b/8242773
222                 return 'Watching some notifications'
223             return ('Watching %s notifications; '
224                     'print %s->registered_ for details') % (
225                         int(vector_finish - vector_start),
226                         typed_ptr(self.val.address))
227         except gdb.error:
228             return 'NotificationRegistrar'
229 pp_set.add_printer('content::NotificationRegistrar',
230                    '^content::NotificationRegistrar$',
231                    NotificationRegistrarPrinter)
232
233
234 class SiteInstanceImplPrinter(object):
235     def __init__(self, val):
236         self.val = val.cast(val.dynamic_type)
237
238     def to_string(self):
239         return 'SiteInstanceImpl@%s for %s' % (
240             self.val.address, self.val['site_'])
241
242     def children(self):
243         yield ('id_', self.val['id_'])
244         yield ('has_site_', self.val['has_site_'])
245         if self.val['browsing_instance_']['ptr_']:
246             yield ('browsing_instance_', self.val['browsing_instance_']['ptr_'])
247         if self.val['process_']:
248             yield ('process_', typed_ptr(self.val['process_']))
249         if self.val['render_process_host_factory_']:
250             yield ('render_process_host_factory_',
251                    self.val['render_process_host_factory_'])
252 pp_set.add_printer('content::SiteInstanceImpl', '^content::SiteInstanceImpl$',
253                    SiteInstanceImplPrinter)
254
255
256 class RenderProcessHostImplPrinter(object):
257     def __init__(self, val):
258         self.val = val.cast(val.dynamic_type)
259
260     def to_string(self):
261         pid = ''
262         try:
263             child_process_launcher_ptr = (
264                 self.val['child_process_launcher_']['impl_']['data_']['ptr'])
265             if child_process_launcher_ptr:
266                 context = (child_process_launcher_ptr['context_']['ptr_'])
267                 if context:
268                     pid = ' PID %s' % str(context['process_']['process_'])
269         except gdb.error:
270             # The definition of the Context type may not be available.
271             # b/8242773
272             pass
273         return 'RenderProcessHostImpl@%s%s' % (self.val.address, pid)
274
275     def children(self):
276         yield ('id_', self.val['id_'])
277         yield ('render_widget_hosts_',
278                self.val['render_widget_hosts_']['data_'])
279         yield ('fast_shutdown_started_', self.val['fast_shutdown_started_'])
280         yield ('deleting_soon_', self.val['deleting_soon_'])
281         yield ('pending_views_', self.val['pending_views_'])
282         yield ('visible_widgets_', self.val['visible_widgets_'])
283         yield ('backgrounded_', self.val['backgrounded_'])
284         yield ('widget_helper_', self.val['widget_helper_'])
285         yield ('is_initialized_', self.val['is_initialized_'])
286         yield ('browser_context_', typed_ptr(self.val['browser_context_']))
287         yield ('sudden_termination_allowed_',
288                self.val['sudden_termination_allowed_'])
289         yield ('ignore_input_events_', self.val['ignore_input_events_'])
290         yield ('is_guest_', self.val['is_guest_'])
291 pp_set.add_printer('content::RenderProcessHostImpl',
292                    '^content::RenderProcessHostImpl$',
293                    RenderProcessHostImplPrinter)
294
295
296 gdb.printing.register_pretty_printer(gdb, pp_set, replace=_DEBUGGING)