Blame gobject/gobject_gdb.py

Packit ae235b
import os.path
Packit ae235b
import gdb
Packit ae235b
import glib_gdb
Packit ae235b
import sys
Packit ae235b
Packit ae235b
if sys.version_info[0] >= 3:
Packit ae235b
    long = int
Packit ae235b
else:
Packit ae235b
    import itertools
Packit ae235b
    map = itertools.imap
Packit ae235b
Packit ae235b
# FrameDecorator is new in gdb 7.7, so we adapt to its absence.
Packit ae235b
try:
Packit ae235b
    import gdb.FrameDecorator
Packit ae235b
    HAVE_GDB_FRAMEDECORATOR = True
Packit ae235b
    FrameDecorator = gdb.FrameDecorator.FrameDecorator
Packit ae235b
except ImportError:
Packit ae235b
    HAVE_GDB_FRAMEDECORATOR = False
Packit ae235b
Packit ae235b
# This is not quite right, as local vars may override symname
Packit ae235b
def read_global_var (symname):
Packit ae235b
    return gdb.selected_frame().read_var(symname)
Packit ae235b
Packit ae235b
def g_type_to_name (gtype):
Packit ae235b
    def lookup_fundamental_type (typenode):
Packit ae235b
        if typenode == 0:
Packit ae235b
            return None
Packit ae235b
        val = read_global_var ("static_fundamental_type_nodes")
Packit ae235b
        if val == None:
Packit ae235b
            return None
Packit ae235b
        return val[typenode >> 2].address
Packit ae235b
Packit ae235b
    gtype = long(gtype)
Packit ae235b
    typenode = gtype - gtype % 4
Packit ae235b
    if typenode > (255 << 2):
Packit ae235b
        typenode = gdb.Value(typenode).cast (gdb.lookup_type("TypeNode").pointer())
Packit ae235b
    else:
Packit ae235b
        typenode = lookup_fundamental_type (typenode)
Packit ae235b
    if typenode != None:
Packit ae235b
        return glib_gdb.g_quark_to_string (typenode["qname"])
Packit ae235b
    return None
Packit ae235b
Packit ae235b
def is_g_type_instance (val):
Packit ae235b
    def is_g_type_instance_helper (type):
Packit ae235b
        if str(type) == "GTypeInstance":
Packit ae235b
            return True
Packit ae235b
Packit ae235b
        while type.code == gdb.TYPE_CODE_TYPEDEF:
Packit ae235b
            type = type.target()
Packit ae235b
Packit ae235b
        if type.code != gdb.TYPE_CODE_STRUCT:
Packit ae235b
            return False
Packit ae235b
Packit ae235b
        fields = type.fields()
Packit ae235b
        if len (fields) < 1:
Packit ae235b
            return False
Packit ae235b
Packit ae235b
        first_field = fields[0]
Packit ae235b
        return is_g_type_instance_helper(first_field.type)
Packit ae235b
Packit ae235b
    type = val.type
Packit ae235b
    if type.code != gdb.TYPE_CODE_PTR:
Packit ae235b
        return False
Packit ae235b
    type = type.target()
Packit ae235b
    return is_g_type_instance_helper (type)
Packit ae235b
Packit ae235b
def g_type_name_from_instance (instance):
Packit ae235b
    if long(instance) != 0:
Packit ae235b
        try:
Packit ae235b
            inst = instance.cast (gdb.lookup_type("GTypeInstance").pointer())
Packit ae235b
            klass = inst["g_class"]
Packit ae235b
            gtype = klass["g_type"]
Packit ae235b
            name = g_type_to_name (gtype)
Packit ae235b
            return name
Packit ae235b
        except RuntimeError:
Packit ae235b
            pass
Packit ae235b
    return None
Packit ae235b
Packit ae235b
class GTypePrettyPrinter:
Packit ae235b
    "Prints a GType instance pointer"
Packit ae235b
Packit ae235b
    def __init__ (self, val):
Packit ae235b
        self.val = val
Packit ae235b
Packit ae235b
    def to_string (self):
Packit ae235b
        name = g_type_name_from_instance (self.val)
Packit ae235b
        if name:
Packit ae235b
            return ("0x%x [%s]")% (long(self.val), name)
Packit ae235b
        return  ("0x%x") % (long(self.val))
Packit ae235b
Packit ae235b
def pretty_printer_lookup (val):
Packit ae235b
    if is_g_type_instance (val):
Packit ae235b
        return GTypePrettyPrinter (val)
Packit ae235b
Packit ae235b
    return None
Packit ae235b
Packit ae235b
def get_signal_name (id):
Packit ae235b
    if id == None:
