1import os.path 2import gdb 3import glib_gdb 4import sys 5 6if sys.version_info[0] >= 3: 7 long = int 8else: 9 import itertools 10 map = itertools.imap 11 12# FrameDecorator is new in gdb 7.7, so we adapt to its absence. 13try: 14 import gdb.FrameDecorator 15 HAVE_GDB_FRAMEDECORATOR = True 16 FrameDecorator = gdb.FrameDecorator.FrameDecorator 17except ImportError: 18 HAVE_GDB_FRAMEDECORATOR = False 19 20# This is not quite right, as local vars may override symname 21def read_global_var (symname): 22 return gdb.selected_frame().read_var(symname) 23 24def 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 is None: 30 return None 31 return val[typenode >> 2].address 32 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 40 41def 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 46 47def is_g_type_instance (val): 48 def is_g_type_instance_helper (type): 49 if str(type) == "GTypeInstance": 50 return True 51 52 while type.code == gdb.TYPE_CODE_TYPEDEF: 53 type = type.target() 54 55 if type.code != gdb.TYPE_CODE_STRUCT: 56 return False 57 58 fields = type.fields() 59 if len (fields) < 1: 60 return False 61 62 first_field = fields[0] 63 return is_g_type_instance_helper(first_field.type) 64 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) 70 71def 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 82 83class GTypePrettyPrinter: 84 "Prints a GType instance pointer" 85 86 def __init__ (self, val): 87 self.val = val 88 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)) 94 95def 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" 100 101class GTypeHandlePrettyPrinter: 102 "Prints a GType instance" 103 104 def __init__ (self, val, hint = ""): 105 self.val = val 106 self.hint = hint 107 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)) 123 124def 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: ") 131 132 return None 133 134def get_signal_name (id): 135 if id is 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 146 147def frame_name(frame): 148 return str(frame.function()) 149 150def frame_var(frame, var): 151 return frame.inferior_frame().read_var(var) 152 153 154class SignalFrame(FrameDecorator): 155 def __init__ (self, frames): 156 FrameDecorator.__init__(self, frames[-1]) 157 self.frame = frames[-1] 158 self.frames = frames 159 160 def name (self): 161 return "signal-emission" 162 163 def read_var (self, frame, name, array = None): 164 try: 165 v = frame_var (frame, name) 166 if v is 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 173 174 def read_object (self, frame, name, array = None): 175 try: 176 v = frame_var (frame, name) 177 if v is 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 188 189 def append (self, array, obj): 190 if obj != None: 191 array.append (obj) 192 193 def or_join_array (self, array): 194 if len(array) == 0: 195 return "???" 196 else: 197 return ' or '.join(set(map(str, array))) 198 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 206 207 def function (self): 208 instances = [] 209 signals = [] 210 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) 220 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) 231 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) 239 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 244 245 instance = self.or_join_array (instances) 246 signal = self.or_join_array (signals) 247 248 return "<emit signal %s on instance %s>" % (signal, instance) 249 250 def elided (self): 251 return self.frames[0:-1] 252 253 def describe (self, stream, full): 254 stream.write (" " + self.function () + "\n") 255 256class GFrameDecorator: 257 def __init__ (self, iter): 258 self.queue = [] 259 self.iter = iter 260 261 def __iter__ (self): 262 return self 263 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 271 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 277 278 def next (self): 279 # Ensure we have enough frames for a full signal emission 280 self.fill() 281 282 # Are we at the end? 283 if len(self.queue) == 0: 284 raise StopIteration 285 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 307 308 signal_frames = self.queue[start:end] 309 new_frames = [SignalFrame(signal_frames)] 310 self.queue[start:end] = new_frames 311 312 return self.queue.pop(0) 313 314 def __next__ (self): 315 return self.next() 316 317class GFrameFilter(object): 318 name = 'glib' 319 enabled = True 320 priority = 100 321 322 def filter(self, iterator): 323 return GFrameDecorator(iterator) 324 325def register (obj): 326 if obj is None: 327 obj = gdb 328 329 if HAVE_GDB_FRAMEDECORATOR: 330 filter = GFrameFilter() 331 obj.frame_filters[filter.name] = filter 332 obj.pretty_printers.append(pretty_printer_lookup) 333