def pretty_print(self, objs: Iterable[drgn.Object]) -> None: # RangeTreeSeg is a SingleInputCommand, and it's like a pretty-printer # for range_seg*_t's, but since it has no `names`, it can't be invoked # from the command line. The reason is that range_seg*_t's specify their # ranges relative to rt_start/rt_shift, which are not accessible from # the range_seg*_t. Therefore, they can only be pretty-printed as part # of a range_tree_t*, from the range_tree pretty-printer. class RangeTreeSeg(sdb.SingleInputCommand): def __init__(self, rt: drgn.Object): super().__init__() self.rt = rt def _call_one(self, obj: drgn.Object) -> None: start = (obj.rs_start << self.rt.rt_shift) + self.rt.rt_start end = (obj.rs_end << self.rt.rt_shift) + self.rt.rt_start if hasattr(self.rt, 'rs_fill'): fill = obj.rs_fill << self.rt.rt_shift print(f" [{hex(start)} {hex(end)}) " f"(length {hex(end - start)}) " f"(fill {hex(fill)})") else: print(f" [{hex(start)} {hex(end)}) " f"(length {hex(end - start)})") for rt in objs: print(f"{hex(rt)}: range tree of {int(rt.rt_root.bt_num_elems)} " f"entries, {int(rt.rt_space)} bytes") for _ in sdb.execute_pipeline( [rt], [RangeSeg(), RangeTreeSeg(rt)]): pass
def pretty_print(self, vdevs: Iterable[drgn.Object], indent: int = 0) -> None: print( "".ljust(indent), "ADDR".ljust(18), "STATE".ljust(7), "AUX".ljust(4), "DESCRIPTION", ) print("".ljust(indent), "-" * 60) for vdev in vdevs: level = 0 pvd = vdev.vdev_parent while pvd: level += 2 pvd = pvd.vdev_parent if int(vdev.vdev_path) != 0: print( "".ljust(indent), hex(vdev).ljust(18), enum_lookup("vdev_state_t", vdev.vdev_state).ljust(7), enum_lookup("vdev_aux_t", vdev.vdev_stat.vs_aux).ljust(4), "".ljust(level), vdev.vdev_path.string_().decode("utf-8"), ) else: print( "".ljust(indent), hex(vdev).ljust(18), enum_lookup("vdev_state_t", vdev.vdev_state).ljust(7), enum_lookup("vdev_aux_t", vdev.vdev_stat.vs_aux).ljust(4), "".ljust(level), vdev.vdev_ops.vdev_op_type.string_().decode("utf-8"), ) if self.args.histogram: metaslabs = sdb.execute_pipeline([vdev], [Metaslab()]) histsum, shift = self.sum_histograms(metaslabs) if shift > 0: ZFSHistogram.print_histogram(histsum, shift, indent + 5) if self.args.metaslab: metaslabs = sdb.execute_pipeline([vdev], [Metaslab()]) Metaslab(self.arg_list).pretty_print(metaslabs, indent + 5)
def print_indented(self, vdevs: Iterable[drgn.Object], indent: int = 0) -> None: print( "".ljust(indent), "ADDR".ljust(18), "STATE".ljust(7), "AUX".ljust(4), "DESCRIPTION", ) print("".ljust(indent), "-" * 60) prev = None for vdev in vdevs: level = 0 pvd = vdev.vdev_parent while pvd: level += 2 pvd = pvd.vdev_parent if vdev.vdev_isl2cache and prev and not prev.vdev_isl2cache: print("".ljust(indent), "-".ljust(18), "-".ljust(7), "-".ljust(4), "".ljust(0), "cache") if vdev.vdev_islog and prev and not prev.vdev_islog: print("".ljust(indent), "-".ljust(18), "-".ljust(7), "-".ljust(4), "".ljust(0), "logs") if vdev.vdev_isspare and prev and not prev.vdev_isspare: print("".ljust(indent), "-".ljust(18), "-".ljust(7), "-".ljust(4), "".ljust(0), "spares") if vdev.vdev_isl2cache or vdev.vdev_isspare: level = 2 if int(vdev.vdev_path) != 0: print( "".ljust(indent), hex(vdev).ljust(18), enum_lookup("vdev_state_t", vdev.vdev_state).ljust(7), enum_lookup("vdev_aux_t", vdev.vdev_stat.vs_aux).ljust(4), "".ljust(level), vdev.vdev_path.string_().decode("utf-8"), ) else: print( "".ljust(indent), hex(vdev).ljust(18), enum_lookup("vdev_state_t", vdev.vdev_state).ljust(7), enum_lookup("vdev_aux_t", vdev.vdev_stat.vs_aux).ljust(4), "".ljust(level), vdev.vdev_ops.vdev_op_type.string_().decode("utf-8"), ) if self.args.histogram: if not sdb.is_null(vdev.vdev_mg): ZFSHistogram.print_histogram(vdev.vdev_mg.mg_histogram, 0, indent + 5) prev = vdev if self.args.metaslab: metaslabs = sdb.execute_pipeline([vdev], [Metaslab()]) Metaslab(self.arg_list).print_indented(metaslabs, indent + 5)
def pretty_print(self, spas): print("{:18} {}".format("ADDR", "NAME")) print("%s" % ("-" * 60)) for spa in spas: print("{:18} {}".format(hex(spa), spa.spa_name.string_().decode("utf-8"))) if self.args.vdevs: vdevs = sdb.execute_pipeline([spa], [Vdev()]) Vdev(self.arg_string).pretty_print(vdevs, 5)
def no_input(self): spas = sdb.execute_pipeline( [sdb.get_object("spa_namespace_avl").address_of_()], [Avl(), sdb.Cast("spa_t *")], ) for spa in spas: if (self.args.poolnames and spa.spa_name.string_().decode("utf-8") not in self.args.poolnames): continue yield spa
def no_input(self) -> Iterable[drgn.Object]: proc_list = self.prog["zfs_dbgmsgs"].pl_list list_addr = proc_list.address_of_() # pylint: disable=C0330 for obj in sdb.execute_pipeline( self.prog, [list_addr], [SPLList(self.prog), Cast(self.prog, "zfs_dbgmsg_t *")]): yield obj
def massage_input_and_call(self, objs: Iterable[drgn.Object] ) -> Iterable[drgn.Object]: """ Commands can declare that they accept input of type "foo_t*" by setting their input_type. They can be passed input of type "void *" or "foo_t" and this method will automatically convert the input objects to the expected type (foo_t*). """ # If this Command doesn't expect any particular type, just call(). if self.input_type is None: yield from self._call_and_yield(objs) return # If this Command doesn't expect a pointer, just call(). expected_type = sdb.prog.type(self.input_type) if expected_type.kind is not drgn.TypeKind.POINTER: yield from self._call_and_yield(objs) return first_obj_type, objs = sdb.get_first_type(objs) if first_obj_type is not None: # If we are passed a void*, cast it to the expected type. if (first_obj_type.kind is drgn.TypeKind.POINTER and first_obj_type.type.primitive is drgn.PrimitiveType.C_VOID): # pylint: disable=import-outside-toplevel # # The reason we have to import here is that putting the the # import at the top-level hits a cyclic import error which # breaks everything. We may need to redesign how we do imports. from sdb.commands.cast import Cast yield from sdb.execute_pipeline(objs, [Cast(self.input_type), self]) return # If we are passed a foo_t when we expect a foo_t*, use its address. if sdb.prog.pointer_type(first_obj_type) == expected_type: # pylint: disable=import-outside-toplevel from sdb.commands.address import Address yield from sdb.execute_pipeline(objs, [Address(), self]) return yield from self._call_and_yield(objs)
def from_range_tree(self, rt: drgn.Object) -> Iterable[drgn.Object]: enum_dict = dict(sdb.get_type('enum range_seg_type').enumerators) range_seg_type_to_type = { enum_dict['RANGE_SEG32']: 'range_seg32_t*', enum_dict['RANGE_SEG64']: 'range_seg64_t*', enum_dict['RANGE_SEG_GAP']: 'range_seg_gap_t*', } seg_type_name = range_seg_type_to_type[int(rt.rt_type)] yield from sdb.execute_pipeline([rt.rt_root.address_of_()], [Btree(), Cast(seg_type_name)])
def no_input(self): spas = sdb.execute_pipeline( self.prog, [self.prog["spa_namespace_avl"].address_of_()], [Avl(self.prog), Cast(self.prog, "spa_t *")], ) for spa in spas: if (self.args.poolnames and spa.spa_name.string_().decode("utf-8") not in self.args.poolnames): continue yield spa
def pretty_print(self, spas: Iterable[drgn.Object]) -> None: print("{:18} {}".format("ADDR", "NAME")) print("%s" % ("-" * 60)) for spa in spas: print("{:18} {}".format(hex(spa), spa.spa_name.string_().decode("utf-8"))) if self.args.histogram: ZFSHistogram.print_histogram(spa.spa_normal_class.mc_histogram, 0, 5) if self.args.vdevs or self.args.metaslab: vdevs = sdb.execute_pipeline([spa], [Vdev()]) Vdev(self.arg_list).pretty_print(vdevs, 5)
def pretty_print(self, vdevs, indent=0): print( "".ljust(indent), "ADDR".ljust(18), "STATE".ljust(7), "AUX".ljust(4), "DESCRIPTION", ) print("".ljust(indent), "-" * 60) for vdev in vdevs: level = 0 pvd = vdev.vdev_parent while pvd: level += 2 pvd = pvd.vdev_parent if int(vdev.vdev_path) != 0: print( "".ljust(indent), hex(vdev).ljust(18), enum_lookup(self.prog, "vdev_state_t", vdev.vdev_state).ljust(7), enum_lookup(self.prog, "vdev_aux_t", vdev.vdev_stat.vs_aux).ljust(4), "".ljust(level), vdev.vdev_path.string_().decode("utf-8"), ) else: print( "".ljust(indent), hex(vdev).ljust(18), enum_lookup(self.prog, "vdev_state_t", vdev.vdev_state).ljust(7), enum_lookup(self.prog, "vdev_aux_t", vdev.vdev_stat.vs_aux).ljust(4), "".ljust(level), vdev.vdev_ops.vdev_op_type.string_().decode("utf-8"), ) if self.args.metaslab: metaslabs = sdb.execute_pipeline(self.prog, [vdev], [Metaslab(self.prog)]) Metaslab(self.prog, self.arg_string).pretty_print(metaslabs, indent + 5)
def all_dnode_dbufs(self, dn: drgn.Object) -> Iterable[drgn.Object]: yield from sdb.execute_pipeline( [dn.dn_dbufs.address_of_()], [sdb.Walk(), sdb.Cast(self.output_type)])
def walk(self, obj: drgn.Object) -> Iterable[drgn.Object]: for i in range(obj.ml_num_sublists): sublist = obj.ml_sublists[i].mls_list.address_of_() yield from sdb.execute_pipeline([sublist], [SPLList()])
def no_input(self) -> Iterable[drgn.Object]: proc_list = sdb.get_object("zfs_dbgmsgs").pl_list list_addr = proc_list.address_of_() yield from sdb.execute_pipeline( [list_addr], [SPLList(), sdb.Cast(["zfs_dbgmsg_t *"])])