# -*- coding: utf-8 -*- # # Copyright (c) 2016 Microsoft Corporation. All rights reserved. # Released under Apache 2.0 license as described in the file LICENSE. # # Authors: Sebastian Ullrich, Gabriel Ebner # import gdb import gdb.printing def is_scalar(o): return o.cast(gdb.lookup_type('uintptr_t')) & 1 == 1 def box(n): return gdb.Value(n << 1 | 1).cast(gdb.lookup_type('lean::object').pointer()) def unbox(o): return o.cast(gdb.lookup_type('uintptr_t')) >> 1 def to_cnstr(o): return o.cast(gdb.lookup_type('lean::constructor_object').pointer()) def get_cnstr_tag(o): return to_cnstr(o).dereference()['m_tag'] char_p = gdb.lookup_type('char').pointer() def get_cnstr_obj_arg(o, i): return (o.cast(char_p) + gdb.lookup_type('lean::constructor_object').sizeof).cast(gdb.lookup_type('lean::object').pointer().pointer())[i] def get_closure_arg(o, i): return (o.cast(char_p) + gdb.lookup_type('lean::closure_object').sizeof).cast(gdb.lookup_type('lean::object').pointer().pointer())[i] def get_c_str(o): return (o.cast(char_p) + gdb.lookup_type('lean::string_object').sizeof) def get_rc(o): return (o.cast(gdb.lookup_type('uintptr_t').pointer()) - 1).dereference() class LeanObjectPrinter: """Print a lean::object object.""" kinds = [ ('constructor', ['m_tag', 'm_scalar_size']), ('closure', ['m_arity', 'm_fun']), ('array', []), ('sarray', []), ('parray_root', []), ('parray_set', []), ('parray_push', []), ('parray_pop', []), ('string', ['m_size', 'm_capacity', 'm_length']), ('mpz', ['m_value']), ('thunk', ['m_value', 'm_closure']), ('external', []), ] def __init__(self, val): self.val = val.address if not is_scalar(self.val): self.kind = int(self.val.dereference()['m_kind']) def to_string(self): if is_scalar(self.val): return unbox(self.val) else: return "{} (RC {})".format(LeanObjectPrinter.kinds[self.kind][0], get_rc(self.val)) def children(self): if is_scalar(self.val): return yield ('RC', get_rc(self.val)) if self.kind >= len(LeanObjectPrinter.kinds): return typ, fields = LeanObjectPrinter.kinds[self.kind] if fields: val = self.val.cast(gdb.lookup_type("lean::" + typ + "_object").pointer()).dereference() for f in fields: yield (f, val[f]) if typ == 'constructor': for i in range(val['m_num_objs']): yield ('', get_cnstr_obj_arg(self.val, i)) elif typ == 'closure': for i in range(val['m_num_fixed']): yield ('', get_closure_arg(self.val, i)) class LeanOptionalPrinter: """Print a lean::optional object.""" def __init__(self, val): self.val = val def get_val(self): if hasattr(self.val, 'm_some'): if not self.val['m_some']: return None elif not self.val['m_value'].cast(gdb.lookup_type('char').pointer()): return None return self.val['m_value'] def children(self): val = self.get_val() return [('', val)] if val else [] def to_string(self): return str(self.val.type) class LeanNamePrinter: """Print a lean::name object.""" def __init__(self, val): self.val = val def to_string(self): def rec(o): prefix = get_cnstr_obj_arg(o, 0) part = get_cnstr_obj_arg(o, 1) s = ("'%s'" % get_c_str(part).string()) if get_cnstr_tag(o) == 1 else str(unbox(part)) if not is_scalar(prefix): return "%s.%s" % (rec(prefix), s) else: return s if is_scalar(self.val['m_obj']): return "" else: return rec(self.val['m_obj']) class LeanExprPrinter: """Print a lean::expr object.""" expr_kinds = [ ('bvar', [('idx', 'nat')]), ('fvar', ['name']), ('mvar', ['name', ('type', 'expr')]), ('sort', ['level']), ('const', ['name', ('levels', 'list_ref')]), ('app', [('fn', 'expr'), ('arg', 'expr')]), ('lam', ['name', ('type', 'expr'), ('body', 'expr')]), ('pi', ['name', ('type', 'expr'), ('body', 'expr')]), ('let', ['name', ('type', 'expr'), ('val', 'expr'), ('body', 'expr')]), ('lit', ['literal']), ('mdata', ['kvmap', 'expr']), ('proj', ['name', 'nat', 'expr']), ] def __init__(self, val): self.val = val def to_string(self): return 'lean::expr[{}]'.format(LeanExprPrinter.expr_kinds[get_cnstr_tag(self.val['m_obj'])][0]) def children(self): _, fields = LeanExprPrinter.expr_kinds[get_cnstr_tag(self.val['m_obj'])] for i, f in enumerate(fields): if isinstance(f, tuple): name, typ = f else: name, typ = f, f yield (name, get_cnstr_obj_arg(self.val['m_obj'], i).cast(gdb.lookup_type('lean::' + typ))) class LeanLevelPrinter: """Print a lean::level object.""" level_kinds = [ ('lean::level_cell', 'zero', []), ('lean::level_succ', 'succ', ['m_l']), ('lean::level_max_core', 'max', ['m_lhs', 'm_rhs']), ('lean::level_max_core', 'imax', ['m_lhs', 'm_rhs']), ('lean::level_param_core', 'param', ['m_id']), ('lean::level_param_core', 'meta', ['m_id']), ] def __init__(self, val): self.val = val def to_string(self): kind = int(self.val['m_obj']['m_kind']) (subtype, name, fields) = LeanLevelPrinter.level_kinds[kind] subtype = gdb.lookup_type(subtype) val = self.val['m_obj'].cast(subtype.pointer()).dereference() return "({})".format(" ".join([name] + [str(val[field]) for field in fields])) class LeanListPrinter: """Print a lean::list object.""" def __init__(self, val): self.val = val def children(self): l = self.val i = 0 while l['m_obj']: cell = l['m_obj'].dereference() yield ('[%s]' % i, cell['m_head']) l = cell['m_tail'] i += 1 def to_string(self): return str(self.val.type) def display_hint(self): return 'array' class LeanBufferPrinter: """Print a lean::buffer object.""" def __init__(self, val): self.val = val def children(self): p = self.val['m_buffer'] for i in range(int(self.val['m_pos'])): yield ('[%s]' % i, p.dereference()) p += 1 def to_string(self): return str(self.val.type) def display_hint(self): return 'array' class LeanListRefPrinter: """Print a lean::list_ref object.""" def __init__(self, val): self.val = val def children(self): l = self.val['m_obj'] i = 0 while not is_scalar(l): yield ('[%s]' % i, get_cnstr_obj_arg(l, 0).cast(self.val.type.template_argument(0))) l = get_cnstr_obj_arg(l, 1) i += 1 def to_string(self): return str(self.val.type) def display_hint(self): return 'array' class LeanRBTreePrinter: """Print a lean::rb_tree object.""" def __init__(self, val): self.val = val def children(self): def rec(node): if node['m_ptr']: cell = node['m_ptr'].dereference() for i in rec(cell['m_left']): yield i yield ('', cell['m_value']) for i in rec(cell['m_right']): yield i return rec(self.val['m_root']) def to_string(self): return 'lean::rb_tree' # full type is way too verbose def display_hint(self): return 'array' class LeanRBMapPrinter: """Print a lean::rb_map object.""" def __init__(self, val): self.val = val def children(self): for (_, child) in LeanRBTreePrinter(self.val['m_map']).children(): yield ('', child['first']) yield ('', child['second']) def to_string(self): return 'lean::rb_map' # full type is way too verbose def display_hint(self): return 'map' def build_pretty_printer(): pp = gdb.printing.RegexpCollectionPrettyPrinter("lean") pp.add_printer('object', '^lean::object$', LeanObjectPrinter) pp.add_printer('optional', '^lean::optional', LeanOptionalPrinter) pp.add_printer('name', '^lean::name$', LeanNamePrinter) pp.add_printer('expr', '^lean::expr$', LeanExprPrinter) #pp.add_printer('level', '^lean::level$', LeanLevelPrinter) #pp.add_printer('list', '^lean::list', LeanListPrinter) pp.add_printer('buffer', '^lean::buffer', LeanBufferPrinter) pp.add_printer('list_ref', '^lean::list_ref', LeanListRefPrinter) pp.add_printer('rb_tree', '^lean::rb_tree', LeanRBTreePrinter) pp.add_printer('rb_map', '^lean::rb_map', LeanRBMapPrinter) return pp def register(): gdb.printing.register_pretty_printer( gdb.current_objfile(), build_pretty_printer(), replace=True) register()