glib (2.79.0)

(root)/
share/
glib-2.0/
gdb/
gobject_gdb.py
       1  import gdb
       2  import glib_gdb
       3  import sys
       4  
       5  if sys.version_info[0] >= 3:
       6      long = int
       7  else:
       8      import itertools
       9  
      10      map = itertools.imap
      11  
      12  # FrameDecorator is new in gdb 7.7, so we adapt to its absence.
      13  try:
      14      import gdb.FrameDecorator
      15  
      16      HAVE_GDB_FRAMEDECORATOR = True
      17      FrameDecorator = gdb.FrameDecorator.FrameDecorator
      18  except ImportError:
      19      HAVE_GDB_FRAMEDECORATOR = False
      20  
      21  
      22  # This is not quite right, as local vars may override symname
      23  def read_global_var(symname):
      24      return gdb.selected_frame().read_var(symname)
      25  
      26  
      27  def g_type_to_typenode(gtype):
      28      def lookup_fundamental_type(typenode):
      29          if typenode == 0:
      30              return None
      31          val = read_global_var("static_fundamental_type_nodes")
      32          if val is None:
      33              return None
      34          return val[typenode >> 2].address
      35  
      36      gtype = long(gtype)
      37      typenode = gtype - gtype % 4
      38      if typenode > (255 << 2):
      39          typenode = gdb.Value(typenode).cast(gdb.lookup_type("TypeNode").pointer())
      40      else:
      41          typenode = lookup_fundamental_type(typenode)
      42      return typenode
      43  
      44  
      45  def g_type_to_name(gtype):
      46      typenode = g_type_to_typenode(gtype)
      47      if typenode is not None:
      48          return glib_gdb.g_quark_to_string(typenode["qname"])
      49      return None
      50  
      51  
      52  def is_g_type_instance(val):
      53      def is_g_type_instance_helper(type):
      54          if str(type) == "GTypeInstance":
      55              return True
      56  
      57          while type.code == gdb.TYPE_CODE_TYPEDEF:
      58              type = type.target()
      59  
      60          if type.code != gdb.TYPE_CODE_STRUCT:
      61              return False
      62  
      63          fields = type.fields()
      64          if len(fields) < 1:
      65              return False
      66  
      67          first_field = fields[0]
      68          return is_g_type_instance_helper(first_field.type)
      69  
      70      type = val.type
      71      if type.code != gdb.TYPE_CODE_PTR:
      72          return False
      73      type = type.target()
      74      return is_g_type_instance_helper(type)
      75  
      76  
      77  def g_type_name_from_instance(instance):
      78      if long(instance) != 0:
      79          try:
      80              inst = instance.cast(gdb.lookup_type("GTypeInstance").pointer())
      81              klass = inst["g_class"]
      82              gtype = klass["g_type"]
      83              name = g_type_to_name(gtype)
      84              return name
      85          except RuntimeError:
      86              pass
      87      return None
      88  
      89  
      90  class ESC[4;38;5;81mGTypePrettyPrinter:
      91      "Prints a GType instance pointer"
      92  
      93      def __init__(self, val):
      94          self.val = val
      95  
      96      def to_string(self):
      97          name = g_type_name_from_instance(self.val)
      98          if name:
      99              return ("0x%x [%s]") % (long(self.val), name)
     100          return ("0x%x") % (long(self.val))
     101  
     102  
     103  def is_g_type_class_instance(val):
     104      type = val.type
     105      if type.code != gdb.TYPE_CODE_PTR:
     106          return False
     107      return str(type.target()) == "GTypeClass"
     108  
     109  
     110  class ESC[4;38;5;81mGTypeHandlePrettyPrinter:
     111      "Prints a GType instance"
     112  
     113      def __init__(self, val, hint=""):
     114          self.val = val
     115          self.hint = hint
     116  
     117      def to_string(self):
     118          typenode = g_type_to_typenode(self.val)
     119          if typenode is not None:
     120              name = glib_gdb.g_quark_to_string(typenode["qname"])
     121              s = ("0x%x [%s%s") % (long(self.val), self.hint, name)
     122              for i in range(1, int(typenode["n_supers"])):
     123                  node = g_type_to_typenode(typenode["supers"][i])
     124                  if node:
     125                      name = glib_gdb.g_quark_to_string(node["qname"])
     126                  else:
     127                      name = "???"
     128                  s += "/" + name
     129              return s + "]"
     130          else:
     131              return ("0x%x") % (long(self.val))
     132  
     133  
     134  def pretty_printer_lookup(val):
     135      if is_g_type_instance(val):
     136          return GTypePrettyPrinter(val)
     137      if str(val.type) == "GType":
     138          return GTypeHandlePrettyPrinter(val)
     139      if is_g_type_class_instance(val):
     140          return GTypeHandlePrettyPrinter(val["g_type"], "g_type: ")
     141  
     142      return None
     143  
     144  
     145  def get_signal_name(id):
     146      if id is None:
     147          return None
     148      id = long(id)
     149      if id == 0:
     150          return None
     151  
     152      try:
     153          val = read_global_var("g_signal_nodes")
     154          max_s = read_global_var("g_n_signal_nodes")
     155          max_s = long(max_s)
     156          if id < max_s:
     157              return val[id]["name"].string()
     158      except gdb.error:
     159          return None
     160  
     161      return None
     162  
     163  
     164  def frame_name(frame):
     165      return str(frame.function())
     166  
     167  
     168  def frame_var(frame, var):
     169      return frame.inferior_frame().read_var(var)
     170  
     171  
     172  class ESC[4;38;5;81mSignalFrame(ESC[4;38;5;149mFrameDecorator):
     173      def __init__(self, frames):
     174          FrameDecorator.__init__(self, frames[-1])
     175          self.frame = frames[-1]
     176          self.frames = frames
     177  
     178      def name(self):
     179          return "signal-emission"
     180  
     181      def read_var(self, frame, name, array=None):
     182          try:
     183              v = frame_var(frame, name)
     184              if v is None or v.is_optimized_out:
     185                  return None
     186              if array is not None:
     187                  array.append(v)
     188              return v
     189          except ValueError:
     190              return None
     191  
     192      def read_object(self, frame, name, array=None):
     193          try:
     194              v = frame_var(frame, name)
     195              if v is None or v.is_optimized_out:
     196                  return None
     197              v = v.cast(gdb.lookup_type("GObject").pointer())
     198              # Ensure this is a somewhat correct object pointer
     199              if v is not None and g_type_name_from_instance(v):
     200                  if array is not None:
     201                      array.append(v)
     202                  return v
     203              return None
     204          except ValueError:
     205              return None
     206  
     207      def append(self, array, obj):
     208          if obj is not None:
     209              array.append(obj)
     210  
     211      def or_join_array(self, array):
     212          if len(array) == 0:
     213              return "???"
     214          else:
     215              return " or ".join(set(map(str, array)))
     216  
     217      def get_detailed_signal_from_frame(self, frame, signal):
     218          detail = self.read_var(frame, "detail")
     219          detail = glib_gdb.g_quark_to_string(detail)
     220          if detail is not None:
     221              return signal + ":" + detail
     222          else:
     223              return signal
     224  
     225      def function(self):
     226          instances = []
     227          signals = []
     228  
     229          for frame in self.frames:
     230              name = frame_name(frame)
     231              if name == "signal_emit_unlocked_R":
     232                  self.read_object(frame, "instance", instances)
     233                  node = self.read_var(frame, "node")
     234                  if node:
     235                      signal = node["name"].string()
     236                      signal = self.get_detailed_signal_from_frame(frame, signal)
     237                      self.append(signals, signal)
     238  
     239              if name == "g_signal_emitv":
     240                  instance_and_params = self.read_var(frame, "instance_and_params")
     241                  if instance_and_params:
     242                      instance = instance_and_params[0]["v_pointer"].cast(
     243                          gdb.Type("GObject").pointer()
     244                      )
     245                      self.append(instances, instance)
     246                  id = self.read_var(frame, "signal_id")
     247                  signal = get_signal_name(id)
     248                  if signal:
     249                      signal = self.get_detailed_signal_from_frame(frame, signal)
     250                      self.append(signals, signal)
     251  
     252              if name == "g_signal_emit_valist" or name == "g_signal_emit":
     253                  self.read_object(frame, "instance", instances)
     254                  id = self.read_var(frame, "signal_id")
     255                  signal = get_signal_name(id)
     256                  if signal:
     257                      signal = self.get_detailed_signal_from_frame(frame, signal)
     258                      self.append(signals, signal)
     259  
     260              if name == "g_signal_emit_by_name":
     261                  self.read_object(frame, "instance", instances)
     262                  self.read_var(frame, "detailed_signal", signals)
     263                  break
     264  
     265          instance = self.or_join_array(instances)
     266          signal = self.or_join_array(signals)
     267  
     268          return "<emit signal '%s' on instance %s>" % (signal, instance)
     269  
     270      def elided(self):
     271          return self.frames[0:-1]
     272  
     273      def describe(self, stream, full):
     274          stream.write(" " + self.function() + "\n")
     275  
     276  
     277  class ESC[4;38;5;81mGFrameDecorator:
     278      def __init__(self, iter):
     279          self.queue = []
     280          self.iter = iter
     281  
     282      def __iter__(self):
     283          return self
     284  
     285      def fill(self):
     286          while len(self.queue) <= 8:
     287              try:
     288                  f = next(self.iter)
     289                  self.queue.append(f)
     290              except StopIteration:
     291                  return
     292  
     293      def find_signal_emission(self):
     294          for i in range(min(len(self.queue), 3)):
     295              name = frame_name(self.queue[i])
     296              if name == "signal_emit_unlocked_R" or name == "_g_closure_invoke_va":
     297                  return i
     298          return -1
     299  
     300      def next(self):
     301          # Ensure we have enough frames for a full signal emission
     302          self.fill()
     303  
     304          # Are we at the end?
     305          if len(self.queue) == 0:
     306              raise StopIteration
     307  
     308          emission = self.find_signal_emission()
     309          if emission > 0:
     310              start = emission
     311              while True:
     312                  if start == 0:
     313                      break
     314                  prev_name = frame_name(self.queue[start - 1])
     315                  if prev_name.find("_marshal") >= 0 or prev_name == "g_closure_invoke":
     316                      start = start - 1
     317                  else:
     318                      break
     319              end = emission + 1
     320              while end < len(self.queue):
     321                  if frame_name(self.queue[end]) in [
     322                      "g_signal_emitv",
     323                      "g_signal_emit_valist",
     324                      "g_signal_emit",
     325                      "g_signal_emit_by_name",
     326                      "signal_emitv_unlocked",
     327                      "signal_emit_valist_unlocked",
     328                  ]:
     329                      end = end + 1
     330                  else:
     331                      break
     332  
     333              signal_frames = self.queue[start:end]
     334              new_frames = [SignalFrame(signal_frames)]
     335              self.queue[start:end] = new_frames
     336  
     337          return self.queue.pop(0)
     338  
     339      def __next__(self):
     340          return self.next()
     341  
     342  
     343  class ESC[4;38;5;81mGFrameFilter(ESC[4;38;5;149mobject):
     344      name = "glib"
     345      enabled = True
     346      priority = 100
     347  
     348      def filter(self, iterator):
     349          return GFrameDecorator(iterator)
     350  
     351  
     352  def register(obj):
     353      if obj is None:
     354          obj = gdb
     355  
     356      if HAVE_GDB_FRAMEDECORATOR:
     357          filter = GFrameFilter()
     358          obj.frame_filters[filter.name] = filter
     359      obj.pretty_printers.append(pretty_printer_lookup)