示例#1
0
def rbtree_postorder_for_each(root: gdb.Value) -> Iterable[gdb.Value]:
    """
    Iterate over nodes of a rooted RB tree in post-order fashion

    Args:
        root: The tree to iterate.  The value must be of type
            ``struct rb_root`` or ``struct rb_root *``.

    Yields:
        gdb.Value: The next node of the tree. The value is
        of type ``struct rb_node``.

    Raises:
        :obj:`.CorruptTreeError`: the list is corrupted
    """
    if not isinstance(root, gdb.Value):
        raise ArgumentTypeError('root', root, gdb.Value)
    if root.type == types.rb_root_type.pointer():
        root = root.dereference()
    elif root.type != types.rb_root_type:
        raise UnexpectedGDBTypeError('root', root, types.rb_root_type)

    if root.type is not types.rb_root_type:
        types.override('struct rb_root', root.type)

    if int(root.address) == 0:
        raise CorruptTreeError("root is NULL pointer")

    node = _rb_left_deepest_node(root['rb_node'])

    while node is not None:
        yield node.dereference()
        node = _rb_next_postorder(node)
示例#2
0
    def _init_task_types(cls, task: gdb.Value) -> None:
        if not cls._valid:
            t = types.task_struct_type
            if task.type != t:
                raise UnexpectedGDBTypeError('task', task, t)

            # Using a type within the same context makes things a *lot* faster
            # This works around a shortcoming in gdb.  A type lookup and
            # a type resolved from a symbol will be different structures
            # within gdb.  Equality requires a deep comparison rather than
            # a simple pointer comparison.
            types.override('struct task_struct', task.type)
            fields = types.task_struct_type.fields()
            cls._task_state_has_exit_state = 'exit_state' in fields
            cls._pick_get_rss()
            cls._pick_last_run()
            cls._valid = True
示例#3
0
    def __init__(self, task_struct: gdb.Value) -> None:
        self._init_task_types(task_struct)

        if not isinstance(task_struct, gdb.Value):
            raise ArgumentTypeError('task_struct', task_struct, gdb.Value)

        if not (task_struct.type == types.task_struct_type or
                task_struct.type == types.task_struct_type.pointer()):
            raise UnexpectedGDBTypeError('task_struct', task_struct,
                                         types.task_struct_type)

        self.task_struct = task_struct
        self.active = False
        self.cpu = -1
        self.regs: Dict[str, int] = dict()

        self.thread_info: gdb.Value
        self.thread: gdb.InferiorThread

        # mem data
        self.mem_valid = False
        self.rss = 0
        self.total_vm = 0
        self.pgd_addr = 0
示例#4
0
def list_for_each(list_head: gdb.Value,
                  include_head: bool = False,
                  reverse: bool = False,
                  print_broken_links: bool = True,
                  exact_cycles: bool = False) -> Iterator[gdb.Value]:
    """
    Iterate over a list and yield each node

    Args:
        list_head: The list to iterate.  The value must be of type
            ``struct list_head`` or ``struct list_head *``.
        include_head (optional): Include the head of the list in
            iteration - useful for lists with no anchors
        reverse (optional): Iterate the list in reverse order
            (follow the ``prev`` links)
        print_broken_links (optional): Print warnings about broken links
        exact_cycles (optional): Detect and raise an exception if
            a cycle is detected in the list

    Yields:
        gdb.Value: The next node in the list.  The value is
        of type ``struct list_head``.

    Raises:
        :obj:`.CorruptListError`: the list is corrupted
        :obj:`.ListCycleError`: the list contains cycles
        :obj:`BufferError`: portions of the list cannot be read
        :obj:`gdb.NotAvailableError`: The target value is not available.
    """
    pending_exception = None
    if not isinstance(list_head, gdb.Value):
        raise ArgumentTypeError('list_head', list_head, gdb.Value)
    if list_head.type == types.list_head_type.pointer():
        list_head = list_head.dereference()
    elif list_head.type != types.list_head_type:
        raise UnexpectedGDBTypeError('list_head', list_head,
                                     types.list_head_type)
    if list_head.type is not types.list_head_type:
        types.override('struct list_head', list_head.type)
    fast = None
    if int(list_head.address) == 0:
        raise CorruptListError("list_head is NULL pointer.")

    next_ = 'next'
    prev_ = 'prev'
    if reverse:
        next_ = 'prev'
        prev_ = 'next'

    if exact_cycles:
        visited: Set[int] = set()

    if include_head:
        yield list_head

    try:
        nxt = list_head[next_]
        prev = list_head
        if int(nxt) == 0:
            raise CorruptListError("{} pointer is NULL".format(next_))
        node = nxt.dereference()
    except gdb.error as e:
        raise BufferError("Failed to read list_head {:#x}: {}".format(
            int(list_head.address), str(e))) from e

    last_good_addr = None
    while node.address != list_head.address:
        if exact_cycles:
            if int(node.address) in visited:
                raise ListCycleError("Cycle in list detected.")
            visited.add(int(node.address))
        try:
            if int(prev.address) != int(node[prev_]):
                error = f"broken {prev_} link {int(prev.address):#x} "
                error += f"-{next_}-> {int(node.address):#x} "
                error += f"-{prev_}-> {int(node[prev_]):#x}"
                pending_exception = CorruptListError(error)
                if print_broken_links:
                    print(error)
                # broken prev link means there might be a cycle that
                # does not include the initial head, so start detecting
                # cycles
                if not exact_cycles and fast is None:
                    fast = node
            nxt = node[next_]
            # only yield after trying to read something from the node, no
            # point in giving out bogus list elements
            yield node
        except gdb.error as e:
            if last_good_addr is not None:
                last_good_str = f"0x{last_good_addr:x}"
            else:
                last_good_str = "(none)"
            raise BufferError(
                f"Failed to read list_head 0x{int(node.address):x} "
                f"in list 0x{int(list_head.address):x}, last good "
                f"list_head {last_good_str}: {str(e)}") from e

        try:
            if fast is not None:
                # are we detecting cycles? advance fast 2 times and compare
                # each with our current node (Floyd's Tortoise and Hare
                # algorithm)
                for i in range(2):  # pylint: disable=unused-variable
                    fast = fast[next_].dereference()
                    if int(node.address) == int(fast.address):
                        raise ListCycleError("Cycle in list detected.")
        except gdb.error:
            # we hit an unreadable element, so just stop detecting cycles
            # and the slow iterator will hit it as well
            fast = None

        prev = node
        if int(nxt) == 0:
            raise CorruptListError("{} -> {} pointer is NULL".format(
                node.address, next_))
        last_good_addr = int(node.address)
        node = nxt.dereference()

    if pending_exception is not None:
        # The pylint error seems to think we'll raise None here
        raise pending_exception  # pylint: disable=raising-bad-type