Merge remote-tracking branch 'gvdb/master'
[platform/upstream/glib.git] / gobject / gobject.py
1 import gdb
2 import glib
3 import gdb.backtrace
4 import gdb.command.backtrace
5
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)
9
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()
18
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
28
29 def is_g_type_instance (val):
30     def is_g_type_instance_helper (type):
31         if str(type) == "GTypeInstance":
32             return True
33
34         while type.code == gdb.TYPE_CODE_TYPEDEF:
35             type = type.target()
36
37         if type.code != gdb.TYPE_CODE_STRUCT:
38             return False
39
40         fields = type.fields()
41         if len (fields) < 1:
42             return False
43
44         first_field = fields[0]
45         return is_g_type_instance_helper(first_field.type)
46
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)
52
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
64
65 class GTypePrettyPrinter:
66     "Prints a GType instance pointer"
67
68     def __init__ (self, val):
69         self.val = val
70
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))
76
77 def pretty_printer_lookup (val):
78     if is_g_type_instance (val):
79         return GTypePrettyPrinter (val)
80
81     return None
82
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
95
96 class GFrameWrapper:
97     def __init__ (self, frame):
98         self.frame = frame;
99
100     def name (self):
101         name = self.frame.name()
102         if name and name.startswith("IA__"):
103             return name[4:]
104         return name
105
106     def __getattr__ (self, name):
107         return getattr (self.frame, name)
108
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
117
118 class DummyFrame:
119     def __init__ (self, frame):
120         self.frame = frame
121
122     def name (self):
123         return "signal-emission-dummy"
124
125     def describe (self, stream, full):
126         stream.write (" <...>\n")
127
128     def __getattr__ (self, name):
129         return getattr (self.frame, name)
130
131 class SignalFrame:
132     def __init__ (self, frames):
133         self.frame = frames[-1]
134         self.frames = frames;
135
136     def name (self):
137         return "signal-emission"
138
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
149
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
164
165     def append (self, array, obj):
166         if obj != None:
167             array.append (obj)
168
169     def or_join_array (self, array):
170         if len(array) == 0:
171             return "???"
172
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]
180
181         return s
182
183     def describe (self, stream, full):
184         instances = []
185         signals = []
186
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)
199
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)
213
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)
224
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
229
230         instance = self.or_join_array (instances)
231         signal = self.or_join_array (signals)
232
233         stream.write (" <emit signal %s on instance %s>\n" %  (signal, instance))
234
235     def __getattr__ (self, name):
236         return getattr (self.frame, name)
237
238 class GFrameFilter:
239     def __init__ (self, iter):
240         self.queue = []
241         self.iter = iter
242
243     def __iter__ (self):
244         return self
245
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
253
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
259
260     def next (self):
261         # Ensure we have enough frames for a full signal emission
262         self.fill()
263
264         # Are we at the end?
265         if len(self.queue) == 0:
266             raise StopIteration
267
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
288
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))
294
295             self.queue[start:end] = new_frames
296
297         return self.queue.pop(0)
298
299
300 def register (obj):
301     if obj == None:
302         obj = gdb
303
304     gdb.backtrace.push_frame_filter (GFrameFilter)
305     obj.pretty_printers.append(pretty_printer_lookup)