Exemple #1
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
Exemple #2
0
def btrfs_fs_info(super_block: gdb.Value, force: bool = False) -> gdb.Value:
    """
    Resolves a btrfs_fs_info from  a VFS superblock

    This method resolves a struct btrfs_fs_info from a struct super_block

    Args:
        super_block: The ``struct super_block`` to use to resolve a'
            ``struct btrfs_fs_info``.  A pointer to a ``struct super_block``
            is also acceptable.

        force: Ignore type checking.

    Returns:
        :obj:`gdb.Value: The resolved ``struct btrfs_fs_info``.  The value will
        be of type ``struct btrfs_fs_info``.

    Raises:
        :obj:`.InvalidArgumentError`: the super_block does not belong to btrfs
        :obj:`gdb.NotAvailableError`: The target value was not available.
    """
    if not force and not is_btrfs_super(super_block):
        raise InvalidArgumentError("super_block does not belong to btrfs")

    fs_info = super_block['s_fs_info'].cast(types.btrfs_fs_info_p_type)
    return fs_info.dereference()
Exemple #3
0
    def _resolve_percpu_var(self, symvar: SymbolOrValue) -> gdb.Value:
        orig_var = symvar
        if isinstance(symvar, gdb.Symbol):
            var = symvar.value()
        else:
            var = symvar
        if not isinstance(var, gdb.Value):
            raise InvalidArgumentError(
                "Argument must be gdb.Symbol or gdb.Value")

        if var.type.code == gdb.TYPE_CODE_PTR:
            # The percpu contains pointers
            if var.address is not None and self.is_percpu_var(var.address):
                var = var.address
            # Pointer to a percpu
            elif self.is_percpu_var(var):
                if var.type != types.void_p_type:
                    var = var.dereference().address
                assert self.is_percpu_var(var)
            else:
                raise PerCPUError(orig_var)
        # object is a percpu
        elif self.is_percpu_var(var.address):
            var = var.address
        else:
            raise PerCPUError(orig_var)

        return var
Exemple #4
0
def percpu_counter_sum(var: SymbolOrValue) -> int:
    """
    Returns the sum of a percpu counter

    Args:
        var: The percpu counter to sum.  The value must be of type
            ``struct percpu_counter``.

    Returns:
        :obj:`int`: the sum of all components of the percpu counter
    """
    if isinstance(var, gdb.Symbol):
        var = var.value()

    if not (var.type == types.percpu_counter_type or
            (var.type.code == gdb.TYPE_CODE_PTR
             and var.type.target() == types.percpu_counter_type)):
        raise InvalidArgumentError(
            "var must be gdb.Symbol or gdb.Value describing `{}' not `{}'".
            format(types.percpu_counter_type, var.type))

    total = int(var['count'])

    v = get_percpu_vars(var['counters'])
    for cpu in v:
        total += int(v[cpu])

    return total
Exemple #5
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()))
Exemple #6
0
    def _setup_roots(self,
                     roots: PathSpecifier = None,
                     verbose: bool = False) -> None:
        if roots is None:
            self.roots = ["/"]
        elif isinstance(roots, list) and roots and isinstance(roots[0], str):
            x = None
            for root in roots:
                if os.path.exists(root):
                    if x is None:
                        x = [root]
                    else:
                        x.append(root)
                else:
                    print("root {} does not exist".format(root))

            if x is None:
                x = ["/"]
            self.roots = x
        elif isinstance(roots, str):
            x = None
            if os.path.exists(roots):
                if x is None:
                    x = [roots]
                else:
                    x.append(roots)
            if x is None:
                x = ["/"]
            self.roots = x
        else:
            raise InvalidArgumentError(
                "roots must be None, str, or list of str")
        if verbose:
            print("roots={}".format(self.roots))
Exemple #7
0
def _check_bitmap_type(bitmap: gdb.Value) -> None:
    if ((bitmap.type.code != gdb.TYPE_CODE_ARRAY
         or bitmap[0].type.code != types.unsigned_long_type.code
         or bitmap[0].type.sizeof != types.unsigned_long_type.sizeof) and
        (bitmap.type.code != gdb.TYPE_CODE_PTR
         or bitmap.type.target().code != types.unsigned_long_type.code
         or bitmap.type.target().sizeof != types.unsigned_long_type.sizeof)):
        raise InvalidArgumentError(
            "bitmaps are expected to be arrays of unsigned long not `{}'".
            format(bitmap.type))
