glib (2.79.0)
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)