1import gdb 2import glib_gdb 3import sys 4 5if sys.version_info[0] >= 3: 6 long = int 7else: 8 import itertools 9 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 16 HAVE_GDB_FRAMEDECORATOR = True 17 FrameDecorator = gdb.FrameDecorator.FrameDecorator 18except ImportError: 19 HAVE_GDB_FRAMEDECORATOR = False 20 21 22# This is not quite right, as local vars may override symname 23def read_global_var(symname): 24 return gdb.selected_frame().read_var(symname) 25 26 27def 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 45def 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 52def 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 77def 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 90class GTypePrettyPrinter: 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 103def 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 110class GTypeHandlePrettyPrinter: 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 134def 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 145def get_signal_name(id): 146 if id is None: 147 return None 148 id = long(id) 149 if id == 0: 150 return None 151 val = read_global_var("g_signal_nodes") 152 max_s = read_global_var("g_n_signal_nodes") 153 max_s = long(max_s) 154 if id < max_s: 155 return val[id]["name"].string() 156 return None 157 158 159def frame_name(frame): 160 return str(frame.function()) 161 162 163def frame_var(frame, var): 164 return frame.inferior_frame().read_var(var) 165 166 167class SignalFrame(FrameDecorator): 168 def __init__(self, frames): 169 FrameDecorator.__init__(self, frames[-1]) 170 self.frame = frames[-1] 171 self.frames = frames 172 173 def name(self): 174 return "signal-emission" 175 176 def read_var(self, frame, name, array=None): 177 try: 178 v = frame_var(frame, name) 179 if v is None or v.is_optimized_out: 180 return None 181 if array is not None: 182 array.append(v) 183 return v 184 except ValueError: 185 return None 186 187 def read_object(self, frame, name, array=None): 188 try: 189 v = frame_var(frame, name) 190 if v is None or v.is_optimized_out: 191 return None 192 v = v.cast(gdb.lookup_type("GObject").pointer()) 193 # Ensure this is a somewhat correct object pointer 194 if v is not None and g_type_name_from_instance(v): 195 if array is not None: 196 array.append(v) 197 return v 198 return None 199 except ValueError: 200 return None 201 202 def append(self, array, obj): 203 if obj is not None: 204 array.append(obj) 205 206 def or_join_array(self, array): 207 if len(array) == 0: 208 return "???" 209 else: 210 return " or ".join(set(map(str, array))) 211 212 def get_detailed_signal_from_frame(self, frame, signal): 213 detail = self.read_var(frame, "detail") 214 detail = glib_gdb.g_quark_to_string(detail) 215 if detail is not None: 216 return signal + ":" + detail 217 else: 218 return detail 219 220 def function(self): 221 instances = [] 222 signals = [] 223 224 for frame in self.frames: 225 name = frame_name(frame) 226 if name == "signal_emit_unlocked_R": 227 self.read_object(frame, "instance", instances) 228 node = self.read_var(frame, "node") 229 if node: 230 signal = node["name"].string() 231 signal = self.get_detailed_signal_from_frame(frame, signal) 232 self.append(signals, signal) 233 234 if name == "g_signal_emitv": 235 instance_and_params = self.read_var(frame, "instance_and_params") 236 if instance_and_params: 237 instance = instance_and_params[0]["v_pointer"].cast( 238 gdb.Type("GObject").pointer() 239 ) 240 self.append(instances, instance) 241 id = self.read_var(frame, "signal_id") 242 signal = get_signal_name(id) 243 if signal: 244 signal = self.get_detailed_signal_from_frame(frame, signal) 245 self.append(signals, signal) 246 247 if name == "g_signal_emit_valist" or name == "g_signal_emit": 248 self.read_object(frame, "instance", instances) 249 id = self.read_var(frame, "signal_id") 250 signal = get_signal_name(id) 251 if signal: 252 signal = self.get_detailed_signal_from_frame(frame, signal) 253 self.append(signals, signal) 254 255 if name == "g_signal_emit_by_name": 256 self.read_object(frame, "instance", instances) 257 self.read_var(frame, "detailed_signal", signals) 258 break 259 260 instance = self.or_join_array(instances) 261 signal = self.or_join_array(signals) 262 263 return "<emit signal %s on instance %s>" % (signal, instance) 264 265 def elided(self): 266 return self.frames[0:-1] 267 268 def describe(self, stream, full): 269 stream.write(" " + self.function() + "\n") 270 271 272class GFrameDecorator: 273 def __init__(self, iter): 274 self.queue = [] 275 self.iter = iter 276 277 def __iter__(self): 278 return self 279 280 def fill(self): 281 while len(self.queue) <= 8: 282 try: 283 f = next(self.iter) 284 self.queue.append(f) 285 except StopIteration: 286 return 287 288 def find_signal_emission(self): 289 for i in range(min(len(self.queue), 3)): 290 if frame_name(self.queue[i]) == "signal_emit_unlocked_R": 291 return i 292 return -1 293 294 def next(self): 295 # Ensure we have enough frames for a full signal emission 296 self.fill() 297 298 # Are we at the end? 299 if len(self.queue) == 0: 300 raise StopIteration 301 302 emission = self.find_signal_emission() 303 if emission > 0: 304 start = emission 305 while True: 306 if start == 0: 307 break 308 prev_name = frame_name(self.queue[start - 1]) 309 if prev_name.find("_marshal_") >= 0 or prev_name == "g_closure_invoke": 310 start = start - 1 311 else: 312 break 313 end = emission + 1 314 while end < len(self.queue): 315 if frame_name(self.queue[end]) in [ 316 "g_signal_emitv", 317 "g_signal_emit_valist", 318 "g_signal_emit", 319 "g_signal_emit_by_name", 320 "_g_closure_invoke_va", 321 ]: 322 end = end + 1 323 else: 324 break 325 326 signal_frames = self.queue[start:end] 327 new_frames = [SignalFrame(signal_frames)] 328 self.queue[start:end] = new_frames 329 330 return self.queue.pop(0) 331 332 def __next__(self): 333 return self.next() 334 335 336class GFrameFilter(object): 337 name = "glib" 338 enabled = True 339 priority = 100 340 341 def filter(self, iterator): 342 return GFrameDecorator(iterator) 343 344 345def register(obj): 346 if obj is None: 347 obj = gdb 348 349 if HAVE_GDB_FRAMEDECORATOR: 350 filter = GFrameFilter() 351 obj.frame_filters[filter.name] = filter 352 obj.pretty_printers.append(pretty_printer_lookup) 353