Increase the timeout for some GLib tests
[glib.git] / gobject / gobject_gdb.py
blob8c302203179b0d790ce6b9d8a3a595f38ea8e32c
1 import os.path
2 import gdb
3 import glib_gdb
4 import sys
6 if sys.version_info[0] >= 3:
7 long = int
8 else:
9 import itertools
10 map = itertools.imap
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
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)
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()
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_gdb.g_quark_to_string (typenode["qname"])
41 return None
43 def is_g_type_instance (val):
44 def is_g_type_instance_helper (type):
45 if str(type) == "GTypeInstance":
46 return True
48 while type.code == gdb.TYPE_CODE_TYPEDEF:
49 type = type.target()
51 if type.code != gdb.TYPE_CODE_STRUCT:
52 return False
54 fields = type.fields()
55 if len (fields) < 1:
56 return False
58 first_field = fields[0]
59 return is_g_type_instance_helper(first_field.type)
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)
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
79 class GTypePrettyPrinter:
80 "Prints a GType instance pointer"
82 def __init__ (self, val):
83 self.val = val
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))
91 def pretty_printer_lookup (val):
92 if is_g_type_instance (val):
93 return GTypePrettyPrinter (val)
95 return None
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
110 def frame_name(frame):
111 return str(frame.function())
113 def frame_var(frame, var):
114 return frame.inferior_frame().read_var(var)
117 class SignalFrame(FrameDecorator):
118 def __init__ (self, frames):
119 FrameDecorator.__init__(self, frames[-1])
120 self.frame = frames[-1]
121 self.frames = frames
123 def name (self):
124 return "signal-emission"
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
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
152 def append (self, array, obj):
153 if obj != None:
154 array.append (obj)
156 def or_join_array (self, array):
157 if len(array) == 0:
158 return "???"
159 else:
160 return ' or '.join(set(map(str, array)))
162 def get_detailed_signal_from_frame(self, frame, signal):
163 detail = self.read_var (frame, "detail")
164 detail = glib_gdb.g_quark_to_string (detail)
165 if detail is not None:
166 return signal + ":" + detail
167 else:
168 return detail
170 def function (self):
171 instances = []
172 signals = []
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)
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)
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)
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
208 instance = self.or_join_array (instances)
209 signal = self.or_join_array (signals)
211 return "<emit signal %s on instance %s>" % (signal, instance)
213 def elided (self):
214 return self.frames[0:-1]
216 def describe (self, stream, full):
217 stream.write (" " + self.function () + "\n")
219 class GFrameDecorator:
220 def __init__ (self, iter):
221 self.queue = []
222 self.iter = iter
224 def __iter__ (self):
225 return self
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
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
241 def next (self):
242 # Ensure we have enough frames for a full signal emission
243 self.fill()
245 # Are we at the end?
246 if len(self.queue) == 0:
247 raise StopIteration
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
271 signal_frames = self.queue[start:end]
272 new_frames = [SignalFrame(signal_frames)]
273 self.queue[start:end] = new_frames
275 return self.queue.pop(0)
277 def __next__ (self):
278 return self.next()
280 class GFrameFilter(object):
281 name = 'glib'
282 enabled = True
283 priority = 100
285 def filter(self, iterator):
286 return GFrameDecorator(iterator)
288 def register (obj):
289 if obj == None:
290 obj = gdb
292 if HAVE_GDB_FRAMEDECORATOR:
293 filter = GFrameFilter()
294 obj.frame_filters[filter.name] = filter
295 obj.pretty_printers.append(pretty_printer_lookup)