Exemple #8
0
    def set_active(self, cpu: int, regs: Dict[str, int]) -> None:
        """
        Set this task as active in the debugging environment

        Args:
            cpu: Which CPU this task was using
            regs: The registers associated with this task

        Raises:
            :obj:`.InvalidArgumentError`: The cpu was not a valid integer.
        """
        if not (isinstance(cpu, int) and cpu >= 0):
            raise InvalidArgumentError("cpu must be integer >= 0")

        self.active = True
        self.cpu = cpu
        self.regs = regs
    def _get_percpu_var(self, symvar: SymbolOrValue, cpu: int) -> gdb.Value:
        if isinstance(symvar, (gdb.Symbol, gdb.MinSymbol)):
            var = symvar.value()
        else:
            var = symvar
        if not isinstance(var, gdb.Value):
            raise InvalidArgumentError("Argument must be gdb.Symbol or gdb.Value")
        if cpu < 0:
            raise ValueError("cpu must be >= 0")

        addr = symvals['__per_cpu_offset'][cpu]
        if addr > 0:
            addr += self._relocated_offset(var)

        val = gdb.Value(addr).cast(var.type)
        if var.type != types.void_p_type:
            val = val.dereference()
        return val
Exemple #10
0
def for_each_child(kn: gdb.Value) -> Iterable[gdb.Value]:
    """
    Iterates over all child nodes of given kernfs_node.

    Args:
        kn: ``struct kernfs_node`` of directory type

    Yields:
        gdb.Value: ``struct kernfs_node``

    Raises:
        :obj:`.InvalidArgumentError`: kernfs_node is not a directory
    """
    if int(kn['flags']) & KERNFS_DIR == 0:
        raise InvalidArgumentError(
            f"kernfs_node at {kn.address} is not a directory")

    return rbtree_postorder_for_each_entry(kn['dir']['children'],
                                           types.kernfs_node_type, 'rb')
Exemple #11
0
def item_to_quotaoff_log_item(item: gdb.Value) -> gdb.Value:
    """
    Converts an xfs_log_item to an xfs_quotaoff_log_item

    Args:
        item: The log item to convert.  The value must be of type
            ``struct xfs_log_item``.

    Returns:
        :obj:`gdb.Value`: The converted log item.  The value will be of
        type ``struct xfs_quotaoff_log_item``

    Raises:
        InvalidArgumentError: The type of log item is not ``XFS_LI_QUOTAOFF``
        :obj:`gdb.NotAvailableError`: The target value was not available.
    """
    if item['li_type'] != XFS_LI_QUOTAOFF:
        raise InvalidArgumentError("item is not an QUOTAOFF log item")
    return container_of(item, types.xfs_qoff_logitem_type, 'qql_item')
Exemple #12
0
def for_each_block_device(subtype: gdb.Value = None) -> Iterable[gdb.Value]:
    """
    Iterates over each block device registered with the block class.

    This method iterates over the block_class klist and yields every
    member found.  The members are either struct gendisk or
    struct hd_struct, depending on whether it describes an entire
    disk or a partition, respectively.

    The members can be filtered by providing a subtype, which
    corresponds to a the the type field of the struct device.

    Args:
        subtype (optional): The ``struct device_type`` that will be used
            to match and filter.  Typically the values associated with
            the ``disk_type`` or ``part_type`` :obj:`gdb.Symbol`.

    Yields:
        :obj:`gdb.Value`:  The next block device that matches the subtype.
        The value is of type ``struct gendisk`` or ``struct hd_struct``.

    Raises:
        :obj:`RuntimeError`: An unknown device type was encountered
            during iteration.
        :obj:`TypeError`: The provided subtype was not of
            ``struct device_type`` or ``struct device type *``
    """

    if subtype:
        if get_basic_type(subtype.type) == types.device_type_type:
            subtype = subtype.address
        elif get_basic_type(subtype.type) != types.device_type_type.pointer():
            raise InvalidArgumentError("subtype must be {} not {}".format(
                types.device_type_type.pointer(), subtype.type.unqualified()))
    for dev in for_each_class_device(symvals.block_class, subtype):
        if dev['type'] == symvals.disk_type.address:
            yield dev_to_gendisk(dev)
        elif dev['type'] == symvals.part_type.address:
            yield dev_to_part(dev)
        else:
            raise RuntimeError("Encountered unexpected device type {}".format(
                dev['type']))
Exemple #13
0
def inode_to_block_device(inode: gdb.Value) -> gdb.Value:
    """
    Returns the block device associated with this inode.

    If the inode describes a block device, return that block device.
    Otherwise, raise InvalidArgumentError.

    Args:
        inode: The ``struct inode`` for which to return the associated
            block device.  The value must be of type ``struct inode``.

    Returns:
        :obj:`gdb.Value`: The ``struct block_device`` associated with the
        provided ``struct inode``.  The value is of type
        ``struct block_device``.

    Raises:
        :obj:`.InvalidArgumentError`: inode does not describe a block device
    """
    if inode['i_sb'] != symvals.blockdev_superblock:
        raise InvalidArgumentError("inode does not correspond to block device")
    return container_of(inode, types.bdev_inode_type, 'vfs_inode')['bdev']
