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

commands.py 6.8 kB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. import gdb
  2. import re
  3. import subprocess
  4. _demangle_cache = {}
  5. def demangle(name):
  6. if name not in _demangle_cache:
  7. _demangle_cache[name] = subprocess.run(['c++filt', "-t", name], stdout=subprocess.PIPE).stdout
  8. return _demangle_cache[name].decode('utf-8').strip()
  9. def dynamic_cast(val):
  10. assert val.type.code == gdb.TYPE_CODE_REF
  11. val = val.cast(val.dynamic_type)
  12. return val
  13. def eval_on_val(val, eval_str):
  14. if val.type.code == gdb.TYPE_CODE_REF:
  15. val = val.referenced_value()
  16. address = val.address
  17. eval_str = "(*({}){}){}".format(address.type, address, eval_str)
  18. return gdb.parse_and_eval(eval_str)
  19. def is_subclass_of(subclass, baseclass):
  20. for field in subclass.fields():
  21. if field.is_base_class:
  22. if field.type == baseclass:
  23. return True
  24. elif is_subclass_of(field.type, baseclass):
  25. return True
  26. def vector_size(vector):
  27. impl = vector["_M_impl"]
  28. return int(impl["_M_finish"] - impl["_M_start"])
  29. def vector_item(vector, i):
  30. impl = vector["_M_impl"]
  31. return (impl["_M_start"] + i).dereference()
  32. def shared_ptr_deref(ptr):
  33. return ptr["_M_ptr"].dereference()
  34. def get_type_name(type_index):
  35. return gdb.lookup_global_symbol("mgb::imperative::debug::get_type_name(std::type_index const&)").value()(type_index).string()
  36. mge_apply_transform_pattern = re.compile(r"^(.*)::apply_transform\(mgb::imperative::Operator const&, mgb::imperative::Span<mgb::imperative::ValueRef>\)$")
  37. mge_op_fallback_pattern = re.compile(r"^(.*)::fallback\(mgb::imperative::Span<mgb::imperative::ValueRef>\) const$")
  38. def is_mge_frame(frame):
  39. function = frame.function()
  40. if not (function and function.name):
  41. return False
  42. matcher = mge_apply_transform_pattern.match(function.name)
  43. if matcher:
  44. typename = matcher.group(1)
  45. return is_subclass_of(gdb.lookup_type(typename), gdb.lookup_type("mgb::imperative::Transform"))
  46. matcher = mge_op_fallback_pattern.match(function.name)
  47. if matcher:
  48. typename = matcher.group(1)
  49. return is_subclass_of(gdb.lookup_type(typename), gdb.lookup_type("mgb::imperative::Operator"))
  50. return False
  51. def count_frame_level(frame):
  52. level = -1
  53. while frame:
  54. frame = frame.newer()
  55. level += 1
  56. return level
  57. def print_mge_frame(frame):
  58. function = frame.function()
  59. op = eval_on_val(dynamic_cast(frame.read_var("op")), ".to_string().c_str()").string()
  60. inputs = str(frame.read_var("inputs"))
  61. matcher = mge_apply_transform_pattern.match(function.name)
  62. if matcher:
  63. name = matcher.group(1)
  64. else:
  65. name = mge_op_fallback_pattern.match(function.name).group(1)
  66. #TODO: span
  67. sal = frame.find_sal()
  68. filename = sal.symtab.filename
  69. line = sal.line
  70. print("#{} {} apply {} on {}, file: {}:{}".format(count_frame_level(frame), name, op, inputs, filename, line))
  71. class MegengineBacktrace(gdb.Command):
  72. def __init__(self):
  73. super().__init__("mge-bt", gdb.COMMAND_USER)
  74. def invoke(self, arg, from_tty):
  75. frame = gdb.newest_frame()
  76. mge_stack = []
  77. while frame is not None:
  78. if is_mge_frame(frame):
  79. mge_stack.append(frame)
  80. frame = frame.older()
  81. for frame in reversed(mge_stack):
  82. print_mge_frame(frame)
  83. class MegengineBreakApply(gdb.Command):
  84. def __init__(self):
  85. super().__init__("mge-brk-apply", gdb.COMMAND_USER)
  86. def invoke(self, arg, from_tty):
  87. gdb.Breakpoint("mgb::imperative::apply(mgb::imperative::Operator const&, mgb::imperative::Span<mgb::imperative::ValueRef>)")
  88. class MegengineWatch(gdb.Command):
  89. def __init__(self):
  90. super().__init__("mge-watch", gdb.COMMAND_USER)
  91. def invoke(self, arg, from_tty):
  92. watch = gdb.lookup_global_symbol("mgb::imperative::debug::watch_value(mgb::imperative::ValueRef)").value()
  93. value = gdb.parse_and_eval(arg)
  94. watch(value)
  95. print("watching {}".format(str(value)))
  96. class MegengineUp(gdb.Command):
  97. def __init__(self):
  98. super().__init__("mge-up", gdb.COMMAND_USER)
  99. def invoke(self, arg, from_tty):
  100. frame = gdb.selected_frame()
  101. if frame is None:
  102. print("Unable to find older dispatch frame")
  103. return
  104. frame = frame.older()
  105. while frame is not None and not is_mge_frame(frame):
  106. frame = frame.older()
  107. if frame is None:
  108. print("Unable to find older dispatch frame")
  109. return
  110. frame.select()
  111. print_mge_frame(frame)
  112. class MegengineDown(gdb.Command):
  113. def __init__(self):
  114. super().__init__("mge-down", gdb.COMMAND_USER)
  115. def invoke(self, arg, from_tty):
  116. frame = gdb.selected_frame()
  117. if frame is None:
  118. print("Unable to find newer dispatch frame")
  119. return
  120. frame = frame.newer()
  121. while frame is not None and not is_mge_frame(frame):
  122. frame = frame.newer()
  123. if frame is None:
  124. print("Unable to find newer dispatch frame")
  125. return
  126. frame.select()
  127. print_mge_frame(frame)
  128. class MegengineInfo(gdb.Command):
  129. def __init__(self):
  130. super().__init__("mge-info", gdb.COMMAND_USER)
  131. def invoke(self, arg, from_tty):
  132. if arg == "opr":
  133. registered_oprs = gdb.lookup_global_symbol("mgb::imperative::Operator::registered_types()").value()()
  134. size = vector_size(registered_oprs)
  135. for i in range(size):
  136. registered_opr = vector_item(registered_oprs, i)
  137. # name = eval_on_val(registered_opr, ".name()").string()
  138. name = get_type_name(registered_opr)
  139. print("{}: {}".format(i, demangle(name)))
  140. elif arg == "trf":
  141. dispatch_context = gdb.lookup_global_symbol("mgb::imperative::Transform::get_context()").value()()
  142. transformations = dispatch_context["transformations"]
  143. size = vector_size(transformations)
  144. for i in range(size):
  145. transformation = vector_item(transformations, i)
  146. # name = eval_on_val(transformation, ".get()->name().c_str()").string()
  147. name = shared_ptr_deref(transformation).dynamic_type.name
  148. # name = get_type_name(transformation)
  149. print("{}: {}".format(i, demangle(name)))
  150. else:
  151. print("Unsupported argument {}".format(arg))
  152. def complete(self, text, word):
  153. return ["opr", "trf"]
  154. MegengineBacktrace()
  155. MegengineBreakApply()
  156. MegengineUp()
  157. MegengineDown()
  158. MegengineInfo()
  159. MegengineWatch()
  160. gdb.Breakpoint("mgb::imperative::debug::notify_event(char const*)")