Example #1
0
    def setup_page_type(cls, gdbtype: gdb.Type) -> None:
        # TODO: should check config, but that failed to work on ppc64, hardcode
        # 64k for now
        if crash.current_target().arch.name() == "powerpc:common64":
            cls.PAGE_SHIFT = 16
            # also a config
            cls.directmap_base = 0xc000000000000000

            cls.sparsemem = True
            cls.sparsemem_vmemmap = False
            cls.sparsemem_extreme = False
            cls.SECTION_SIZE_BITS = 24

        cls.PAGE_SIZE = 1 << cls.PAGE_SHIFT
        cls.PAGE_MASK = ~(cls.PAGE_SIZE - 1)

        cls.slab_cache_name = find_member_variant(gdbtype,
                                                  ['slab_cache', 'lru'])
        cls.slab_page_name = find_member_variant(gdbtype, ['slab_page', 'lru'])
        cls.compound_head_name = find_member_variant(
            gdbtype, ['compound_head', 'first_page'])
        if not hasattr(cls, 'vmemmap'):
            cls.vmemmap = gdb.Value(cls.vmemmap_base).cast(gdbtype.pointer())

        if struct_has_member(gdbtype, 'page_type'):
            cls._is_buddy = cls.__is_buddy_page_type
        else:
            cls._is_buddy = cls.__is_buddy_mapcount

        cls.setup_page_type_done = True
        if cls.setup_pageflags_done and not cls.setup_pageflags_finish_done:
            cls.setup_pageflags_finish()
Example #2
0
def _check_struct_request(request_s: gdb.Type) -> None:
    global _rq_in_flight
    if struct_has_member(request_s, 'rq_state'):

        def _rq_in_flight(request: gdb.Value) -> bool:
            return (request['rq_state'] !=
                    types.enum_mq_rq_state_type['MQ_RQ_IDLE'])
    elif struct_has_member(request_s, 'atomic_flags'):

        def _rq_in_flight(request: gdb.Value) -> bool:
            return (request['atomic_flags'] & (1 << int(
                types.enum_rq_atomic_flags_type['REQ_ATOM_STARTED'].enumval))
                    != 0)
    else:

        def _rq_in_flight(request: gdb.Value) -> bool:
            return request['cmd_flags'] & REQ_STARTED != 0  # type: ignore
Example #3
0
    def _pick_get_rss(cls) -> None:
        if struct_has_member(types.mm_struct_type, 'rss'):
            cls._get_rss = cls._get_rss_field
        elif struct_has_member(types.mm_struct_type, '_rss'):
            cls._get_rss = cls._get__rss_field
        elif struct_has_member(types.mm_struct_type, 'rss_stat'):
            cls._get_rss = cls._get_rss_stat_field
        else:
            if struct_has_member(types.mm_struct_type, '_file_rss'):
                cls._anon_file_rss_fields.append('_file_rss')

            if struct_has_member(types.mm_struct_type, '_anon_rss'):
                cls._anon_file_rss_fields.append('_anon_rss')

            cls._get_rss = cls._get_anon_file_rss_fields

            if not cls._anon_file_rss_fields:
                raise RuntimeError("No method to retrieve RSS from task found.")
Example #4
0
 def _setup_dynamic_offset_cache(self) -> None:
     # TODO: interval tree would be more efficient, but this adds no 3rd
     # party module dependency...
     use_area_map = struct_has_member(types.pcpu_chunk_type, 'map')
     for slot in range(symvals.pcpu_nr_slots):
         for chunk in list_for_each_entry(symvals.pcpu_slot[slot],
                                          types.pcpu_chunk_type, 'list'):
             if use_area_map:
                 self._setup_dynamic_offset_cache_area_map(chunk)
             else:
                 self._setup_dynamic_offset_cache_bitmap(chunk)
Example #5
0
    def execute(self, args: argparse.Namespace) -> None:
        regex = None
        print_header = True
        if args.args:
            regex = re.compile(fnmatch.translate(args.args[0]))

        core_layout = None

        for mod in for_each_module():
            if core_layout is None:
                core_layout = struct_has_member(mod.type, 'core_layout')

            modname = mod['name'].string()
            if regex:
                m = regex.match(modname)
                if m is None:
                    continue

            if args.p is not None:
                if print_header:
                    print_header = False
                    if args.p == -1:
                        print("Module\t\t\tPercpu Base\t\tSize")
                    else:
                        print("Module\t\t\tPercpu Base@CPU{:d}\t\tSize".format(
                            args.p))
                self.print_module_percpu(mod, args.p)
                continue

            if print_header:
                print_header = False
                print("Module\t\t\tAddress\t\t\tSize\tUsed by")

            if core_layout:
                addr = int(mod['core_layout']['base'])
                size = int(mod['core_layout']['size'])
            else:
                addr = int(mod['module_core'])
                size = int(mod['core_size'])

            module_use = ""
            count = 0
            for use in list_for_each_entry(mod['source_list'],
                                           types.module_use_type,
                                           'source_list'):
                if module_use == "":
                    module_use += " "
                else:
                    module_use += ","
                module_use += use['source']['name'].string()
                count += 1

            print("{:16s}\t{:#x}\t{:d}\t{:d}{}".format(modname, addr, size,
                                                       count, module_use))