Exemple #14
0
def xfs_mount(sb: gdb.Value, force: bool = False) -> gdb.Value:
    """
    Converts a VFS superblock to a xfs mount

    This method converts a ``struct super_block`` to a ``struct xfs_mount *``

    Args:
        super_block: The struct super_block to convert to a
            ``struct xfs_fs_info``.  The value must be of type
            ``struct super_block``.

    Returns:
        :obj:`gdb.Value`: The converted ``struct xfs_mount``.  The value will be
        of type ``struct xfs_mount *``.

    Raises:
        InvalidArgumentError: The ``struct super_block`` does not belong to xfs
        :obj:`gdb.NotAvailableError`: The target value was not available.
    """
    if not force and not is_xfs_super(sb):
        raise InvalidArgumentError("superblock does not belong to xfs")

    return sb['s_fs_info'].cast(types.xfs_mount_p_type)
Exemple #15
0
    def _setup_module_debuginfo_path(
            self,
            module_debuginfo_path: PathSpecifier = None,
            verbose: bool = False) -> None:
        x: List[str] = []
        if module_debuginfo_path is None:
            defaults = [
                "modules.debug",
                "lib/modules/{}".format(self.version),
            ]

            self.module_debuginfo_path = self._find_debuginfo_paths(defaults)
        elif (isinstance(module_debuginfo_path, list)
              and isinstance(module_debuginfo_path[0], str)):

            for root in self.roots:
                for mpath in module_debuginfo_path:
                    path = "{}/{}".format(root, mpath)
                    if os.path.exists(path):
                        x.append(path)

            self.module_debuginfo_path = x
        elif isinstance(module_debuginfo_path, str):

            for root in self.roots:
                path = "{}/{}".format(root, module_debuginfo_path)
                if os.path.exists(path):
                    x.append(path)

            self.module_debuginfo_path = x
        else:
            raise InvalidArgumentError(
                "module_debuginfo_path must be None, str, or list of str")

        if verbose:
            print("module_debuginfo_path={}".format(
                self.module_debuginfo_path))
Exemple #16
0
def xfs_inode(vfs_inode: gdb.Value, force: bool = False) -> gdb.Value:
    """
    Converts a VFS inode to a xfs inode

    This method converts a ``struct inode`` to a ``struct xfs_inode``.

    Args:
        vfs_inode: The ``struct inode`` to convert to a ``struct xfs_inode``
            The value must be of type ``struct inode``.

        force: ignore type checking

    Returns:
        :obj:`gdb.Value`: The converted ``struct xfs_inode``.  The value
        will be of type ``struct xfs_inode``.

    Raises:
        TypeError: The inode does not belong to xfs
        :obj:`gdb.NotAvailableError`: The target value was not available.
    """
    if not force and not is_xfs_inode(vfs_inode):
        raise InvalidArgumentError("inode does not belong to xfs")

    return container_of(vfs_inode, types.xfs_inode, 'i_vnode')
Exemple #17
0
    def _setup_vmlinux_debuginfo(self,
                                 vmlinux_debuginfo: PathSpecifier = None,
                                 verbose: bool = False) -> None:
        if vmlinux_debuginfo is None:
            defaults = [
                "{}.debug".format(self.kernel),
                "vmlinux-{}.debug".format(self.version),
                "boot/{}.debug".format(os.path.basename(self.kernel)),
                "boot/vmlinux-{}.debug".format(self.version),
            ]

            self.vmlinux_debuginfo = self._find_debuginfo_paths(defaults)

        elif (isinstance(vmlinux_debuginfo, list) and vmlinux_debuginfo
              and isinstance(vmlinux_debuginfo[0], str)):
            self.vmlinux_debuginfo = vmlinux_debuginfo
        elif isinstance(vmlinux_debuginfo, str):
            self.vmlinux_debuginfo = [vmlinux_debuginfo]
        else:
            raise InvalidArgumentError(
                "vmlinux_debuginfo must be None, str, or list of str")

        if verbose:
            print("vmlinux_debuginfo={}".format(self.vmlinux_debuginfo))
Exemple #18
0
def _check_queue_type(queue: gdb.Value) -> None:
    if not queue_is_mq(queue):
        raise InvalidArgumentError(
            "Passed request queue is not a multiqueue queue")