gmain: fix some silly code in a programmer-error case
[glib.git] / gobject / gobject.py
blobb96d1505e52c0d76180d690910e7f2e1aba52fd1
1 import gdb
2 import glib
3 import gdb.backtrace
4 import gdb.command.backtrace
6 # This is not quite right, as local vars may override symname
7 def read_global_var (symname):
8 return gdb.selected_frame().read_var(symname)
10 def g_type_to_name (gtype):
11 def lookup_fundamental_type (typenode):
12 if typenode == 0:
13 return None
14 val = read_global_var ("static_fundamental_type_nodes")
15 if val == None:
16 return None
17 return val[typenode >> 2].address()
19 gtype = long(gtype)
20 typenode = gtype - gtype % 4
21 if typenode > (255 << 2):
22 typenode = gdb.Value(typenode).cast (gdb.lookup_type("TypeNode").pointer())
23 else:
24 typenode = lookup_fundamental_type (typenode)
25 if typenode != None:
26 return glib.g_quark_to_string (typenode["qname"])
27 return None
29 def is_g_type_instance (val):
30 def is_g_type_instance_helper (type):
31 if str(type) == "GTypeInstance":
32 return True
34 while type.code == gdb.TYPE_CODE_TYPEDEF:
35 type = type.target()
37 if type.code != gdb.TYPE_CODE_STRUCT:
38 return False
40 fields = type.fields()
41 if len (fields) < 1:
42 return False
44 first_field = fields[0]
45 return is_g_type_instance_helper(first_field.type)
47 type = val.type
48 if type.code != gdb.TYPE_CODE_PTR:
49 return False
50 type = type.target()
51 return is_g_type_instance_helper (type)
53 def g_type_name_from_instance (instance):
54 if long(instance) != 0:
55 try:
56 inst = instance.cast (gdb.lookup_type("GTypeInstance").pointer())
57 klass = inst["g_class"]
58 gtype = klass["g_type"]
59 name = g_type_to_name (gtype)
60 return name
61 except RuntimeError:
62 pass
63 return None
65 class GTypePrettyPrinter:
66 "Prints a GType instance pointer"
68 def __init__ (self, val):
69 self.val = val
71 def to_string (self):
72 name = g_type_name_from_instance (self.val)
73 if name:
74 return ("0x%x [%s]")% (long(self.val), name)
75 return ("0x%x") % (long(self.val))
77 def pretty_printer_lookup (val):
78 if is_g_type_instance (val):
79 return GTypePrettyPrinter (val)
81 return None
83 def get_signal_name (id):
84 if id == None:
85 return None
86 id = long(id)
87 if id == 0:
88 return None
89 val = read_global_var ("g_signal_nodes")
90 max_s = read_global_var ("g_n_signal_nodes")
91 max_s = long(max_s)
92 if id < max_s:
93 return val[id]["name"].string()
94 return None
96 class GFrameWrapper:
97 def __init__ (self, frame):
98 self.frame = frame;
100 def name (self):
101 name = self.frame.name()
102 if name and name.startswith("IA__"):
103 return name[4:]
104 return name
106 def __getattr__ (self, name):
107 return getattr (self.frame, name)
109 # Monkey patch FrameWrapper to avoid IA__ in symbol names
110 old__init__ = gdb.command.backtrace.FrameWrapper.__init__
111 def monkey_patched_init(self, frame):
112 name = frame.name()
113 if name and name.startswith("IA__"):
114 frame = GFrameWrapper(frame)
115 old__init__(self,frame)
116 gdb.command.backtrace.FrameWrapper.__init__ = monkey_patched_init
118 class DummyFrame:
119 def __init__ (self, frame):
120 self.frame = frame
122 def name (self):
123 return "signal-emission-dummy"
125 def describe (self, stream, full):
126 stream.write (" <...>\n")
128 def __getattr__ (self, name):
129 return getattr (self.frame, name)
131 class SignalFrame:
132 def __init__ (self, frames):
133 self.frame = frames[-1]
134 self.frames = frames;
136 def name (self):
137 return "signal-emission"
139 def read_var (self, frame, name, array = None):
140 try:
141 v = frame.read_var (name)
142 if v == None or v.is_optimized_out:
143 return None
144 if array != None:
145 array.append (v)
146 return v
147 except ValueError:
148 return None
150 def read_object (self, frame, name, array = None):
151 try:
152 v = frame.read_var (name)
153 if v == None or v.is_optimized_out:
154 return None
155 v = v.cast (gdb.lookup_type("GObject").pointer())
156 # Ensure this is a somewhat correct object pointer
157 if v != None and g_type_name_from_instance (v):
158 if array != None:
159 array.append (v)
160 return v
161 return None
162 except ValueError:
163 return None
165 def append (self, array, obj):
166 if obj != None:
167 array.append (obj)
169 def or_join_array (self, array):
170 if len(array) == 0:
171 return "???"
173 v = {}
174 for i in range(len(array)):
175 v[str(array[i])] = 1
176 array = v.keys()
177 s = array[0]
178 for i in range(1, len(array)):
179 s = s + " or %s"%array[i]
181 return s
183 def describe (self, stream, full):
184 instances = []
185 signals = []
187 for frame in self.frames:
188 name = frame.name()
189 if name == "signal_emit_unlocked_R":
190 self.read_object (frame, "instance", instances)
191 node = self.read_var (frame, "node")
192 if node:
193 signal = node["name"].string()
194 detail = self.read_var (frame, "detail")
195 detail = glib.g_quark_to_string (detail)
196 if detail != None:
197 signal = signal + ":" + detail
198 self.append (signals, signal)
200 if name == "g_signal_emitv":
201 instance_and_params = self.read_var (frame, "instance_and_params")
202 if instance_and_params:
203 instance = instance_and_params[0]["v_pointer"].cast (gdb.Type("GObject").pointer())
204 self.append (instances, instance)
205 id = self.read_var (frame, "signal_id")
206 signal = get_signal_name (id)
207 if signal:
208 detail = self.read_var (frame, "detail")
209 detail = glib.g_quark_to_string (detail)
210 if detail != None:
211 signal = signal + ":" + detail
212 self.append (signals, signal)
214 if name == "g_signal_emit_valist" or name == "g_signal_emit":
215 self.read_object (frame, "instance", instances)
216 id = self.read_var (frame, "signal_id")
217 signal = get_signal_name (id)
218 if signal:
219 detail = self.read_var (frame, "detail")
220 detail = glib.g_quark_to_string (detail)
221 if detail != None:
222 signal = signal + ":" + detail
223 self.append (signals, signal)
225 if name == "g_signal_emit_by_name":
226 self.read_object (frame, "instance", instances)
227 self.read_var (frame, "detailed_signal", signals)
228 break
230 instance = self.or_join_array (instances)
231 signal = self.or_join_array (signals)
233 stream.write (" <emit signal %s on instance %s>\n" % (signal, instance))
235 def __getattr__ (self, name):
236 return getattr (self.frame, name)
238 class GFrameFilter:
239 def __init__ (self, iter):
240 self.queue = []
241 self.iter = iter
243 def __iter__ (self):
244 return self
246 def fill (self):
247 while len(self.queue) <= 6:
248 try:
249 f = self.iter.next ()
250 self.queue.append (f)
251 except StopIteration:
252 return
254 def find_signal_emission (self):
255 for i in range (min (len(self.queue), 3)):
256 if self.queue[i].name() == "signal_emit_unlocked_R":
257 return i
258 return -1
260 def next (self):
261 # Ensure we have enough frames for a full signal emission
262 self.fill()
264 # Are we at the end?
265 if len(self.queue) == 0:
266 raise StopIteration
268 emission = self.find_signal_emission ()
269 if emission > 0:
270 start = emission
271 while True:
272 if start == 0:
273 break
274 prev_name = self.queue[start-1].name()
275 if prev_name.find("_marshal_") or prev_name == "g_closure_invoke":
276 start = start - 1
277 else:
278 break
279 end = emission + 1
280 while end < len(self.queue):
281 if self.queue[end].name() in ["g_signal_emitv",
282 "g_signal_emit_valist",
283 "g_signal_emit",
284 "g_signal_emit_by_name"]:
285 end = end + 1
286 else:
287 break
289 signal_frames = self.queue[start:end]
290 new_frames = []
291 for i in range(len(signal_frames)-1):
292 new_frames.append(DummyFrame(signal_frames[i]))
293 new_frames.append(SignalFrame(signal_frames))
295 self.queue[start:end] = new_frames
297 return self.queue.pop(0)
300 def register (obj):
301 if obj == None:
302 obj = gdb
304 gdb.backtrace.push_frame_filter (GFrameFilter)
305 obj.pretty_printers.append(pretty_printer_lookup)