|
@@ -0,0 +1,210 @@ |
|
|
|
|
|
import gdb |
|
|
|
|
|
|
|
|
|
|
|
import re |
|
|
|
|
|
import subprocess |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_demangle_cache = {} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def demangle(name): |
|
|
|
|
|
if name not in _demangle_cache: |
|
|
|
|
|
_demangle_cache[name] = subprocess.run(['c++filt', "-t", name], stdout=subprocess.PIPE).stdout |
|
|
|
|
|
return _demangle_cache[name].decode('utf-8').strip() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def dynamic_cast(val): |
|
|
|
|
|
assert val.type.code == gdb.TYPE_CODE_REF |
|
|
|
|
|
val = val.cast(val.dynamic_type) |
|
|
|
|
|
return val |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def eval_on_val(val, eval_str): |
|
|
|
|
|
if val.type.code == gdb.TYPE_CODE_REF: |
|
|
|
|
|
val = val.referenced_value() |
|
|
|
|
|
address = val.address |
|
|
|
|
|
eval_str = "(*({}){}){}".format(address.type, address, eval_str) |
|
|
|
|
|
return gdb.parse_and_eval(eval_str) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def is_subclass_of(subclass, baseclass): |
|
|
|
|
|
for field in subclass.fields(): |
|
|
|
|
|
if field.is_base_class: |
|
|
|
|
|
if field.type == baseclass: |
|
|
|
|
|
return True |
|
|
|
|
|
elif is_subclass_of(field.type, baseclass): |
|
|
|
|
|
return True |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def vector_size(vector): |
|
|
|
|
|
impl = vector["_M_impl"] |
|
|
|
|
|
return int(impl["_M_finish"] - impl["_M_start"]) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def vector_item(vector, i): |
|
|
|
|
|
impl = vector["_M_impl"] |
|
|
|
|
|
return (impl["_M_start"] + i).dereference() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def shared_ptr_deref(ptr): |
|
|
|
|
|
return ptr["_M_ptr"].dereference() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_type_name(type_index): |
|
|
|
|
|
return gdb.lookup_global_symbol("mgb::imperative::debug::get_type_name(std::type_index const&)").value()(type_index).string() |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
mge_apply_transform_pattern = re.compile(r"^(.*)::apply_transform\(mgb::imperative::Operator const&, mgb::imperative::Span<mgb::imperative::ValueRef>\)$") |
|
|
|
|
|
mge_op_fallback_pattern = re.compile(r"^(.*)::fallback\(mgb::imperative::Span<mgb::imperative::ValueRef>\) const$") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def is_mge_frame(frame): |
|
|
|
|
|
function = frame.function() |
|
|
|
|
|
if not (function and function.name): |
|
|
|
|
|
return False |
|
|
|
|
|
matcher = mge_apply_transform_pattern.match(function.name) |
|
|
|
|
|
if matcher: |
|
|
|
|
|
typename = matcher.group(1) |
|
|
|
|
|
return is_subclass_of(gdb.lookup_type(typename), gdb.lookup_type("mgb::imperative::Transform")) |
|
|
|
|
|
matcher = mge_op_fallback_pattern.match(function.name) |
|
|
|
|
|
if matcher: |
|
|
|
|
|
typename = matcher.group(1) |
|
|
|
|
|
return is_subclass_of(gdb.lookup_type(typename), gdb.lookup_type("mgb::imperative::Operator")) |
|
|
|
|
|
return False |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def count_frame_level(frame): |
|
|
|
|
|
level = -1 |
|
|
|
|
|
while frame: |
|
|
|
|
|
frame = frame.newer() |
|
|
|
|
|
level += 1 |
|
|
|
|
|
return level |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def print_mge_frame(frame): |
|
|
|
|
|
function = frame.function() |
|
|
|
|
|
op = eval_on_val(dynamic_cast(frame.read_var("op")), ".to_string().c_str()").string() |
|
|
|
|
|
inputs = str(frame.read_var("inputs")) |
|
|
|
|
|
matcher = mge_apply_transform_pattern.match(function.name) |
|
|
|
|
|
if matcher: |
|
|
|
|
|
name = matcher.group(1) |
|
|
|
|
|
else: |
|
|
|
|
|
name = mge_op_fallback_pattern.match(function.name).group(1) |
|
|
|
|
|
#TODO: span |
|
|
|
|
|
sal = frame.find_sal() |
|
|
|
|
|
filename = sal.symtab.filename |
|
|
|
|
|
line = sal.line |
|
|
|
|
|
print("#{} {} apply {} on {}, file: {}:{}".format(count_frame_level(frame), name, op, inputs, filename, line)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MegengineBacktrace(gdb.Command): |
|
|
|
|
|
def __init__(self): |
|
|
|
|
|
super().__init__("mge-bt", gdb.COMMAND_USER) |
|
|
|
|
|
|
|
|
|
|
|
def invoke(self, arg, from_tty): |
|
|
|
|
|
frame = gdb.newest_frame() |
|
|
|
|
|
mge_stack = [] |
|
|
|
|
|
while frame is not None: |
|
|
|
|
|
if is_mge_frame(frame): |
|
|
|
|
|
mge_stack.append(frame) |
|
|
|
|
|
frame = frame.older() |
|
|
|
|
|
for frame in reversed(mge_stack): |
|
|
|
|
|
print_mge_frame(frame) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MegengineBreakApply(gdb.Command): |
|
|
|
|
|
def __init__(self): |
|
|
|
|
|
super().__init__("mge-brk-apply", gdb.COMMAND_USER) |
|
|
|
|
|
|
|
|
|
|
|
def invoke(self, arg, from_tty): |
|
|
|
|
|
gdb.Breakpoint("mgb::imperative::apply(mgb::imperative::Operator const&, mgb::imperative::Span<mgb::imperative::ValueRef>)") |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MegengineWatch(gdb.Command): |
|
|
|
|
|
def __init__(self): |
|
|
|
|
|
super().__init__("mge-watch", gdb.COMMAND_USER) |
|
|
|
|
|
|
|
|
|
|
|
def invoke(self, arg, from_tty): |
|
|
|
|
|
watch = gdb.lookup_global_symbol("mgb::imperative::debug::watch_value(mgb::imperative::ValueRef)").value() |
|
|
|
|
|
value = gdb.parse_and_eval(arg) |
|
|
|
|
|
watch(value) |
|
|
|
|
|
print("watching {}".format(str(value))) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MegengineUp(gdb.Command): |
|
|
|
|
|
def __init__(self): |
|
|
|
|
|
super().__init__("mge-up", gdb.COMMAND_USER) |
|
|
|
|
|
|
|
|
|
|
|
def invoke(self, arg, from_tty): |
|
|
|
|
|
frame = gdb.selected_frame() |
|
|
|
|
|
if frame is None: |
|
|
|
|
|
print("Unable to find older dispatch frame") |
|
|
|
|
|
return |
|
|
|
|
|
frame = frame.older() |
|
|
|
|
|
while frame is not None and not is_mge_frame(frame): |
|
|
|
|
|
frame = frame.older() |
|
|
|
|
|
if frame is None: |
|
|
|
|
|
print("Unable to find older dispatch frame") |
|
|
|
|
|
return |
|
|
|
|
|
frame.select() |
|
|
|
|
|
print_mge_frame(frame) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MegengineDown(gdb.Command): |
|
|
|
|
|
def __init__(self): |
|
|
|
|
|
super().__init__("mge-down", gdb.COMMAND_USER) |
|
|
|
|
|
|
|
|
|
|
|
def invoke(self, arg, from_tty): |
|
|
|
|
|
frame = gdb.selected_frame() |
|
|
|
|
|
if frame is None: |
|
|
|
|
|
print("Unable to find newer dispatch frame") |
|
|
|
|
|
return |
|
|
|
|
|
frame = frame.newer() |
|
|
|
|
|
while frame is not None and not is_mge_frame(frame): |
|
|
|
|
|
frame = frame.newer() |
|
|
|
|
|
if frame is None: |
|
|
|
|
|
print("Unable to find newer dispatch frame") |
|
|
|
|
|
return |
|
|
|
|
|
frame.select() |
|
|
|
|
|
print_mge_frame(frame) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
class MegengineInfo(gdb.Command): |
|
|
|
|
|
def __init__(self): |
|
|
|
|
|
super().__init__("mge-info", gdb.COMMAND_USER) |
|
|
|
|
|
|
|
|
|
|
|
def invoke(self, arg, from_tty): |
|
|
|
|
|
if arg == "opr": |
|
|
|
|
|
registered_oprs = gdb.lookup_global_symbol("mgb::imperative::Operator::registered_types()").value()() |
|
|
|
|
|
size = vector_size(registered_oprs) |
|
|
|
|
|
for i in range(size): |
|
|
|
|
|
registered_opr = vector_item(registered_oprs, i) |
|
|
|
|
|
# name = eval_on_val(registered_opr, ".name()").string() |
|
|
|
|
|
name = get_type_name(registered_opr) |
|
|
|
|
|
print("{}: {}".format(i, demangle(name))) |
|
|
|
|
|
elif arg == "trf": |
|
|
|
|
|
dispatch_context = gdb.lookup_global_symbol("mgb::imperative::Transform::get_context()").value()() |
|
|
|
|
|
transformations = dispatch_context["transformations"] |
|
|
|
|
|
size = vector_size(transformations) |
|
|
|
|
|
for i in range(size): |
|
|
|
|
|
transformation = vector_item(transformations, i) |
|
|
|
|
|
# name = eval_on_val(transformation, ".get()->name().c_str()").string() |
|
|
|
|
|
name = shared_ptr_deref(transformation).dynamic_type.name |
|
|
|
|
|
# name = get_type_name(transformation) |
|
|
|
|
|
print("{}: {}".format(i, demangle(name))) |
|
|
|
|
|
else: |
|
|
|
|
|
print("Unsupported argument {}".format(arg)) |
|
|
|
|
|
|
|
|
|
|
|
def complete(self, text, word): |
|
|
|
|
|
return ["opr", "trf"] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MegengineBacktrace() |
|
|
|
|
|
MegengineBreakApply() |
|
|
|
|
|
MegengineUp() |
|
|
|
|
|
MegengineDown() |
|
|
|
|
|
MegengineInfo() |
|
|
|
|
|
MegengineWatch() |
|
|
|
|
|
|
|
|
|
|
|
gdb.Breakpoint("mgb::imperative::debug::notify_event(char const*)") |