Packit ae235b
        return None
Packit ae235b
    id = long(id)
Packit ae235b
    if id == 0:
Packit ae235b
        return None
Packit ae235b
    val = read_global_var ("g_signal_nodes")
Packit ae235b
    max_s = read_global_var ("g_n_signal_nodes")
Packit ae235b
    max_s = long(max_s)
Packit ae235b
    if id < max_s:
Packit ae235b
        return val[id]["name"].string()
Packit ae235b
    return None
Packit ae235b
Packit ae235b
def frame_name(frame):
Packit ae235b
    return str(frame.function())
Packit ae235b
Packit ae235b
def frame_var(frame, var):
Packit ae235b
    return frame.inferior_frame().read_var(var)
Packit ae235b
Packit ae235b
Packit ae235b
class SignalFrame(FrameDecorator):
Packit ae235b
    def __init__ (self, frames):
Packit ae235b
        FrameDecorator.__init__(self, frames[-1])
Packit ae235b
        self.frame = frames[-1]
Packit ae235b
        self.frames = frames
Packit ae235b
Packit ae235b
    def name (self):
Packit ae235b
        return "signal-emission"
Packit ae235b
Packit ae235b
    def read_var (self, frame, name, array = None):
Packit ae235b
        try:
Packit ae235b
            v = frame_var (frame, name)
Packit ae235b
            if v == None or v.is_optimized_out:
Packit ae235b
                return None
Packit ae235b
            if array != None:
Packit ae235b
                array.append (v)
Packit ae235b
            return v
Packit ae235b
        except ValueError:
Packit ae235b
            return None
Packit ae235b
Packit ae235b
    def read_object (self, frame, name, array = None):
Packit ae235b
        try:
Packit ae235b
            v = frame_var (frame, name)
Packit ae235b
            if v == None or v.is_optimized_out:
Packit ae235b
                return None
Packit ae235b
            v = v.cast (gdb.lookup_type("GObject").pointer())
Packit ae235b
            # Ensure this is a somewhat correct object pointer
Packit ae235b
            if v != None and g_type_name_from_instance (v):
Packit ae235b
                if array != None:
Packit ae235b
                    array.append (v)
Packit ae235b
                return v
Packit ae235b
            return None
Packit ae235b
        except ValueError:
Packit ae235b
            return None
Packit ae235b
Packit ae235b
    def append (self, array, obj):
Packit ae235b
        if obj != None:
Packit ae235b
            array.append (obj)
Packit ae235b
Packit ae235b
    def or_join_array (self, array):
Packit ae235b
        if len(array) == 0:
Packit ae235b
            return "???"
Packit ae235b
        else:
Packit ae235b
            return ' or '.join(set(map(str, array)))
Packit ae235b
Packit ae235b
    def get_detailed_signal_from_frame(self, frame, signal):
Packit ae235b
        detail = self.read_var (frame, "detail")
Packit ae235b
        detail = glib_gdb.g_quark_to_string (detail)
Packit ae235b
        if detail is not None:
Packit ae235b
            return signal + ":" + detail
Packit ae235b
        else:
Packit ae235b
            return detail
Packit ae235b
Packit ae235b
    def function (self):
Packit ae235b
        instances = []
Packit ae235b
        signals = []
Packit ae235b
Packit ae235b
        for frame in self.frames:
Packit ae235b
            name = frame_name(frame)
Packit ae235b
            if name == "signal_emit_unlocked_R":
Packit ae235b
                self.read_object (frame, "instance", instances)
Packit ae235b
                node = self.read_var (frame, "node")
Packit ae235b
                if node:
Packit ae235b
                    signal = node["name"].string()
Packit ae235b
                    signal = self.get_detailed_signal_from_frame(frame, signal)
Packit ae235b
                    self.append(signals, signal)
Packit ae235b
Packit ae235b
            if name == "g_signal_emitv":
Packit ae235b
                instance_and_params = self.read_var (frame, "instance_and_params")
Packit ae235b
                if instance_and_params:
Packit ae235b
                    instance = instance_and_params[0]["v_pointer"].cast (gdb.Type("GObject").pointer())
Packit ae235b
                    self.append (instances, instance)
Packit ae235b
                id = self.read_var (frame, "signal_id")
Packit ae235b
                signal = get_signal_name (id)
Packit ae235b
                if signal:
Packit ae235b
                    signal = self.get_detailed_signal_from_frame(frame, signal)
Packit ae235b
                    self.append (signals, signal)
Packit ae235b
Packit ae235b
            if name == "g_signal_emit_valist" or name == "g_signal_emit":