Example #6
0
    def get_last_cpu(self) -> int:
        """
        Returns the last cpu this task was scheduled to execute on

        Returns:
            :obj:`int`: The last cpu this task was scheduled to execute on
        """
        if struct_has_member(self.task_struct, 'cpu'):
            cpu = self.task_struct['cpu']
        else:
            cpu = self.thread_info['cpu']
        return int(cpu)
Example #7
0
    def check_task_interface(cls, init_task: gdb.Symbol) -> None:
        """
        Check which interface to iterating over mount structures is in use

        Meant to be used as a SymbolCallback.

        Args:
            init_task: The ``init_task`` symbol.
        """
        cls._init_fs_root = init_task.value()['fs']['root']
        if struct_has_member(init_task, 'nsproxy'):
            cls._for_each_mount = cls._for_each_mount_nsproxy
        else:
            raise NotImplementedError("Mount.for_each_mount is unhandled on this kernel version")
Example #8
0
def queue_is_mq(queue: gdb.Value) -> bool:
    """
    Tests whether the queue is blk-mq queue.

    Args:
        queue: The request queue to test. The value must be
            of type ``struct request_queue``.

    Returns:
        :obj:`bool`: whether the ``struct request_queue`` is a multiqueue queue
    """
    if not struct_has_member(queue, 'mq_ops'):
        return False
    return int(queue['mq_ops']) != 0
Example #9
0
def btrfs_metadata_uuid(sb: gdb.Value, force: bool = False) -> uuid.UUID:
    """
    Returns the btrfs metadata uuid for the specified superblock.

    Args:
        super_block: The ``struct super_block`` for which to return the
            btrfs metadata uuid.  The value must be of type
            ``struct super_block``.

        force: Ignore type checking.

    Returns:
        :obj:`uuid.UUID`: The Python UUID Object for the btrfs fsid

    Raises:
        :obj:`.InvalidArgumentError`: the super_block does not belong to btrfs
        :obj:`gdb.NotAvailableError`: The target value was not available.
    """
    fs_info = btrfs_fs_info(sb, force)
    if struct_has_member(types.btrfs_fs_info_type, 'metadata_uuid'):
        return decode_uuid(fs_info['metadata_uuid'])
    if struct_has_member(fs_info['fs_devices'].type, 'metadata_uuid'):
        return decode_uuid(fs_info['fs_devices']['metadata_uuid'])
    return btrfs_fsid(sb, force)
Example #10
0
    def setup_iterator_type(cls, gdbtype: gdb.Type) -> None:
        """
        Detect whether to iterate the class list using ``struct device``
        or ``struct device_private``.

        Linux v5.1-rc1 moved ``knode_class`` from ``struct device`` to
        ``struct device_private``.  We need to detect it here to ensure
        list iteration works properly.

        Meant to be used as a TypeCallback.

        Args:
            gdbtype: The ``struct device`` type.
        """
        if struct_has_member(gdbtype, 'knode_class'):
            cls._class_is_private = False
Example #11
0
    def detect_ail_version(cls, gdbtype: gdb.Type) -> None:
        """
        Detect what version of the ail structure is in use

        Linux v4.17 renamed the xfs_ail members to use
        ail_* instead of xa_* except for xa_ail which
        was renamed to ail_head.

        Meant to be used as a TypeCallback.

        Args:
            gdbtype: The ``struct xfs_ail`` type.
        """
        if struct_has_member(gdbtype, 'ail_head'):
            cls._ail_head_name = 'ail_head'
        else:
            cls._ail_head_name = 'xa_ail'
Example #12
0
def mount_flags(mnt: gdb.Value, show_hidden: bool = False) -> str:
    """
    Returns the human-readable flags of the ``struct mount``
    :ref:`structure <mount_structure>`.

    Args:
        mnt: The :ref:`mount structure <mount_structure>` for which to
            return flags

        show_hidden: Whether to return hidden flags

    Returns:
        :obj:`str`: The mount flags in human-readable form
    """
    if struct_has_member(mnt, 'mnt'):
        mnt = mnt['mnt']
    if show_hidden:
        return decode_flags(mnt['mnt_flags'], MNT_FLAGS_HIDDEN, ",")
    return decode_flags(mnt['mnt_flags'], MNT_FLAGS, ",")
