Example #1
0
def gendisk_name(gendisk: gdb.Value) -> str:
    """
    Returns the name of the provided block device.

    This method evaluates the block device and returns the name,
    including partition number, if applicable.

    Args:
        gendisk: A ``struct gendisk`` or ``struct hd_struct`` for which to
            return the name.  The value must be of type ``struct gendisk``
            or ``struct hd_struct``.

    Returns:
        :obj:`str`: The name of the block device

    Raises:
        :obj:`.InvalidArgumentError`: gendisk does not describe a
            ``struct gendisk`` or ``struct hd_struct``
    """
    if gendisk.type.code == gdb.TYPE_CODE_PTR:
        gendisk = gendisk.dereference()

    if get_basic_type(gendisk.type) == types.gendisk_type:
        return gendisk['disk_name'].string()

    if get_basic_type(gendisk.type) == types.hd_struct_type:
        parent = dev_to_gendisk(part_to_dev(gendisk)['parent'])
        return "{}{:d}".format(gendisk_name(parent), int(gendisk['partno']))

    raise InvalidArgumentError("expected {} or {}, not {}".format(
        types.gendisk_type, types.hd_struct_type, gendisk.type.unqualified()))
Example #2
0
def klist_for_each(klist: gdb.Value) -> Iterable[gdb.Value]:
    """
    Iterate over a klist and yield each node

    Args:
        klist: The list to iterate.  The value must be of type
            ``struct klist`` or ``struct klist *``.

    Yields:
        :obj:`gdb.Value`: The next node in the list.  The value is of type
            ``struct klist_node``.
    """
    if klist.type == types.klist_type.pointer():
        klist = klist.dereference()
    elif klist.type != types.klist_type:
        raise InvalidArgumentError(
            "klist must be gdb.Value representing 'struct klist' or 'struct klist *' not {}"
            .format(klist.type))
    if klist.type is not types.klist_type:
        types.override('struct klist', klist.type)

    for node in list_for_each_entry(klist['k_list'], types.klist_node_type,
                                    'n_node'):
        if node['n_klist'] != klist.address:
            raise KlistCorruptedError("Corrupted")
        yield node
Example #3
0
def decode_uuid_t(value: gdb.Value) -> uuid.UUID:
    """
    Decode a Linux kernel uuid_t into a Python-style UUID object

    Args:
        value (gdb.Value): The uuid_t to be decoded

    Returns:
        uuid.UUID: The UUID object that describes the value

    Raises:
        TypeError: value is not gdb.Value<uuid_t>
    """
    if not isinstance(value, gdb.Value):
        raise TypeError("value must be gdb.Value")

    if value.type != types.uuid_t_type:
        if (value.type.code == gdb.TYPE_CODE_PTR
                and value.type.target() == types.uuid_t_type):
            value = value.dereference()
        else:
            raise TypeError("value must describe a uuid_t")

    if struct_has_member(types.uuid_t_type, 'b'):
        member = 'b'
    else:
        member = '__u_bits'

    return decode_uuid(value[member])
Example #4
0
def make_node_iterator(node_ptr: gdb.Value):
    """  """

    # Yield nodes, from left to right
    while node_ptr != 0:
        node = node_ptr.dereference()
        node_ptr = node['next']
        yield node['data']
def _to_ast_ptr(value: gdb.Value) -> gdb.Value:
    if value.type.code == gdb.TYPE_CODE_PTR:
        if value.type.target().name == "ast_t":
            return value
        else:
            return _to_ast_ptr(value.dereference())
    elif value.type.code == gdb.TYPE_CODE_TYPEDEF and value.type.name == "ast_ptr_t":
        return value
    raise ValueError
Example #6
0
    def show_one_mount(self, mnt: gdb.Value, args: argparse.Namespace) -> None:
        if mnt.type.code == gdb.TYPE_CODE_PTR:
            mnt = mnt.dereference()

        flags = ""
        if args.f:
            flags = " ({})".format(mount_flags(mnt))
        path = d_path(mnt, mount_root(mnt))
        if args.v:
            print("{:016x} {:016x}  {:<10} {:<16} {}"
                  .format(int(mnt.address), int(mount_super(mnt)),
                          mount_fstype(mnt), mount_device(mnt), path))
        else:
            print("{} on {} type {}{}"
                  .format(mount_device(mnt), path, mount_fstype(mnt), flags))
Example #7
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