Packit ae235b
                self.read_object (frame, "instance", instances)
Packit ae235b
                id = self.read_var (frame, "signal_id")
Packit ae235b
                signal = get_signal_name (id)
Packit ae235b
                if signal:
Packit ae235b
                    signal = self.get_detailed_signal_from_frame(frame, signal)
Packit ae235b
                    self.append (signals, signal)
Packit ae235b
Packit ae235b
            if name == "g_signal_emit_by_name":
Packit ae235b
                self.read_object (frame, "instance", instances)
Packit ae235b
                self.read_var (frame, "detailed_signal", signals)
Packit ae235b
                break
Packit ae235b
Packit ae235b
        instance = self.or_join_array (instances)
Packit ae235b
        signal = self.or_join_array (signals)
Packit ae235b
Packit ae235b
        return "<emit signal %s on instance %s>" %  (signal, instance)
Packit ae235b
Packit ae235b
    def elided (self):
Packit ae235b
        return self.frames[0:-1]
Packit ae235b
Packit ae235b
    def describe (self, stream, full):
Packit ae235b
        stream.write (" " + self.function () + "\n")
Packit ae235b
Packit ae235b
class GFrameDecorator:
Packit ae235b
    def __init__ (self, iter):
Packit ae235b
        self.queue = []
Packit ae235b
        self.iter = iter
Packit ae235b
Packit ae235b
    def __iter__ (self):
Packit ae235b
        return self
Packit ae235b
Packit ae235b
    def fill (self):
Packit ae235b
        while len(self.queue) <= 8:
Packit ae235b
            try:
Packit ae235b
                f = next(self.iter)
Packit ae235b
                self.queue.append (f)
Packit ae235b
            except StopIteration:
Packit ae235b
                return
Packit ae235b
Packit ae235b
    def find_signal_emission (self):
Packit ae235b
        for i in range (min (len(self.queue), 3)):
Packit ae235b
            if frame_name(self.queue[i]) == "signal_emit_unlocked_R":
Packit ae235b
                return i
Packit ae235b
        return -1
Packit ae235b
Packit ae235b
    def next (self):
Packit ae235b
        # Ensure we have enough frames for a full signal emission
Packit ae235b
        self.fill()
Packit ae235b
Packit ae235b
        # Are we at the end?
Packit ae235b
        if len(self.queue) == 0:
Packit ae235b
            raise StopIteration
Packit ae235b
Packit ae235b
        emission = self.find_signal_emission ()
Packit ae235b
        if emission > 0:
Packit ae235b
            start = emission
Packit ae235b
            while True:
Packit ae235b
                if start == 0:
Packit ae235b
                    break
Packit ae235b
                prev_name = frame_name(self.queue[start-1])
Packit ae235b
                if prev_name.find("_marshal_") >= 0 or prev_name == "g_closure_invoke":
Packit ae235b
                    start = start - 1
Packit ae235b
                else:
Packit ae235b
                    break
Packit ae235b
            end = emission + 1
Packit ae235b
            while end < len(self.queue):
Packit ae235b
                if frame_name(self.queue[end]) in ["g_signal_emitv",
Packit ae235b
                                                   "g_signal_emit_valist",
Packit ae235b
                                                   "g_signal_emit",
Packit ae235b
                                                   "g_signal_emit_by_name",
Packit ae235b
                                                   "_g_closure_invoke_va"]:
Packit ae235b
                    end = end + 1
Packit ae235b
                else:
Packit ae235b
                    break
Packit ae235b
Packit ae235b
            signal_frames = self.queue[start:end]
Packit ae235b
            new_frames = [SignalFrame(signal_frames)]
Packit ae235b
            self.queue[start:end] = new_frames
Packit ae235b
Packit ae235b
        return self.queue.pop(0)
Packit ae235b
Packit ae235b
    def __next__ (self):
Packit ae235b
        return self.next()
Packit ae235b
Packit ae235b
class GFrameFilter(object):
Packit ae235b
    name = 'glib'
Packit ae235b
    enabled = True
Packit ae235b
    priority = 100
Packit ae235b
Packit ae235b
    def filter(self, iterator):
Packit ae235b
        return GFrameDecorator(iterator)
Packit ae235b
Packit ae235b
def register (obj):
Packit ae235b
    if obj == None:
Packit ae235b
        obj = gdb
Packit ae235b
Packit ae235b
    if HAVE_GDB_FRAMEDECORATOR:
Packit ae235b
        filter = GFrameFilter()
Packit ae235b
        obj.frame_filters[filter.name] = filter
Packit ae235b
    obj.pretty_printers.append(pretty_printer_lookup)