Пример #1
0
 def __invalid_memory_objects_check(self, objs: Iterable[drgn.Object],
                                    fatal: bool) -> Iterable[drgn.Object]:
     """
     A filter method for objects passed through the pipeline that
     are backed by invalid memory. When `fatal` is set to True
     we raise an error which will stop this control flow when
     such objects are encountered. If `fatal` is False we just
     print the error and go on.
     """
     for obj in objs:
         try:
             obj.read_()
         except drgn.FaultError as err:
             if obj.address_ is None:
                 #
                 # This is possible when the object was created `echo`.
                 #
                 err_msg = str(err)
             else:
                 err_msg = f"addresss {hex(obj.address_of_().value_())}"
             err = CommandError(self.name,
                                f"invalid memory access: {err_msg}")
             if fatal:
                 raise err
             print(err.text)
             continue
         yield obj
Пример #2
0
 def _call(self, objs: Iterable[drgn.Object]) -> Iterable[drgn.Object]:
     for obj in objs:
         #
         # We canonicalize the type just in case it is a typedef
         # to a pointer (e.g. typedef char* char_p).
         #
         obj_type = type_canonicalize(obj.type_)
         if obj_type.kind != drgn.TypeKind.POINTER:
             raise CommandError(
                 self.name,
                 f"'{obj.type_.type_name()}' is not a valid pointer type")
         if obj_type.type.type_name() == 'void':
             raise CommandError(self.name,
                                "cannot dereference a void pointer")
         yield drgn.Object(get_prog(),
                           type=obj.type_.type,
                           address=obj.value_())
Пример #3
0
    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}'")
Пример #4
0
    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_))
Пример #5
0
    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)
Пример #6
0
 def check_input_type(self,
                      objs: Iterable[drgn.Object]) -> Iterable[drgn.Object]:
     """
     This function acts as a generator, checking that each passed object
     matches the input type for the command
     """
     assert self.input_type is not None
     type_name = type_canonicalize_name(self.input_type)
     for obj in objs:
         if type_canonical_name(obj.type_) != type_name:
             raise CommandError(
                 self.name,
                 f'expected input of type {self.input_type}, but received '
                 f'type {obj.type_}')
         yield obj
Пример #7
0
    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
        expected_type = type_canonicalize_name(self.input_type)
        for obj in objs:
            if type_canonical_name(obj.type_) != expected_type:
                raise CommandError(
                    self.name,
                    'expected input of type {}, but received {}'.format(
                        expected_type, type_canonical_name(obj.type_)))

            yield from self.walk(obj)
Пример #8
0
    def _call(  # type: ignore[return]
            self,
            objs: Iterable[drgn.Object]) -> Optional[Iterable[drgn.Object]]:
        """
        This function will call pretty_print() on each input object,
        verifying the types as we go.
        """

        assert self.input_type is not None
        type_name = type_canonicalize_name(self.input_type)
        for obj in objs:
            if type_canonical_name(obj.type_) != type_name:
                raise CommandError(
                    self.name,
                    f'exepected input of type {self.input_type}, but received '
                    f'type {obj.type_}')

            self.pretty_print([obj])
Пример #9
0
    def _call(self, objs: Iterable[drgn.Object]) -> Iterable[drgn.Object]:
        baked = {
            type_canonicalize_name(type_): class_
            for type_, class_ in Walker.allWalkers.items()
        }
        has_input = False
        for i in objs:
            has_input = True
            this_type_name = type_canonical_name(i.type_)
            if this_type_name not in baked:
                raise CommandError(self.name, Walk._help_message(i.type_))

            yield from baked[this_type_name]().walk(i)

        # If we got no input and we're the last thing in the pipeline, we're
        # probably the first thing in the pipeline. Print out the available
        # walkers.
        if not has_input and self.islast:
            print(Walk._help_message())
Пример #10
0
 def call(self, objs: Iterable[drgn.Object]) -> Iterable[drgn.Object]:
     # pylint: disable=missing-docstring
     #
     # Even though we have __invalid_memory_objects_check() to
     # ensure that the objects returned are valid, we still
     # need to account for invalid accesses happening while
     # the command is running.
     #
     try:
         result = self._call(objs)
         if result is not None:
             #
             # The whole point of the SingleInputCommands are that
             # they don't stop executing in the first encounter of
             # a bad dereference. That's why we check here whether
             # the command that we are running is a subclass of
             # SingleInputCommand and we set the `fatal` flag
             # accordinly.
             #
             yield from self.__invalid_memory_objects_check(
                 result, not issubclass(self.__class__, SingleInputCommand))
     except drgn.FaultError as err:
         raise CommandError(self.name, f"invalid memory access: {str(err)}")
Пример #11
0
 def _call(self, objs: Iterable[drgn.Object]) -> Iterable[drgn.Object]:
     for obj in objs:
         #
         # Even though we have __invalid_memory_objects_check() to
         # ensure that the objects returned are valid, we still
         # need to account for invalid accesses happening while
         # the command is running.
         #
         result = None
         try:
             result = self._call_one(obj)
         except drgn.FaultError as err:
             if obj.address_ is None:
                 #
                 # This is possible when the object was created `echo`.
                 #
                 err_msg = f"invalid memory access: {str(err)}"
             else:
                 err_msg = "invalid memory access while handling object "
                 err_msg += "at address {hex(obj.address_of_().value_())}"
             cmd_err = CommandError(self.name, err_msg)
             print(cmd_err.text)
         if result is not None:
             yield from result
Пример #12
0
 def no_input(self) -> Iterable[drgn.Object]:
     # pylint: disable=missing-docstring
     raise CommandError(self.name, 'command requires an input')
Пример #13
0
 def _call(self, objs: Iterable[drgn.Object]) -> Iterable[drgn.Object]:
     for obj in objs:
         try:
             yield drgn.cast(self.type, obj)
         except TypeError as err:
             raise CommandError(self.name, str(err))