Merge branch 'source-get-id-docs' into 'master'
[glib.git] / gobject / gobject_gdb.py
blob1746576fdd41d919e41220febc31d0a96e88840c
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_typenode (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 return typenode
41 def g_type_to_name (gtype):
42 typenode = g_type_to_typenode(gtype)
43 if typenode != None:
44 return glib_gdb.g_quark_to_string (typenode["qname"])
45 return None
47 def is_g_type_instance (val):
48 def is_g_type_instance_helper (type):
49 if str(type) == "GTypeInstance":
50 return True
52 while type.code == gdb.TYPE_CODE_TYPEDEF:
53 type = type.target()
55 if type.code != gdb.TYPE_CODE_STRUCT:
56 return False
58 fields = type.fields()
59 if len (fields) < 1:
60 return False
62 first_field = fields[0]
63 return is_g_type_instance_helper(first_field.type)
65 type = val.type
66 if type.code != gdb.TYPE_CODE_PTR:
67 return False
68 type = type.target()
69 return is_g_type_instance_helper (type)
71 def g_type_name_from_instance (instance):
72 if long(instance) != 0:
73 try:
74 inst = instance.cast (gdb.lookup_type("GTypeInstance").pointer())
75 klass = inst["g_class"]
76 gtype = klass["g_type"]
77 name = g_type_to_name (gtype)
78 return name
79 except RuntimeError:
80 pass
81 return None
83 class GTypePrettyPrinter:
84 "Prints a GType instance pointer"
86 def __init__ (self, val):
87 self.val = val
89 def to_string (self):
90 name = g_type_name_from_instance (self.val)
91 if name:
92 return ("0x%x [%s]")% (long(self.val), name)
93 return ("0x%x") % (long(self.val))
95 def is_g_type_class_instance (val):
96 type = val.type
97 if type.code != gdb.TYPE_CODE_PTR:
98 return False
99 return str(type.target()) == "GTypeClass"
101 class GTypeHandlePrettyPrinter:
102 "Prints a GType instance"
104 def __init__ (self, val, hint = ""):
105 self.val = val
106 self.hint = hint
108 def to_string (self):
109 typenode = g_type_to_typenode(self.val)
110 if typenode != None:
111 name = glib_gdb.g_quark_to_string (typenode["qname"])
112 s = ("0x%x [%s%s")% (long(self.val), self.hint, name)
113 for i in range (1, int(typenode["n_supers"])):
114 node = g_type_to_typenode(typenode["supers"][i])
115 if node:
116 name = glib_gdb.g_quark_to_string(node["qname"])
117 else:
118 name = "???"
119 s += "/" + name
120 return s + "]"
121 else:
122 return ("0x%x") % (long(self.val))
124 def pretty_printer_lookup (val):
125 if is_g_type_instance (val):
126 return GTypePrettyPrinter (val)
127 if str(val.type) == "GType":
128 return GTypeHandlePrettyPrinter (val)
129 if is_g_type_class_instance (val):
130 return GTypeHandlePrettyPrinter (val["g_type"], "g_type: ")
132 return None
134 def get_signal_name (id):
135 if id == None:
136 return None
137 id = long(id)
138 if id == 0:
139 return None
140 val = read_global_var ("g_signal_nodes")
141 max_s = read_global_var ("g_n_signal_nodes")
142 max_s = long(max_s)
143 if id < max_s:
144 return val[id]["name"].string()
145 return None
147 def frame_name(frame):
148 return str(frame.function())
150 def frame_var(frame, var):
151 return frame.inferior_frame().read_var(var)
154 class SignalFrame(FrameDecorator):
155 def __init__ (self, frames):
156 FrameDecorator.__init__(self, frames[-1])
157 self.frame = frames[-1]
158 self.frames = frames
160 def name (self):
161 return "signal-emission"
163 def read_var (self, frame, name, array = None):
164 try:
165 v = frame_var (frame, name)
166 if v == None or v.is_optimized_out:
167 return None
168 if array != None:
169 array.append (v)
170 return v
171 except ValueError:
172 return None
174 def read_object (self, frame, name, array = None):
175 try:
176 v = frame_var (frame, name)
177 if v == None or v.is_optimized_out:
178 return None
179 v = v.cast (gdb.lookup_type("GObject").pointer())
180 # Ensure this is a somewhat correct object pointer
181 if v != None and g_type_name_from_instance (v):
182 if array != None:
183 array.append (v)
184 return v
185 return None
186 except ValueError:
187 return None
189 def append (self, array, obj):
190 if obj != None:
191 array.append (obj)
193 def or_join_array (self, array):
194 if len(array) == 0:
195 return "???"
196 else:
197 return ' or '.join(set(map(str, array)))
199 def get_detailed_signal_from_frame(self, frame, signal):
200 detail = self.read_var (frame, "detail")
201 detail = glib_gdb.g_quark_to_string (detail)
202 if detail is not None:
203 return signal + ":" + detail
204 else:
205 return detail
207 def function (self):
208 instances = []
209 signals = []
211 for frame in self.frames:
212 name = frame_name(frame)
213 if name == "signal_emit_unlocked_R":
214 self.read_object (frame, "instance", instances)
215 node = self.read_var (frame, "node")
216 if node:
217 signal = node["name"].string()
218 signal = self.get_detailed_signal_from_frame(frame, signal)
219 self.append(signals, signal)
221 if name == "g_signal_emitv":
222 instance_and_params = self.read_var (frame, "instance_and_params")
223 if instance_and_params:
224 instance = instance_and_params[0]["v_pointer"].cast (gdb.Type("GObject").pointer())
225 self.append (instances, instance)
226 id = self.read_var (frame, "signal_id")
227 signal = get_signal_name (id)
228 if signal:
229 signal = self.get_detailed_signal_from_frame(frame, signal)
230 self.append (signals, signal)
232 if name == "g_signal_emit_valist" or name == "g_signal_emit":
233 self.read_object (frame, "instance", instances)
234 id = self.read_var (frame, "signal_id")
235 signal = get_signal_name (id)
236 if signal:
237 signal = self.get_detailed_signal_from_frame(frame, signal)
238 self.append (signals, signal)
240 if name == "g_signal_emit_by_name":
241 self.read_object (frame, "instance", instances)
242 self.read_var (frame, "detailed_signal", signals)
243 break
245 instance = self.or_join_array (instances)
246 signal = self.or_join_array (signals)
248 return "<emit signal %s on instance %s>" % (signal, instance)
250 def elided (self):
251 return self.frames[0:-1]
253 def describe (self, stream, full):
254 stream.write (" " + self.function () + "\n")
256 class GFrameDecorator:
257 def __init__ (self, iter):
258 self.queue = []
259 self.iter = iter
261 def __iter__ (self):
262 return self
264 def fill (self):
265 while len(self.queue) <= 8:
266 try:
267 f = next(self.iter)
268 self.queue.append (f)
269 except StopIteration:
270 return
272 def find_signal_emission (self):
273 for i in range (min (len(self.queue), 3)):
274 if frame_name(self.queue[i]) == "signal_emit_unlocked_R":
275 return i
276 return -1
278 def next (self):
279 # Ensure we have enough frames for a full signal emission
280 self.fill()
282 # Are we at the end?
283 if len(self.queue) == 0:
284 raise StopIteration
286 emission = self.find_signal_emission ()
287 if emission > 0:
288 start = emission
289 while True:
290 if start == 0:
291 break
292 prev_name = frame_name(self.queue[start-1])
293 if prev_name.find("_marshal_") >= 0 or prev_name == "g_closure_invoke":
294 start = start - 1
295 else:
296 break
297 end = emission + 1
298 while end < len(self.queue):
299 if frame_name(self.queue[end]) in ["g_signal_emitv",
300 "g_signal_emit_valist",
301 "g_signal_emit",
302 "g_signal_emit_by_name",
303 "_g_closure_invoke_va"]:
304 end = end + 1
305 else:
306 break
308 signal_frames = self.queue[start:end]
309 new_frames = [SignalFrame(signal_frames)]
310 self.queue[start:end] = new_frames
312 return self.queue.pop(0)
314 def __next__ (self):
315 return self.next()
317 class GFrameFilter(object):
318 name = 'glib'
319 enabled = True
320 priority = 100
322 def filter(self, iterator):
323 return GFrameDecorator(iterator)
325 def register (obj):
326 if obj == None:
327 obj = gdb
329 if HAVE_GDB_FRAMEDECORATOR:
330 filter = GFrameFilter()
331 obj.frame_filters[filter.name] = filter
332 obj.pretty_printers.append(pretty_printer_lookup)