def massage_input_and_call( cmd: Command, 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 cmd.input_type is None: yield from cmd.call(objs) return # If this Command doesn't expect a pointer, just call(). expected_type = target.get_type(cmd.input_type) if expected_type.kind is not drgn.TypeKind.POINTER: yield from cmd.call(objs) return first_obj_type, objs = 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): yield from execute_pipeline(objs, [Cast([cmd.input_type]), cmd]) return # If we are passed a foo_t when we expect a foo_t*, use its address. if target.get_pointer_type(first_obj_type) == expected_type: yield from execute_pipeline(objs, [Address(), cmd]) return yield from cmd.call(objs)
def __init__(self, args: str = "", name: str = "_") -> None: super().__init__(args, name) if not self.args.type: self.parser.error("the following arguments are required: <type>") tname = " ".join(self.args.type) try: self.type = target.get_type(tname) except LookupError: raise CommandError(self.name, f"could not find type '{tname}'")
def caller(self, objs: Iterable[drgn.Object]) -> Iterable[drgn.Object]: """ This method will dispatch to the appropriate instance function based on the type of the input we receive. """ out_type = None if self.output_type is not None: out_type = target.get_type(self.output_type) baked = dict() for (_, method) in inspect.getmembers(self, inspect.ismethod): if not hasattr(method, "input_typename_handled"): continue baked[type_canonicalize_name( method.input_typename_handled)] = method if self.isfirst: assert not objs yield from self.no_input() return for i in objs: obj_type_name = type_canonical_name(i.type_) # try subclass-specified input types first, so that they can # override any other behavior if obj_type_name in baked: yield from baked[obj_type_name](i) continue # try passthrough of output type # note, this may also be handled by subclass-specified input types if obj_type_name == type_canonical_name(out_type): yield i continue # try walkers if out_type is not None: try: # pylint: disable=protected-access for obj in Walk()._call([i]): yield drgn.cast(out_type, obj) continue except CommandError: pass # error raise CommandError( self.name, 'no handler for input of type {}'.format(i.type_))
def _call(self, objs: Iterable[drgn.Object]) -> Iterable[drgn.Object]: """ This function will call walk() on each input object, verifying the types as we go. """ assert self.input_type is not None type_ = target.get_type(self.input_type) for obj in objs: if obj.type_ != type_: raise CommandError( self.name, 'expected input of type {}, but received {}'.format( type_, obj.type_)) yield from self.walk(obj)