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