Example #13
0
def sq_requests_queued(queue: gdb.Value) -> Tuple[int, int]:
    """
    Report how many requests are queued for this queue

    Args:
        queue: The request queue to inspect for queued requests.
            The value must be of type ``struct request_queue``.

    Returns:
        (:obj:`int`, :obj:`int`): The queued requests.  The first member of
        the 2-tuple is the number of async requests, the second is the number
        of sync requests.
    """
    _check_queue_type(queue)
    if struct_has_member(queue, 'rq'):
        rqlist = queue['rq']
    else:
        rqlist = queue['root_rl']
    return (int(rqlist['count'][0]), int(rqlist['count'][1]))
Example #14
0
def sbitmap_for_each_set(sbitmap: gdb.Value) -> Iterable[int]:
    """
    Yield each set bit in a scalable bitmap

    Args:
        sbitmap: The bitmap to iterate.

    Yields:
        :obj:`int`: The position of a bit that is set

    """

    length = int(sbitmap['depth'])
    for i in range(0, int(sbitmap['map_nr'])):
        word = sbitmap['map'][i]['word']
        if struct_has_member(sbitmap['map'][i], 'cleared'):
            word &= ~sbitmap['map'][i]['cleared']
        offset = i << int(sbitmap['shift'])
        bits = min(int(sbitmap['map'][i]['depth']), length - offset)
        for j in range(0, bits):
            if word & (1 << j):
                yield offset + j
Example #15
0
    def dump_ail(self, args: argparse.Namespace) -> None:
        try:
            sb = get_super_block(args.addr)
        except gdb.NotAvailableError as e:
            raise CommandError(str(e)) from e

        mp = xfs_mount(sb)
        ail = mp['m_ail']
        itemno = 0
        print("AIL @ {:x}".format(int(ail)))
        print("target={} last_pushed_lsn={} log_flush=".format(
            int(ail['xa_target']), int(ail['xa_last_pushed_lsn'])),
              end='')

        # This was added in Linux v3.2 (670ce93fef93b)
        if struct_has_member(ail, 'xa_log_flush'):
            print("{}".format(int(ail['xa_log_flush'])))
        else:
            print("[N/A]")

        for bitem in xfs_for_each_ail_log_item(mp):
            li_type = int(bitem['li_type'])
            lsn = int(bitem['li_lsn'])
            item = xfs_log_item_typed(bitem)
            print("{}: item={:x} lsn={} {} ".format(itemno, int(bitem.address),
                                                    lsn,
                                                    XFS_LI_TYPES[li_type][7:]),
                  end='')
            if li_type == XFS_LI_BUF:
                buf = item['bli_buf']
                flags = decode_flags(item['bli_flags'], XFS_BLI_FLAGS)
                print(" buf@{:x} bli_flags={}".format(int(buf), flags))

                print("     {}".format(xfs_format_xfsbuf(buf)))
            elif li_type == XFS_LI_INODE:
                ili_flags = int(item['ili_lock_flags'])
                xfs_inode = item['ili_inode']
                print("inode@{:x} i_ino={} ili_lock_flags={:x} ".format(
                    int(xfs_inode['i_vnode'].address), int(xfs_inode['i_ino']),
                    ili_flags))
            elif li_type == XFS_LI_EFI:
                efi = item['efi_format']
                print("efi@{:x} size={}, nextents={}, id={:x}".format(
                    int(item.address), int(efi['efi_size']),
                    int(efi['efi_nextents']), int(efi['efi_id'])))
            elif li_type == XFS_LI_EFI:
                efd = item['efd_format']
                print("efd@{:x} size={}, nextents={}, id={:x}".format(
                    int(item.address), int(efd['efd_size']),
                    int(efd['efd_nextents']), int(efd['efd_id'])))
            elif li_type == XFS_LI_DQUOT:
                dquot = item['qli_dquot']
                flags = decode_flags(dquot['dq_flags'], XFS_DQ_FLAGS)
                print("dquot@{:x} flags={}".format(int(dquot), flags))
            elif li_type == XFS_LI_QUOTAOFF:
                qoff = item['qql_format']
                print("qoff@{:x} type={} size={} flags={}".format(
                    int(qoff), int(qoff['qf_type']), int(qoff['qf_size']),
                    int(qoff['qf_flags'])))
            else:
                print("item@{:x}".format(int(item.address)))
            itemno += 1