You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

306 lines
9.2 KiB

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