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