Upstream version 7.36.149.0
[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 gdb.printing
25 import webkit
26
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
30 # to reload.
31 _DEBUGGING = False
32
33
34 pp_set = gdb.printing.RegexpCollectionPrettyPrinter("chromium")
35
36
37 def typed_ptr(ptr):
38     """Prints a pointer along with its exact type.
39
40     By default, gdb would print just the address, which takes more
41     steps to interpret.
42     """
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)
46
47
48 def yield_fields(val):
49     """Use this in a printer's children() method to print an object's fields.
50
51     e.g.
52       def children():
53         for result in yield_fields(self.val):
54           yield result
55     """
56     try:
57         fields = val.type.target().fields()
58     except:
59         fields = val.type.fields()
60     for field in fields:
61         if field.is_base_class:
62             yield (field.name, val.cast(gdb.lookup_type(field.name)))
63         else:
64             yield (field.name, val[field.name])
65
66
67 class Printer(object):
68     def __init__(self, val):
69         self.val = val
70
71
72 class StringPrinter(Printer):
73     def display_hint(self):
74         return 'string'
75
76
77 class String16Printer(StringPrinter):
78     def to_string(self):
79         return webkit.ustring_to_string(self.val['_M_dataplus']['_M_p'])
80 pp_set.add_printer(
81     'string16',
82     '^string16|std::basic_string<(unsigned short|base::char16).*>$',
83     String16Printer);
84
85
86 class GURLPrinter(StringPrinter):
87     def to_string(self):
88         return self.val['spec_']
89 pp_set.add_printer('GURL', '^GURL$', GURLPrinter)
90
91
92 class FilePathPrinter(StringPrinter):
93     def to_string(self):
94         return self.val['path_']['_M_dataplus']['_M_p']
95 pp_set.add_printer('FilePath', '^FilePath$', FilePathPrinter)
96
97
98 class SizePrinter(Printer):
99     def to_string(self):
100         return '%sx%s' % (self.val['width_'], self.val['height_'])
101 pp_set.add_printer('gfx::Size', '^gfx::(Size|SizeF|SizeBase<.*>)$', SizePrinter)
102
103
104 class PointPrinter(Printer):
105     def to_string(self):
106         return '%s,%s' % (self.val['x_'], self.val['y_'])
107 pp_set.add_printer('gfx::Point', '^gfx::(Point|PointF|PointBase<.*>)$',
108                    PointPrinter)
109
110
111 class RectPrinter(Printer):
112     def to_string(self):
113         return '%s %s' % (self.val['origin_'], self.val['size_'])
114 pp_set.add_printer('gfx::Rect', '^gfx::(Rect|RectF|RectBase<.*>)$',
115                    RectPrinter)
116
117
118 class SmartPtrPrinter(Printer):
119     def to_string(self):
120         return '%s%s' % (self.typename, typed_ptr(self.ptr()))
121
122
123 class ScopedRefPtrPrinter(SmartPtrPrinter):
124     typename = 'scoped_refptr'
125     def ptr(self):
126         return self.val['ptr_']
127 pp_set.add_printer('scoped_refptr', '^scoped_refptr<.*>$', ScopedRefPtrPrinter)
128
129
130 class LinkedPtrPrinter(SmartPtrPrinter):
131     typename = 'linked_ptr'
132     def ptr(self):
133         return self.val['value_']
134 pp_set.add_printer('linked_ptr', '^linked_ptr<.*>$', LinkedPtrPrinter)
135
136
137 class WeakPtrPrinter(SmartPtrPrinter):
138     typename = 'base::WeakPtr'
139     def ptr(self):
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)
145
146
147 class CallbackPrinter(Printer):
148     """Callbacks provide no usable information so reduce the space they take."""
149     def to_string(self):
150         return '...'
151 pp_set.add_printer('base::Callback', '^base::Callback<.*>$', CallbackPrinter)
152
153
154 class LocationPrinter(Printer):
155     def to_string(self):
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$',
160                    LocationPrinter)
161
162
163 class PendingTaskPrinter(Printer):
164     def to_string(self):
165         return 'From %s' % (self.val['posted_from'],)
166
167     def children(self):
168         for result in yield_fields(self.val):
169             if result[0] not in ('task', 'posted_from'):
170                 yield result
171 pp_set.add_printer('base::PendingTask', '^base::PendingTask$',
172                    PendingTaskPrinter)
173
174
175 class LockPrinter(Printer):
176     def to_string(self):
177         try:
178             if self.val['owned_by_thread_']:
179                 return 'Locked by thread %s' % self.val['owning_thread_id_']
180             else:
181                 return 'Unlocked'
182         except gdb.error:
183             return 'Unknown state'
184 pp_set.add_printer('base::Lock', '^base::Lock$', LockPrinter)
185
186
187 class TimeDeltaPrinter(object):
188     def __init__(self, val):
189         self._timedelta = datetime.timedelta(microseconds=int(val['delta_']))
190
191     def timedelta(self):
192         return self._timedelta
193
194     def to_string(self):
195         return str(self._timedelta)
196 pp_set.add_printer('base::TimeDelta', '^base::TimeDelta$', TimeDeltaPrinter)
197
198
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)
203
204
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)))
212
213     def datetime(self):
214         return self._datetime
215
216     def to_string(self):
217         return str(self._datetime)
218 pp_set.add_printer('base::Time', '^base::Time$', TimePrinter)
219
220
221 class IpcMessagePrinter(Printer):
222     def header(self):
223         return self.val['header_'].cast(
224             gdb.lookup_type('IPC::Message::Header').pointer())
225
226     def to_string(self):
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)
232
233     def children(self):
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:
238                 continue
239             yield (field.name, self.val[field.name])
240 pp_set.add_printer('IPC::Message', '^IPC::Message$', IpcMessagePrinter)
241
242
243 class NotificationRegistrarPrinter(Printer):
244     def to_string(self):
245         try:
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))
258         except gdb.error:
259             return 'NotificationRegistrar'
260 pp_set.add_printer('content::NotificationRegistrar',
261                    '^content::NotificationRegistrar$',
262                    NotificationRegistrarPrinter)
263
264
265 class SiteInstanceImplPrinter(object):
266     def __init__(self, val):
267         self.val = val.cast(val.dynamic_type)
268
269     def to_string(self):
270         return 'SiteInstanceImpl@%s for %s' % (
271             self.val.address, self.val['site_'])
272
273     def children(self):
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)
285
286
287 class RenderProcessHostImplPrinter(object):
288     def __init__(self, val):
289         self.val = val.cast(val.dynamic_type)
290
291     def to_string(self):
292         pid = ''
293         try:
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_'])
298                 if context:
299                     pid = ' PID %s' % str(context['process_']['process_'])
300         except gdb.error:
301             # The definition of the Context type may not be available.
302             # b/8242773
303             pass
304         return 'RenderProcessHostImpl@%s%s' % (self.val.address, pid)
305
306     def children(self):
307         yield ('id_', self.val['id_'])
308         yield ('listeners_',
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)
326
327
328 gdb.printing.register_pretty_printer(gdb, pp_set, replace=_DEBUGGING)