#!/usr/bin/env python3
# -*- coding: utf-8 -*-

__author__ = "Peace Lee"
__copyright__ = "Copyright 2015-2022, Guider"
__module__ = "guider"
__credits__ = "Peace Lee"
__license__ = "GPLv2"
__version__ = "3.9.8"
__revision__ = "220714"
__maintainer__ = "Peace Lee"
__email__ = "iipeace5@gmail.com"
__repository__ = "https://github.com/iipeace/guider"


# import essential packages #
import sys

try:
    import os
    import re
    import gc
    import time
    import errno
    import signal
    import atexit
    import struct
    from copy import deepcopy

    # from ctypes import *
except ImportError:
    err = sys.exc_info()[1]
    sys.exit("[ERROR] failed to import essential package: %s" % err.args[0])

# convert an unsupported type #
try:
    long  # pylint: disable=used-before-assignment
except:
    long = int

# prevent MemoryError in python2 #
try:
    xrange  # pylint: disable=used-before-assignment
except:
    xrange = range

# enable JIT compiler #
try:
    if "JITCOMPILE" in os.environ:
        from numba import jit  # pylint: disable=import-error
    else:

        def jit(func):
            def decorated():
                func()

            return decorated

except:
    err = sys.exc_info()[1]
    sys.exit("[ERROR] failed to import numba package: %s" % err.args[0])


class ConfigMgr(object):
    """Manager for config"""

    # logo, made by http://www.figlet.org, consider also jp2a #
    logo = """
   _____       _     _
  / ____|     (_)   | |
 | |  __ _   _ _  __| | ___ _ __
 | | |_ | | | | |/ _` |/ _ \ '__|
 | |__| | |_| | | (_| |  __/ |
  \_____|\__,_|_|\__,_|\___|_|  ver_%s_%s on python_%s.%s
""" % (
        __version__,
        __revision__,
        sys.version_info[0],
        sys.version_info[1],
    )

    # color #
    if (
        sys.platform.startswith("linux")
        or sys.platform.startswith("darwin")
        or sys.platform.startswith("freebsd")
    ) and not "REMOTERUN" in os.environ:
        ENDC = "\033[0m"
    else:
        ENDC = ""

    # config info #
    confData = {}

    # support architecture #
    supportArch = ["arm", "aarch64", "x86", "x64"]

    # ANSI color #
    COLOR_LIST = {
        "DEFAULT": "\033[0m",
        "BOLD": "\033[1m",
        "ITALIC": "\033[3m",
        "UNDERLINE": "\033[4m",
        "LIGHT": "\033[5m",
        "BLINK": "\033[6m",
        "REVERSE": "\033[7m",
        "SCRATCH": "\033[9m",
        "BLACK": "\033[30m",
        "RED": "\033[31m",
        "GREEN": "\033[32m",
        "YELLOW": "\033[33m",
        "BLUE": "\033[34m",
        "PINK": "\033[35m",
        "CYAN": "\033[36m",
        "WHITE": "\033[37m",
        "DEFCOLOR": "\033[39m",
        "BGBLACK": "\033[40m",
        "BGRED": "\033[41m",
        "BGGREEN": "\033[42m",
        "BGYELLOW": "\033[43m",
        "BGBLUE": "\033[44m",
        "BGPINK": "\033[45m",
        "BGCYAN": "\033[46m",
        "BGWHITE": "\033[47m",
        "FAIL": "\033[91m",
        "OKGREEN": "\033[92m",
        "SPECIAL": "\033[93m",
        "OKBLUE": "\033[94m",
        "WARNING": "\033[95m",
        "LIGHTGREEN": "\033[1;32m",
    }

    # cgroup entity #
    CGROUP_VALUE = [
        "tasks",
        "cgroup.procs",
        "cpu.shares",
        "cpuset.cpus",
        "memory.limit_in_bytes",
        "memory.memsw.limit_in_bytes",
        "blkio.weight",
        "blkio.weight_device",
    ]

    # cgroup stat #
    CGROUP_STAT = {
        "cpuacct.usage": None,
        "memory.usage_in_bytes": None,
        "tasks": None,
        "cgroup.procs": None,
        "cpu.stat": None,
    }

    # state of process #
    PROC_STAT_TYPE = {
        "R": "running",
        "S": "sleep",
        "D": "disk",
        "T": "stopped",
        "t": "traced",
        "X": "dead",
        "x": "dead",
        "Z": "zombie",
        "K": "wakekill",
        "W": "waking",
        "P": "parked",
        "I": "idle",
    }

    # diskstat statistics #
    DISKSTAT = [
        "major",
        "minor",
        "name",
        "readComplete",
        "readMerge",
        "sectorRead",
        "readTime",
        "writeComplete",
        "writeMerge",
        "sectorWrite",
        "writeTime",
        "currentIO",
        "ioTime",
        "ioWTime",
        "discComplete",
        "discMerged",
        "sectorDisc",
        "discTime",  # 4.18+
        "flushComplete",
        "flushTime",  # 5.5+
    ]

    BGRECLAIMSTAT = [
        "pgsteal_kswapd",
        "pgsteal_kswapd_normal",
        "pgsteal_kswapd_high",
        "pgsteal_kswapd_dma",
        "pgsteal_kswapd_dma32",
        "pgsteal_kswapd_movable",
    ]

    FGRECLAIMSTAT = [
        "pgsteal_direct",
        "pgsteal_direct_normal",
        "pgsteal_direct_high",
        "pgsteal_direct_dma",
        "pgsteal_direct_dma32",
        "pgsteal_direct_movable",
    ]

    # socketcall attributes #
    SOCKETCALL = {
        1: "socket",
        2: "bind",
        3: "connect",
        4: "listen",
        5: "accept",
        6: "getsockname",
        7: "getpeername",
        8: "socketpair",
        9: "send",
        10: "recv",
        11: "sendto",
        12: "recvfrom",
        13: "shutdown",
        14: "setsockopt",
        15: "getsockopt",
        16: "sendmsg",
        17: "recvmsg",
    }

    # socket family #
    SOCKET_FAMILY = {
        0: "AF_UNSPEC",
        1: "AF_FILE",
        2: "AF_INET",
        3: "AF_AX25",
        4: "AF_IPX",
        5: "AF_APPLETALK",
        6: "AF_NETROM",
        7: "AF_BRIDGE",
        8: "AF_ATMPVC",
        9: "AF_X25",
        10: "AF_INET6",
        11: "AF_ROSE",
        12: "AF_DECnet",
        13: "AF_NETBEUI",
        14: "AF_SECURITY",
        15: "AF_KEY",
        16: "AF_NETLINK",
        17: "AF_PACKET",
        18: "AF_ASH",
        19: "AF_ECONET",
        20: "AF_ATMSVC",
        22: "AF_SNA",
        23: "AF_IRDA",
        24: "AF_PPPOX",
        25: "AF_WANPIPE",
        31: "AF_BLUETOOTH",
    }

    # DLOPEN type #
    DLOPEN_TYPE = {
        1: "RTLD_LAZY",
        2: "RTLD_NOW",
        3: "RTLD_BINDING_MASK",
        4: "RTLD_NOLOAD",
        8: "RTLD_DEEPBIND",
    }

    # socket type #
    SOCKET_TYPE = {
        1: "SOCK_STREAM",
        2: "SOCK_DGRAM",
        3: "SOCK_RAW",
        4: "SOCK_RDM",
        5: "SOCK_SEQPACKET",
        10: "SOCK_PACKET",
    }

    # log level #
    LOG_LEVEL = {
        0: "EMERG",
        1: "ALERT",
        2: "CRIT",
        3: "ERR",
        4: "WARNING",
        5: "NOTICE",
        6: "INFO",
        7: "DEBUG",
    }

    # MSG type #
    MSG_TYPE = {
        0x1: "MSG_OOB",
        0x2: "MSG_PEEK",
        0x4: "MSG_DONTROUTE|MSG_TRYHARD",
        0x8: "MSG_CTRUNC",
        0x10: "MSG_PROBE",
        0x20: "MSG_TRUNC",
        0x40: "MSG_DONTWAIT",
        0x80: "MSG_EOR",
        0x100: "MSG_WAITALL",
        0x200: "MSG_FIN",
        0x400: "MSG_SYN",
        0x800: "MSG_CONFIRM",
        0x1000: "MSG_RST",
        0x2000: "MSG_ERRQUEUE",
        0x4000: "MSG_NOSIGNAL",
        0x8000: "MSG_MORE",
        0x40000000: "MSG_CMSG_CLOEXEC",
        0x80000000: "MSG_CMSG_COMPAT",
    }

    # control message type #
    CMSG_TYPE = {
        0x01: "SCM_RIGHTS",  # rw: access rights (array of int)
        0x02: "SCM_CREDENTIALS",  # rw: struct ucred
        0x03: "SCM_SECURITY",
    }

    # mmap prot type #
    MAP_TYPE = {
        0x0000: "MAP_FILE",
        0x0001: "MAP_SHARED",
        0x0002: "MAP_PRIVATE",
        # 0x0003: "MAP_SHARED_VALIDATE",
        # 0x000f: "MAP_TYPE",
        0x0010: "MAP_FIXED",
        0x0020: "MAP_ANONYMOUS",
        0x0100: "MAP_GROWSDOWN",
        0x0800: "MAP_DENYWRITE",
        0x1000: "MAP_EXECUTABLE",
        0x2000: "MAP_LOCKED",
        0x4000: "MAP_NORESERVE",
        0x8000: "MAP_POPULATE",
        0x10000: "MAP_NONBLOCK",
        0x20000: "MAP_STACK",
        0x40000: "MAP_HUGETLB",
        0x80000: "MAP_SYNC",
    }

    # FAT type #
    FAT_TYPE = {
        -100: "AT_FDCWD",
        0x100: "AT_SYMLINK_NOFOLLOW",
        0x200: "AT_REMOVEDIR",
        0x400: "AT_SYMLINK_FOLLOW",
        0x800: "AT_NO_AUTOMOUNT",
        0x1000: "AT_EMPTY_PATH",
    }

    # mmap prot type #
    PROT_TYPE = {
        0x0: "PROT_NONE",  # Page can not be accessed
        0x1: "PROT_READ",  # Page can be read
        0x2: "PROT_WRITE",  # Page can be written
        0x4: "PROT_EXEC",  # Page can be executed
    }

    # perm type #
    PERM_TYPE = {0x0: "F_OK", 0x1: "X_OK", 0x2: "W_OK", 0x4: "R_OK"}

    # seek type #
    SEEK_TYPE = {0x0: "SEEK_SET", 0x1: "SEEK_CUR", 0x2: "SEEK_END"}

    # prctl flags type #
    PRCTL_TYPE = {
        1: "PR_SET_PDEATHSIG",
        2: "PR_GET_PDEATHSIG",
        3: "PR_GET_DUMPABLE",
        4: "PR_SET_DUMPABLE",
        5: "PR_GET_UNALIGN",
        6: "PR_SET_UNALIGN",
        7: "PR_GET_KEEPCAPS",
        8: "PR_SET_KEEPCAPS",
        9: "PR_GET_FPEMU",
        10: "PR_SET_FPEMU",
        11: "PR_GET_FPEXC",
        12: "PR_SET_FPEXC",
        13: "PR_GET_TIMING",
        14: "PR_SET_TIMING",
        15: "PR_SET_NAME",
        16: "PR_GET_NAME",
        19: "PR_GET_ENDIAN",
        20: "PR_SET_ENDIAN",
        21: "PR_GET_SECCOMP",
        22: "PR_SET_SECCOMP",
        23: "PR_CAPBSET_READ",
        24: "PR_CAPBSET_DROP",
        25: "PR_GET_TSC 25",
        26: "PR_SET_TSC 26",
        27: "PR_GET_SECUREBITS",
        28: "PR_SET_SECUREBITS",
        29: "PR_SET_TIMERSLACK",
        30: "PR_GET_TIMERSLACK",
        31: "PR_TASK_PERF_EVENTS_DISABLE",
        32: "PR_TASK_PERF_EVENTS_ENABLE",
        33: "PR_MCE_KILL",
    }

    # mount flags type #
    MOUNT_TYPE = {
        "MS_RDONLY": 1,  # Mount read-only
        "MS_NOSUID": 2,  # Ignore suid and sgid bits
        "MS_NODEV": 4,  # Disallow access to device special files
        "MS_NOEXEC": 8,  # Disallow program execution
        "MS_SYNCHRONOUS": 16,  # Writes are synced at once
        "MS_REMOUNT": 32,  # Alter flags of a mounted FS
        "MS_MANDLOCK": 64,  # Allow mandatory locks on an FS
        "MS_WRITE": 128,  # Write on file/directory/symlink
        "MS_APPEND": 256,  # Append-only file
        "MS_IMMUTABLE": 512,  # Immutable file
        "MS_NOATIME": 1024,  # Do not update access times
        "MS_NODIRATIME": 2048,  # Do not update directory access times
        "MS_BIND": 4096,  # Bind directory at different place
        "MS_REC": 16384,
        "MS_VERBOSE": 32768,  # War is peace. Verbosity is silence
        "MS_SILENT": 32768,
        "MS_POSIXACL": (1 << 16),  # VFS does not apply the umask
        "MS_UNBINDABLE": (1 << 17),  # change to unbindable
        "MS_PRIVATE": (1 << 18),  # change to private
        "MS_SLAVE": (1 << 19),  # change to slave
        "MS_SHARED": (1 << 20),  # change to shared
        "MS_RELATIME": (1 << 21),  # Update atime relative to mtime/ctime
        "MS_KERNMOUNT": (1 << 22),  # this is a kern_mount call
        "MS_I_VERSION": (1 << 23),  # Update inode I_version field
        "MS_STRICTATIME": (1 << 24),  # Always perform atime updates
        "MS_LAZYTIME": (1 << 25),  # Update the on-disk [acm]times lazily
        "MS_NOSEC": (1 << 28),
        "MS_BORN": (1 << 29),
        "MS_ACTIVE": (1 << 30),
        "MS_NOUSER": (1 << 31),
    }
    MOUNT_TYPE_REVERSE = {}

    # umount flags type #
    UMOUNT_TYPE = {
        "MNT_FORCE": 0x00000001,  # Attempt to forcibily umount
        "MNT_DETACH": 0x00000002,  # Just detach from the tree
        "MNT_EXPIRE": 0x00000004,  # Mark for expiry
        "MNT_NOFOLLOW": 0x00000008,  # Don't follow symlink on umount
        "MNT_UNUSED": 0x80000000,  # Flag guaranteed to be unused
    }
    UMOUNT_TYPE_REVERSE = {}

    # clone flags type #
    CLONE_TYPE = {
        0x000000FF: "CSIGNAL",
        0x00000100: "CLONE_VM",
        0x00000200: "CLONE_FS",
        0x00000400: "CLONE_FILES",
        0x00000800: "CLONE_SIGHAND",
        0x00002000: "CLONE_PTRACE",
        0x00004000: "CLONE_VFORK",
        0x00008000: "CLONE_PARENT",
        0x00010000: "CLONE_THREAD",
        0x00020000: "CLONE_NEWNS",
        0x00040000: "CLONE_SYSVSEM",
        0x00080000: "CLONE_SETTLS",
        0x00100000: "CLONE_PARENT_SETTID",
        0x00200000: "CLONE_CHILD_CLEARTID",
        0x00400000: "CLONE_DETACHED",
        0x00800000: "CLONE_UNTRACED",
        0x01000000: "CLONE_CHILD_SETTID",
        0x02000000: "CLONE_STOPPED",
        0x04000000: "CLONE_NEWUTS",
        0x08000000: "CLONE_NEWIPC",
        0x10000000: "CLONE_NEWUSER",
        0x20000000: "CLONE_NEWPID",
        0x40000000: "CLONE_NEWNET",
        0x80000000: "CLONE_IO",
    }

    # open flags type #
    OPEN_TYPE = {
        0o0: "RDONLY",
        0o1: "WRONLY",
        0o2: "RDWR",
        0o100: "CREAT",
        0o200: "EXCL",
        0o400: "NOCTTY",
        0o1000: "TRUNC",
        0o2000: "APPEND",
        0o4000: "NONBLOCK",
        0o10000: "SYNC",
        0o20000: "ASYNC",
        0o40000: "DIRECT",
        0o100000: "LARGEFILE",
        0o200000: "DIRECTORY",
        0o400000: "NOFOLLOW",
        0o1000000: "NOATIME",
        0o2000000: "CLOEXEC",
        0o10000000: "PATH",
        0o20200000: "TMPFILE",
    }

    # epoll op type #
    EPOLL_CMD_TYPE = [
        "EPOLL_CTL_NONE",  # None
        "EPOLL_CTL_ADD",  # Add a file descriptor to the interface
        "EPOLL_CTL_DEL",  # Remove a file descriptor from the interface
        "EPOLL_CTL_MOD",  # Change file descriptor epoll_event structure
    ]

    # epoll event type #
    EPOLL_EVENT_TYPE = {
        0x001: "EPOLLIN",
        0x002: "EPOLLPRI",
        0x004: "EPOLLOUT",
        0x040: "EPOLLRDNORM",
        0x080: "EPOLLRDBAND",
        0x100: "EPOLLWRNORM",
        0x200: "EPOLLWRBAND",
        0x400: "EPOLLMSG",
        0x008: "EPOLLERR",
        0x010: "EPOLLHUP",
        0x2000: "EPOLLRDHUP",
        (1 << 29): "EPOLLWAKEUP",
        (1 << 30): "EPOLLONESHOT",
        (1 << 31): "EPOLLET",
    }

    # madvise type #
    MADV_TYPE = {
        0: "MADV_NORMAL",  # No further special treatment
        1: "MADV_RANDOM",  # Expect random page references
        2: "MADV_SEQUENTIAL",  # Expect sequential page references
        3: "MADV_WILLNEED",  # Will need these pages
        4: "MADV_DONTNEED",  # Don't need these pages
        8: "MADV_FREE",  # Free pages only if memory pressure
        9: "MADV_REMOVE",  # Remove these pages and resources
        10: "MADV_DONTFORK",  # Do not inherit across fork
        11: "MADV_DOFORK",  # Do inherit across fork
        12: "MADV_MERGEABLE",  # KSM may merge identical pages
        13: "MADV_UNMERGEABLE",  # KSM may not merge identical pages
        14: "MADV_HUGEPAGE",  # Worth backing with hugepages
        15: "MADV_NOHUGEPAGE",  # Not worth backing with hugepages
        16: "MADV_DONTDUMP",  # Explicitly exclude from the core dump,
        17: "MADV_DODUMP",  # Clear the MADV_DONTDUMP flag
        18: "MADV_WIPEONFORK",  # Zero memory on fork, child only
        19: "MADV_KEEPONFORK",  # Undo MADV_WIPEONFORK
        100: "MADV_HWPOISON",  # Poison a page for testing
    }

    # netlink type #
    NETLINK_TYPE = {
        "NETLINK_ROUTE": 0,
        "NETLINK_UNUSED": 1,
        "NETLINK_USERSOCK": 2,
        "NETLINK_FIREWALL": 3,
        "NETLINK_SOCK_DIAG": 4,
        "NETLINK_NFLOG": 5,
        "NETLINK_XFRM": 6,
        "NETLINK_SELINUX": 7,
        "NETLINK_ISCSI": 8,
        "NETLINK_AUDIT": 9,
        "NETLINK_FIB_LOOKUP": 10,
        "NETLINK_CONNECTOR": 11,
        "NETLINK_NETFILTER": 12,
        "NETLINK_IP6_FW": 13,
        "NETLINK_DNRTMSG": 14,
        "NETLINK_KOBJECT_UEVENT": 15,
        "NETLINK_GENERIC": 16,
        "NETLINK_SCSITRANSPORT": 18,
        "NETLINK_ECRYPTFS": 19,
        "NETLINK_RDMA": 20,
        "NETLINK_CRYPTO": 21,
    }

    # entry type #
    INOTIFY_TYPE = {
        "IN_ACCESS": 0x00000001,  # File was accessed */
        "IN_MODIFY": 0x00000002,  # File was modified */
        "IN_ATTRIB": 0x00000004,  # Metadata changed */
        "IN_CLOSE_WRITE": 0x00000008,  # Writtable file was closed */
        "IN_CLOSE_NOWRITE": 0x00000010,  # Unwrittable file closed */
        "IN_CLOSE": 0x00000008 | 0x00000010,  # file closed */
        "IN_OPEN": 0x00000020,  # File was opened */
        "IN_MOVED_FROM": 0x00000040,  # File was moved from X */
        "IN_MOVED_TO": 0x00000080,  # File was moved to Y */
        "IN_MOVED": 0x00000040 | 0x00000080,  # File was moved */
        "IN_CREATE": 0x00000100,  # Subfile was created */
        "IN_DELETE": 0x00000200,  # Subfile was deleted */
        "IN_DELETE_SELF": 0x00000400,  # Self was deleted */
        "IN_MOVE_SELF": 0x00000800,  # Self was moved */
        "IN_UNMOUNT": 0x00002000,  # Backing fs was unmounted */
        "IN_Q_OVERFLOW": 0x00004000,  # Event queued overflowed */
        "IN_IGNORED": 0x00008000,  # File was ignored */
        "IN_ONLYDIR": 0x01000000,  # only watch the path if it is a directory */
        "IN_DONT_FOLLOW": 0x02000000,  # don't follow a sym link */
        "IN_EXCL_UNLINK": 0x04000000,  # exclude events on unlinked objects */
        "IN_MASK_CREATE": 0x10000000,  # only create watches */
        "IN_MASK_ADD": 0x20000000,  # add to the mask of an already existing watch */
        "IN_ISDIR": 0x40000000,  # event occurred against dir */
        "IN_ONESHOT": 0x80000000,  # only send event once */
    }

    # entry type #
    AT_TYPE = {
        "AT_IGNORE": 1,  # Entry should be ignored
        "AT_EXECFD": 2,  # File descriptor of program
        "AT_PHDR": 3,  # Program headers for program
        "AT_PHENT": 4,  # Size of program header entry
        "AT_PHNUM": 5,  # Number of program headers
        "AT_PAGESZ": 6,  # System page size
        "AT_BASE": 7,  # Base address of interpreter
        "AT_FLAGS": 8,  # Flags
        "AT_ENTRY": 9,  # Entry point of program
        "AT_NOTELF": 10,  # Program is not ELF
        "AT_UID": 11,  # Real uid
        "AT_EUID": 12,  # Effective uid
        "AT_GID": 13,  # Real gid
        "AT_EGID": 14,  # Effective gid
        "AT_CLKTCK": 17,  # Frequency of times()
        "AT_PLATFORM": 15,  # String identifying platform
        "AT_HWCAP": 16,  # Machine-dependent hints about
        "AT_FPUCW": 18,  # Used FPU control word
        "AT_DCACHEBSIZE": 19,  # Data cache block size
        "AT_ICACHEBSIZE": 20,  # Instruction cache block size
        "AT_UCACHEBSIZE": 21,  # Unified cache block size
        "AT_IGNOREPPC": 22,  # Entry should be ignored
        "AT_SECURE": 23,  # Boolean, was exec setuid-like?
        "AT_BASE_PLATFORM": 24,  # String identifying real platforms
        "AT_RANDOM": 25,  # Address of 16 random bytes
        "AT_HWCAP2": 26,  # More machine-dependent hints about
        "AT_EXECFN": 31,  # Filename of executable
        "AT_SYSINFO": 32,
        "AT_SYSINFO_EHDR": 33,
        "AT_L1I_CACHESHAPE": 34,
        "AT_L1D_CACHESHAPE": 35,
        "AT_L2_CACHESHAPE": 36,
        "AT_L3_CACHESHAPE": 37,
        "AT_L1I_CACHESIZE": 40,
        "AT_L1I_CACHEGEOMETRY": 41,
        "AT_L1D_CACHESIZE": 42,
        "AT_L1D_CACHEGEOMETRY": 43,
        "AT_L2_CACHESIZE": 44,
        "AT_L2_CACHEGEOMETRY": 45,
        "AT_L3_CACHESIZE": 46,
        "AT_L3_CACHEGEOMETRY": 47,
        "AT_MINSIGSTKSZ": 51,  # Stack needed for signal delivery
    }

    # syscall prototypes #
    SYSCALL_REFBUF = {
        "write": 0,
        "read": 0,
        "send": 0,
        "sendto": 0,
        "recv": 0,
        "recvfrom": 0,
        "pread": 0,
        "pread64": 0,
        "pwrite": 0,
        "pwrite64": 0,
    }

    # BPF syscall commands #
    BPF_CMD = [
        "BPF_MAP_CREATE",
        "BPF_MAP_LOOKUP_ELEM",
        "BPF_MAP_UPDATE_ELEM",
        "BPF_MAP_DELETE_ELEM",
        "BPF_MAP_GET_NEXT_KEY",
        "BPF_PROG_LOAD",
        "BPF_OBJ_PIN",
        "BPF_OBJ_GET",
        "BPF_PROG_ATTACH",
        "BPF_PROG_DETACH",
        "BPF_PROG_TEST_RUN",
        "BPF_PROG_GET_NEXT_ID",
        "BPF_MAP_GET_NEXT_ID",
        "BPF_PROG_GET_FD_BY_ID",
        "BPF_MAP_GET_FD_BY_ID",
        "BPF_OBJ_GET_INFO_BY_FD",
    ]

    BPF_MAP_TYPE = [
        "BPF_MAP_TYPE_UNSPEC",
        "BPF_MAP_TYPE_HASH",
        "BPF_MAP_TYPE_ARRAY",
        "BPF_MAP_TYPE_PROG_ARRAY",
        "BPF_MAP_TYPE_PERF_EVENT_ARRAY",
        "BPF_MAP_TYPE_PERCPU_HASH",
        "BPF_MAP_TYPE_PERCPU_ARRAY",
        "BPF_MAP_TYPE_STACK_TRACE",
        "BPF_MAP_TYPE_CGROUP_ARRAY",
        "BPF_MAP_TYPE_LRU_HASH",
        "BPF_MAP_TYPE_LRU_PERCPU_HASH",
        "BPF_MAP_TYPE_LPM_TRIE",
        "BPF_MAP_TYPE_ARRAY_OF_MAPS",
        "BPF_MAP_TYPE_HASH_OF_MAPS",
        "BPF_MAP_TYPE_DEVMAP",
        "BPF_MAP_TYPE_SOCKMAP",
    ]

    BPF_PROG_TYPE = [
        "BPF_PROG_TYPE_UNSPEC",
        "BPF_PROG_TYPE_SOCKET_FILTER",
        "BPF_PROG_TYPE_KPROBE",
        "BPF_PROG_TYPE_SCHED_CLS",
        "BPF_PROG_TYPE_SCHED_ACT",
        "BPF_PROG_TYPE_TRACEPOINT",
        "BPF_PROG_TYPE_XDP",
        "BPF_PROG_TYPE_PERF_EVENT",
        "BPF_PROG_TYPE_CGROUP_SKB",
        "BPF_PROG_TYPE_CGROUP_SOCK",
        "BPF_PROG_TYPE_LWT_IN",
        "BPF_PROG_TYPE_LWT_OUT",
        "BPF_PROG_TYPE_LWT_XMIT",
        "BPF_PROG_TYPE_SOCK_OPS",
        "BPF_PROG_TYPE_SK_SKB",
    ]

    BPF_ATTACH_TYPE = [
        "BPF_CGROUP_INET_INGRESS",
        "BPF_CGROUP_INET_EGRESS",
        "BPF_CGROUP_INET_SOCK_CREATE",
        "BPF_CGROUP_SOCK_OPS",
        "BPF_SK_SKB_STREAM_PARSER",
        "BPF_SK_SKB_STREAM_VERDICT",
        "__MAX_BPF_ATTACH_TYPE",
    ]

    # unpack types #
    UNPACK_TYPE = {
        "U1": "B",
        "U2": "H",
        "U4": "I",
        "U8": "Q",
        "S1": "b",
        "S2": "h",
        "S4": "i",
        "S8": "q",
    }

    # syscall prototypes #
    SYSCALL_DEFFERABLE = {
        "clock_gettime": 0,
        "clone": 0,
        "getgroups": 0,
        "getgroups16": 0,
        "gethostname": 0,
        "getitimer": 0,
        "getpeername": 0,
        "getsockname": 0,
        "gettimeofday": 0,
        "pread": 0,
        "pread64": 0,
        "process_vm_readv": 0,
        "read": 0,
        "readlink": 0,
        "readv": 0,
        "recv": 0,
        "recvfrom": 0,
        "recvmmsg": 0,
        "recvmsg": 0,
    }

    # syscall prototypes #
    SYSCALL_PROTOTYPES = {
        "accept": (
            "long",
            (
                ("int", "sockfd"),
                ("struct sockaddr *", "addr"),
                ("int *", "addrlen"),
            ),
        ),
        "accept4": (
            "long",
            (
                ("int", "sockfd"),
                ("struct sockaddr *", "addr"),
                ("int *", "addrlen"),
                ("int", "flags"),
            ),
        ),
        "access": ("long", (("const char *", "filename"), ("int", "mode"))),
        "acct": ("long", (("const char *", "name"),)),
        "add_key": (
            "long",
            (
                ("const char *", "_type"),
                ("const char *", "_description"),
                ("const void *", "_payload"),
                ("size_t", "plen"),
                ("key_serial_t", "destringid"),
            ),
        ),
        "adjtimex": ("long", (("struct timex *", "txc_p"),)),
        "alarm": ("long", (("unsigned int", "seconds"),)),
        "bdflush": ("long", (("int", "func"), ("long", "data"))),
        "bind": (
            "long",
            (
                ("int", "sockfd"),
                ("struct sockaddr *", "addr"),
                ("int", "addrlen"),
            ),
        ),
        "bpf": (
            "long",
            (
                ("int", "cmd"),
                ("union bpf_attr *", "attr"),
                ("unsigned int", "size"),
            ),
        ),
        "brk": ("long", (("unsigned long", "brk"),)),
        "capget": (
            "long",
            (("cap_user_header_t", "header"), ("cap_user_data_t", "dataptr")),
        ),
        "capset": (
            "long",
            (
                ("cap_user_header_t", "header"),
                ("const cap_user_data_t", "data"),
            ),
        ),
        "chdir": ("long", (("const char *", "filename"),)),
        "chmod": ("long", (("const char *", "filename"), ("umode_t", "mode"))),
        "chown": (
            "long",
            (
                ("const char *", "filename"),
                ("uid_t", "user"),
                ("gid_t", "group"),
            ),
        ),
        "chown16": (
            "long",
            (
                ("const char *", "filename"),
                ("old_uid_t", "user"),
                ("old_gid_t", "group"),
            ),
        ),
        "chroot": ("long", (("const char *", "filename"),)),
        "clock_adjtime": (
            "long",
            (("clockid_t", "which_clock"), ("struct timex *", "tx")),
        ),
        "clock_adjtime32": (
            "long",
            (("clockid_t", "which_clock"), ("struct old_timex32 *", "tx")),
        ),
        "clock_getres": (
            "long",
            (("clockid_t", "which_clock"), ("struct timespec *", "tp")),
        ),
        "clock_getres_time32": (
            "long",
            (("clockid_t", "which_clock"), ("struct old_timespec32 *", "tp")),
        ),
        "clock_gettime": (
            "long",
            (("clockid_t", "which_clock"), ("struct timespec *", "tp")),
        ),
        "clock_gettime32": (
            "long",
            (("clockid_t", "which_clock"), ("struct old_timespec32 *", "tp")),
        ),
        "clock_nanosleep": (
            "long",
            (
                ("clockid_t", "which_clock"),
                ("int", "flags"),
                ("const struct timespec *", "rqtp"),
                ("struct timespec *", "rmtp"),
            ),
        ),
        "clock_nanosleep_time32": (
            "long",
            (
                ("clockid_t", "which_clock"),
                ("int", "flags"),
                ("struct old_timespec32 *", "rqtp"),
                ("struct old_timespec32 *", "rmtp"),
            ),
        ),
        "clock_settime": (
            "long",
            (("clockid_t", "which_clock"), ("const struct timespec *", "tp")),
        ),
        "clock_settime32": (
            "long",
            (("clockid_t", "which_clock"), ("struct old_timespec32 *", "tp")),
        ),
        "clone": (
            "long",
            (
                ("unsigned long", "child_stack"),
                ("unsigned long", "flags"),
                ("int *", "ptid"),
                ("int *", "ctid"),
                ("unsigned long", "regs"),
            ),
        ),
        "clone3": (
            "long",
            (("struct clone_args *", "uargs"), ("size_t", "size")),
        ),
        "close": ("long", (("unsigned int", "fd"),)),
        "close_range": (
            "long",
            (
                ("unsigned int", "fd"),
                ("unsigned int", "max_fd"),
                ("unsigned int", "flags"),
            ),
        ),
        "connect": (
            "long",
            (
                ("int", "sockfd"),
                ("struct sockaddr *", "addr"),
                ("int", "addrlen"),
            ),
        ),
        "copy_file_range": (
            "long",
            (
                ("int", "fd_in"),
                ("loff_t *", "off_in"),
                ("int", "fd_out"),
                ("loff_t *", "off_out"),
                ("size_t", "len"),
                ("unsigned int", "flags"),
            ),
        ),
        "creat": ("long", (("const char *", "pathname"), ("umode_t", "mode"))),
        "creat_module": ("long", (("const char *", "name"), ("int", "size"))),
        "delete_module": (
            "long",
            (("const char *", "name_user"), ("unsigned int", "flags")),
        ),
        "dup": ("long", (("unsigned int", "fildes"),)),
        "dup2": (
            "long",
            (("unsigned int", "oldfd"), ("unsigned int", "newfd")),
        ),
        "dup3": (
            "long",
            (
                ("unsigned int", "oldfd"),
                ("unsigned int", "newfd"),
                ("int", "flags"),
            ),
        ),
        "epoll_create": ("long", (("int", "size"),)),
        "epoll_create1": ("long", (("int", "flags"),)),
        "epoll_ctl": (
            "long",
            (
                ("int", "epfd"),
                ("int", "op"),
                ("int", "fd"),
                ("struct epoll_event *", "event"),
            ),
        ),
        "epoll_pwait": (
            "long",
            (
                ("int", "epfd"),
                ("struct epoll_event *", "events"),
                ("int", "maxevents"),
                ("int", "timeout"),
                ("const sigset_t *", "sigmask"),
                ("size_t", "sigsetsize"),
            ),
        ),
        "epoll_wait": (
            "long",
            (
                ("int", "epfd"),
                ("struct epoll_event *", "events"),
                ("int", "maxevents"),
                ("int", "timeout"),
            ),
        ),
        "eventfd": ("long", (("unsigned int", "count"),)),
        "eventfd2": ("long", (("unsigned int", "count"), ("int", "flags"))),
        "execve": (
            "long",
            (
                ("const char *", "filename"),
                ("const char * const *", "argv"),
                ("const char * const *", "envp"),
            ),
        ),
        "execveat": (
            "long",
            (
                ("int", "dfd"),
                ("const char *", "filename"),
                ("const char * const *", "argv"),
                ("const char * const *", "envp"),
                ("int", "flags"),
            ),
        ),
        "exit": ("long", (("int", "error_code"),)),
        "exit_group": ("long", (("int", "error_code"),)),
        "faccessat": (
            "long",
            (("int", "dfd"), ("const char *", "filename"), ("int", "mode")),
        ),
        "faccessat2": (
            "long",
            (
                ("int", "dfd"),
                ("const char *", "filename"),
                ("int", "mode"),
                ("int", "flags"),
            ),
        ),
        "fadvise64": (
            "long",
            (
                ("int", "fd"),
                ("loff_t", "offset"),
                ("size_t", "len"),
                ("int", "advice"),
            ),
        ),
        "fadvise64_64": (
            "long",
            (
                ("int", "fd"),
                ("loff_t", "offset"),
                ("loff_t", "len"),
                ("int", "advice"),
            ),
        ),
        "fallocate": (
            "long",
            (
                ("int", "fd"),
                ("int", "mode"),
                ("loff_t", "offset"),
                ("loff_t", "len"),
            ),
        ),
        "fanotify_init": (
            "long",
            (("unsigned int", "flags"), ("unsigned int", "event_f_flags")),
        ),
        "fanotify_mark": (
            "long",
            (
                ("int", "fanotify_fd"),
                ("unsigned int", "flags"),
                ("u64", "mask"),
                ("int", "fd"),
                ("const char *", "pathname"),
            ),
        ),
        "fchdir": ("long", (("unsigned int", "fd"),)),
        "fchmod": ("long", (("unsigned int", "fd"), ("umode_t", "mode"))),
        "fchmodat": (
            "long",
            (
                ("int", "dfd"),
                ("const char *", "filename"),
                ("umode_t", "mode"),
            ),
        ),
        "fchown": (
            "long",
            (("unsigned int", "fd"), ("uid_t", "user"), ("gid_t", "group")),
        ),
        "fchown16": (
            "long",
            (
                ("unsigned int", "fd"),
                ("old_uid_t", "user"),
                ("old_gid_t", "group"),
            ),
        ),
        "fchownat": (
            "long",
            (
                ("int", "dfd"),
                ("const char *", "filename"),
                ("uid_t", "user"),
                ("gid_t", "group"),
                ("int", "flag"),
            ),
        ),
        "fcntl": (
            "long",
            (
                ("unsigned int", "fd"),
                ("unsigned int", "cmd"),
                ("unsigned long", "arg"),
            ),
        ),
        "fcntl64": (
            "long",
            (
                ("unsigned int", "fd"),
                ("unsigned int", "cmd"),
                ("unsigned long", "arg"),
            ),
        ),
        "fdatasync": ("long", (("unsigned int", "fd"),)),
        "fgetxattr": (
            "long",
            (
                ("int", "fd"),
                ("const char *", "name"),
                ("void *", "value"),
                ("size_t", "size"),
            ),
        ),
        "finit_module": (
            "long",
            (("int", "fd"), ("const char *", "uargs"), ("int", "flags")),
        ),
        "flistxattr": (
            "long",
            (("int", "fd"), ("const char *", "list"), ("size_t", "size")),
        ),
        "flock": ("long", (("unsigned int", "fd"), ("unsigned int", "cmd"))),
        "fork": ("long", ()),
        "fremovexattr": ("long", (("int", "fd"), ("const char *", "name"))),
        "fsconfig": (
            "long",
            (
                ("int", "fs_fd"),
                ("unsigned int", "cmd"),
                ("const char *", "key"),
                ("const void *", "value"),
                ("int", "aux"),
            ),
        ),
        "fsetxattr": (
            "long",
            (
                ("int", "fd"),
                ("const char *", "name"),
                ("const void *", "value"),
                ("size_t", "size"),
                ("int", "flags"),
            ),
        ),
        "fsmount": (
            "long",
            (
                ("int", "fs_fd"),
                ("unsigned int", "flags"),
                ("unsigned int", "ms_flags"),
            ),
        ),
        "fsopen": (
            "long",
            (("const char *", "fs_name"), ("unsigned int", "flags")),
        ),
        "fspick": (
            "long",
            (
                ("int", "dfd"),
                ("const char *", "path"),
                ("unsigned int", "flags"),
            ),
        ),
        "fstat": (
            "long",
            (
                ("unsigned int", "fd"),
                ("struct __old_kernel_stat *", "statbuf"),
            ),
        ),
        "fstat64": (
            "long",
            (("unsigned long", "fd"), ("struct stat64 *", "statbuf")),
        ),
        "fstatat64": (
            "long",
            (
                ("int", "dfd"),
                ("const char *", "filename"),
                ("struct stat64 *", "statbuf"),
                ("int", "flag"),
            ),
        ),
        "fstatfs": (
            "long",
            (("unsigned int", "fd"), ("struct statfs *", "buf")),
        ),
        "fstatfs64": (
            "long",
            (
                ("unsigned int", "fd"),
                ("size_t", "sz"),
                ("struct statfs64 *", "buf"),
            ),
        ),
        "fsync": ("long", (("unsigned int", "fd"),)),
        "ftruncate": (
            "long",
            (("unsigned int", "fd"), ("unsigned long", "length")),
        ),
        "ftruncate64": (
            "long",
            (("unsigned int", "fd"), ("loff_t", "length")),
        ),
        "futex": (
            "long",
            (
                ("u32 *", "uaddr"),
                ("int", "op"),
                ("u32", "val"),
                ("struct timespec *", "utime"),
                ("u32 *", "uaddr2"),
                ("u32", "val3"),
            ),
        ),
        "futex_time32": (
            "long",
            (
                ("u32 *", "uaddr"),
                ("int", "op"),
                ("u32", "val"),
                ("struct old_timespec32 *", "utime"),
                ("u32 *", "uaddr2"),
                ("u32", "val3"),
            ),
        ),
        "futimesat": (
            "long",
            (
                ("int", "dfd"),
                ("const char *", "filename"),
                ("struct old_timeval *", "utimes"),
            ),
        ),
        "futimesat_time32": (
            "long",
            (
                ("unsigned int", "dfd"),
                ("const char *", "filename"),
                ("struct old_timeval32 *", "t"),
            ),
        ),
        "get_kernel_syms": ("long", (("struct kernel_sym *", "table"))),
        "get_mempolicy": (
            "long",
            (
                ("int *", "policy"),
                ("unsigned long *", "nmask"),
                ("unsigned long", "maxnode"),
                ("unsigned long", "addr"),
                ("unsigned long", "flags"),
            ),
        ),
        "get_robust_list": (
            "long",
            (
                ("int", "pid"),
                ("struct robust_list_head * *", "head_ptr"),
                ("size_t *", "len_ptr"),
            ),
        ),
        "get_thread_area": ("long", (("struct user_desc *", "u_info"))),
        "getcpu": (
            "long",
            (
                ("unsigned *", "cpu"),
                ("unsigned *", "node"),
                ("struct getcpu_cache *", "cache"),
            ),
        ),
        "getcwd": (
            "long",
            (("char *", "pathname"), ("unsigned long", "size")),
        ),
        "getdents": (
            "long",
            (
                ("unsigned int", "fd"),
                ("struct linux_dirent *", "dirent"),
                ("unsigned int", "count"),
            ),
        ),
        "getdents64": (
            "long",
            (
                ("unsigned int", "fd"),
                ("struct linux_dirent64 *", "dirent"),
                ("unsigned int", "count"),
            ),
        ),
        "getegid": ("long", ()),
        "getegid16": ("long", ()),
        "geteuid": ("long", ()),
        "geteuid16": ("long", ()),
        "getgid": ("long", ()),
        "getgid16": ("long", ()),
        "getgroups": (
            "long",
            (("int", "gidsetsize"), ("gid_t *", "grouplist")),
        ),
        "getgroups16": (
            "long",
            (("int", "gidsetsize"), ("old_gid_t *", "grouplist")),
        ),
        "gethostname": ("long", (("char *", "name"), ("int", "len"))),
        "getitimer": (
            "long",
            (("int", "which"), ("struct itimerval *", "value")),
        ),
        "getpeername": (
            "long",
            (
                ("int", "sockfd"),
                ("struct sockaddr *", "addr"),
                ("int *", "addrlen"),
            ),
        ),
        "getpgid": ("long", (("pid_t", "pid"),)),
        "getpgrp": ("long", ()),
        "getpid": ("long", ()),
        "getppid": ("long", ()),
        "getpriority": ("long", (("int", "which"), ("int", "who"))),
        "getrandom": (
            "long",
            (
                ("void *", "buf"),
                ("size_t", "count"),
                ("unsigned int", "flags"),
            ),
        ),
        "getresgid": (
            "long",
            (("gid_t *", "rgid"), ("gid_t *", "egid"), ("gid_t *", "sgid")),
        ),
        "getresgid16": (
            "long",
            (
                ("old_gid_t *", "rgid"),
                ("old_gid_t *", "egid"),
                ("old_gid_t *", "sgid"),
            ),
        ),
        "getresuid": (
            "long",
            (("uid_t *", "ruid"), ("uid_t *", "euid"), ("uid_t *", "suid")),
        ),
        "getresuid16": (
            "long",
            (
                ("old_uid_t *", "ruid"),
                ("old_uid_t *", "euid"),
                ("old_uid_t *", "suid"),
            ),
        ),
        "getrlimit": (
            "long",
            (("unsigned int", "resource"), ("struct rlimit *", "rlim")),
        ),
        "ugetrlimit": (
            "long",
            (("unsigned int", "resource"), ("struct rlimit *", "rlim")),
        ),
        "getrusage": ("long", (("int", "who"), ("struct rusage *", "ru"))),
        "getsid": ("long", (("pid_t", "pid"),)),
        "getsockname": (
            "long",
            (
                ("int", "sockfd"),
                ("struct sockaddr *", "addr"),
                ("int *", "addrlen"),
            ),
        ),
        "getsockopt": (
            "long",
            (
                ("int", "fd"),
                ("int", "level"),
                ("int", "optname"),
                ("void *", "optval"),
                ("int *", "optlen"),
            ),
        ),
        "gettid": ("long", ()),
        "gettimeofday": (
            "long",
            (("struct timeval *", "tv"), ("struct timezone *", "tz")),
        ),
        "getuid": ("long", ()),
        "getuid16": ("long", ()),
        "getuid32": ("long", ()),
        "getxattr": (
            "long",
            (
                ("const char *", "path"),
                ("const char *", "name"),
                ("void *", "value"),
                ("size_t", "size"),
            ),
        ),
        "init_module": (
            "long",
            (
                ("void *", "umod"),
                ("unsigned long", "len"),
                ("const char *", "uargs"),
            ),
        ),
        "inotify_add_watch": (
            "long",
            (("int", "fd"), ("const char *", "path"), ("u32", "mask")),
        ),
        "inotify_init": ("long", ()),
        "inotify_init1": ("long", (("int", "flags"),)),
        "inotify_rm_watch": ("long", (("int", "fd"), ("__s32", "wd"))),
        "io_cancel": (
            "long",
            (
                ("aio_context_t", "ctx_id"),
                ("struct iocb *", "iocb"),
                ("struct io_event *", "result"),
            ),
        ),
        "io_destroy": ("long", (("aio_context_t", "ctx"),)),
        "io_getevents": (
            "long",
            (
                ("aio_context_t", "ctx_id"),
                ("long", "min_nr"),
                ("long", "nr"),
                ("struct io_event *", "events"),
                ("struct timespec *", "timeout"),
            ),
        ),
        "io_getevents_time32": (
            "long",
            (
                ("__u32", "ctx_id"),
                ("__s32", "min_nr"),
                ("__s32", "nr"),
                ("struct io_event *", "events"),
                ("struct old_timespec32 *", "timeout"),
            ),
        ),
        "io_pgetevents": (
            "long",
            (
                ("aio_context_t", "ctx_id"),
                ("long", "min_nr"),
                ("long", "nr"),
                ("struct io_event *", "events"),
                ("struct timespec *", "timeout"),
                ("const struct __aio_sigset *", "sig"),
            ),
        ),
        "io_pgetevents_time32": (
            "long",
            (
                ("aio_context_t", "ctx_id"),
                ("long", "min_nr"),
                ("long", "nr"),
                ("struct io_event *", "events"),
                ("struct old_timespec32 *", "timeout"),
                ("const struct __aio_sigset *", "sig"),
            ),
        ),
        "io_setup": (
            "long",
            (("unsigned", "nr_reqs"), ("aio_context_t *", "ctx")),
        ),
        "io_submit": (
            "long",
            (
                ("aio_context_t", "ctx_id"),
                ("long", "nr"),
                ("struct iocb * *", "iocbpp"),
            ),
        ),
        "io_uring_enter": (
            "long",
            (
                ("unsigned int", "fd"),
                ("u32", "to_submit"),
                ("u32", "min_complete"),
                ("u32", "flags"),
                ("const sigset_t *", "sig"),
                ("size_t", "sigsz"),
            ),
        ),
        "io_uring_register": (
            "long",
            (
                ("unsigned int", "fd"),
                ("unsigned int", "op"),
                ("void *", "arg"),
                ("unsigned int", "nr_args"),
            ),
        ),
        "io_uring_setup": (
            "long",
            (("u32", "entries"), ("struct io_uring_params *", "p")),
        ),
        "ioctl": (
            "long",
            (
                ("unsigned int", "fd"),
                ("unsigned int", "cmd"),
                ("unsigned long", "arg"),
            ),
        ),
        "ioperm": (
            "long",
            (
                ("unsigned long", "from"),
                ("unsigned long", "num"),
                ("int", "on"),
            ),
        ),
        "iopl": (
            "long",
            (("int", "level")),
        ),
        "ioprio_get": ("long", (("int", "which"), ("int", "who"))),
        "ioprio_set": (
            "long",
            (("int", "which"), ("int", "who"), ("int", "ioprio")),
        ),
        "ipc": (
            "long",
            (
                ("unsigned int", "call"),
                ("int", "first"),
                ("unsigned long", "second"),
                ("unsigned long", "third"),
                ("void *", "ptr"),
                ("long", "fifth"),
            ),
        ),
        "kcmp": (
            "long",
            (
                ("pid_t", "pid1"),
                ("pid_t", "pid2"),
                ("int", "type"),
                ("unsigned long", "idx1"),
                ("unsigned long", "idx2"),
            ),
        ),
        "kexec_file_load": (
            "long",
            (
                ("int", "kernel_fd"),
                ("int", "initrd_fd"),
                ("unsigned long", "cmdline_len"),
                ("const char *", "cmdline_ptr"),
                ("unsigned long", "flags"),
            ),
        ),
        "kexec_load": (
            "long",
            (
                ("unsigned long", "entry"),
                ("unsigned long", "nr_segments"),
                ("struct kexec_segment *", "segments"),
                ("unsigned long", "flags"),
            ),
        ),
        "keyctl": (
            "long",
            (
                ("int", "cmd"),
                ("unsigned long", "arg2"),
                ("unsigned long", "arg3"),
                ("unsigned long", "arg4"),
                ("unsigned long", "arg5"),
            ),
        ),
        "kill": ("long", (("int", "pid"), ("int", "sig"))),
        "lchown": (
            "long",
            (
                ("const char *", "filename"),
                ("uid_t", "user"),
                ("gid_t", "group"),
            ),
        ),
        "lchown16": (
            "long",
            (
                ("const char *", "filename"),
                ("old_uid_t", "user"),
                ("old_gid_t", "group"),
            ),
        ),
        "lgetxattr": (
            "long",
            (
                ("const char *", "path"),
                ("const char *", "name"),
                ("void *", "value"),
                ("size_t", "size"),
            ),
        ),
        "link": (
            "long",
            (("const char *", "oldname"), ("const char *", "newname")),
        ),
        "linkat": (
            "long",
            (
                ("int", "olddfd"),
                ("const char *", "oldname"),
                ("int", "newdfd"),
                ("const char *", "newname"),
                ("int", "flags"),
            ),
        ),
        "listen": ("long", (("int", "sockfd"), ("int", "backlog"))),
        "listxattr": (
            "long",
            (
                ("const char *", "path"),
                ("char char *", "list"),
                ("size_t", "size"),
            ),
        ),
        "llistxattr": (
            "long",
            (
                ("const char *", "path"),
                ("char char *", "list"),
                ("size_t", "size"),
            ),
        ),
        "llseek": (
            "long",
            (
                ("unsigned int", "fd"),
                ("unsigned long", "offset_high"),
                ("unsigned long", "offset_low"),
                ("loff_t *", "result"),
                ("unsigned int", "whence"),
            ),
        ),
        "lookup_dcookie": (
            "long",
            (("u64", "cookie64"), ("char *", "buf"), ("size_t", "len")),
        ),
        "lremovexattr": (
            "long",
            (("const char *", "path"), ("const char *", "name")),
        ),
        "lseek": (
            "long",
            (
                ("unsigned int", "fd"),
                ("off_t", "offset"),
                ("unsigned int", "whence"),
            ),
        ),
        "lsetxattr": (
            "long",
            (
                ("const char *", "path"),
                ("const char *", "name"),
                ("const void *", "value"),
                ("size_t", "size"),
                ("int", "flags"),
            ),
        ),
        "lstat": (
            "long",
            (
                ("const char *", "filename"),
                ("struct __old_kernel_stat *", "statbuf"),
            ),
        ),
        "lstat64": (
            "long",
            (("const char *", "filename"), ("struct stat64 *", "statbuf")),
        ),
        "madvise": (
            "long",
            (
                ("unsigned long", "start"),
                ("size_t", "len"),
                ("int", "behavior"),
            ),
        ),
        "mbind": (
            "long",
            (
                ("unsigned long", "start"),
                ("unsigned long", "len"),
                ("unsigned long", "mode"),
                ("const unsigned long *", "nmask"),
                ("unsigned long", "maxnode"),
                ("unsigned", "flags"),
            ),
        ),
        "membarrier": ("long", (("int", "cmd"), ("int", "flags"))),
        "memfd_create": (
            "long",
            (("const char *", "uname_ptr"), ("unsigned int", "flags")),
        ),
        "migrate_pages": (
            "long",
            (
                ("pid_t", "pid"),
                ("unsigned long", "maxnode"),
                ("const unsigned long *", "from"),
                ("const unsigned long *", "to"),
            ),
        ),
        "mincore": (
            "long",
            (
                ("unsigned long", "start"),
                ("size_t", "len"),
                ("unsigned char *", "vec"),
            ),
        ),
        "mkdir": ("long", (("const char *", "pathname"), ("umode_t", "mode"))),
        "mkdirat": (
            "long",
            (
                ("int", "dfd"),
                ("const char *", "pathname"),
                ("umode_t", "mode"),
            ),
        ),
        "mknod": (
            "long",
            (
                ("const char *", "filename"),
                ("umode_t", "mode"),
                ("unsigned", "dev"),
            ),
        ),
        "mknodat": (
            "long",
            (
                ("int", "dfd"),
                ("const char *", "filename"),
                ("umode_t", "mode"),
                ("unsigned", "dev"),
            ),
        ),
        "mlock": ("long", (("unsigned long", "start"), ("size_t", "len"))),
        "mlock2": (
            "long",
            (("unsigned long", "start"), ("size_t", "len"), ("int", "flags")),
        ),
        "mlockall": ("long", (("int", "flags"),)),
        "mmap_pgoff": (
            "long",
            (
                ("unsigned long", "addr"),
                ("unsigned long", "len"),
                ("unsigned long", "prot"),
                ("unsigned long", "flags"),
                ("unsigned long", "fd"),
                ("unsigned long", "pgoff"),
            ),
        ),
        "mmap": (
            "long",
            (
                ("unsigned long", "addr"),
                ("unsigned long", "len"),
                ("unsigned long", "prot"),
                ("unsigned long", "flags"),
                ("unsigned long", "fd"),
                ("unsigned long", "pgoff"),
            ),
        ),
        "mmap2": (
            "long",
            (
                ("unsigned long", "addr"),
                ("unsigned long", "len"),
                ("unsigned long", "prot"),
                ("unsigned long", "flags"),
                ("unsigned long", "fd"),
                ("unsigned long", "pgoff"),
            ),
        ),
        "move_mount": (
            "long",
            (
                ("int", "from_dfd"),
                ("const char *", "from_path"),
                ("int", "to_dfd"),
                ("const char *", "to_path"),
                ("unsigned int", "ms_flags"),
            ),
        ),
        "arch_prctl": ("int", (("int", "code"), ("unsigned long", "addr"))),
        "mount": (
            "long",
            (
                ("const char *", "dev_name"),
                ("const char *", "dir_name"),
                ("const char *", "type"),
                ("unsigned long", "flags"),
                ("void *", "data"),
            ),
        ),
        "move_pages": (
            "long",
            (
                ("pid_t", "pid"),
                ("unsigned long", "nr_pages"),
                ("const void * *", "pages"),
                ("const int *", "nodes"),
                ("int *", "status"),
                ("int", "flags"),
            ),
        ),
        "mprotect": (
            "long",
            (
                ("unsigned long", "start"),
                ("size_t", "len"),
                ("unsigned long", "prot"),
            ),
        ),
        "mq_getsetattr": (
            "long",
            (
                ("mqd_t", "mqdes"),
                ("const struct mq_attr *", "mqstat"),
                ("struct mq_attr *", "omqstat"),
            ),
        ),
        "mq_notify": (
            "long",
            (("mqd_t", "mqdes"), ("const struct sigevent *", "notification")),
        ),
        "mq_open": (
            "long",
            (
                ("const char *", "name"),
                ("int", "oflag"),
                ("umode_t", "mode"),
                ("struct mq_attr *", "attr"),
            ),
        ),
        "mq_timedreceive": (
            "long",
            (
                ("mqd_t", "mqdes"),
                ("char *", "msg_ptr"),
                ("size_t", "msg_len"),
                ("unsigned int *", "msg_prio"),
                ("const struct timespec *", "abs_timeout"),
            ),
        ),
        "mq_timedreceive_time32": (
            "long",
            (
                ("mqd_t", "mqdes"),
                ("char *", "u_msg_ptr"),
                ("unsigned int", "msg_len"),
                ("unsigned int *", "u_msg_prio"),
                ("const struct old_timespec32 *", "u_abs_timeout"),
            ),
        ),
        "mq_timedsend": (
            "long",
            (
                ("mqd_t", "mqdes"),
                ("const char *", "msg_ptr"),
                ("size_t", "msg_len"),
                ("unsigned int", "msg_prio"),
                ("const struct timespec *", "abs_timeout"),
            ),
        ),
        "mq_timedsend_time32": (
            "long",
            (
                ("mqd_t", "mqdes"),
                ("const char *", "u_msg_ptr"),
                ("unsigned int", "msg_len"),
                ("unsigned int", "msg_prio"),
                ("const struct old_timespec32 *", "u_abs_timeout"),
            ),
        ),
        "mq_unlink": ("long", (("const char *", "name"),)),
        "mremap": (
            "long",
            (
                ("unsigned long", "addr"),
                ("unsigned long", "old_len"),
                ("unsigned long", "new_len"),
                ("unsigned long", "flags"),
                ("unsigned long", "new_addr"),
            ),
        ),
        "msgctl": (
            "long",
            (("int", "msqid"), ("int", "cmd"), ("struct msqid_ds *", "buf")),
        ),
        "msgget": ("long", (("key_t", "key"), ("int", "msgflg"))),
        "msgrcv": (
            "long",
            (
                ("int", "msqid"),
                ("struct msgbuf *", "msgp"),
                ("size_t", "msgsz"),
                ("long", "msgtyp"),
                ("int", "msgflg"),
            ),
        ),
        "msgsnd": (
            "long",
            (
                ("int", "msqid"),
                ("struct msgbuf *", "msgp"),
                ("size_t", "msgsz"),
                ("int", "msgflg"),
            ),
        ),
        "msync": (
            "long",
            (("unsigned long", "start"), ("size_t", "len"), ("int", "flags")),
        ),
        "munlock": ("long", (("unsigned long", "start"), ("size_t", "len"))),
        "munlockall": ("long", ()),
        "munmap": ("long", (("unsigned long", "addr"), ("size_t", "len"))),
        "name_to_handle_at": (
            "long",
            (
                ("int", "dfd"),
                ("const char *", "name"),
                ("struct file_handle *", "handle"),
                ("int *", "mnt_id"),
                ("int", "flag"),
            ),
        ),
        "nanosleep": (
            "long",
            (("struct timespec *", "rqtp"), ("struct timespec *", "rmtp")),
        ),
        "nanosleep_time32": (
            "long",
            (
                ("struct old_timespec32 *", "rqtp"),
                ("struct old_timespec32 *", "rmtp"),
            ),
        ),
        "newfstat": (
            "long",
            (("unsigned int", "fd"), ("struct stat *", "statbuf")),
        ),
        "newfstatat": (
            "long",
            (
                ("int", "dfd"),
                ("const char *", "filename"),
                ("struct stat *", "statbuf"),
                ("int", "flag"),
            ),
        ),
        "newlstat": (
            "long",
            (("const char *", "filename"), ("struct stat *", "statbuf")),
        ),
        "newstat": (
            "long",
            (("const char *", "filename"), ("struct stat *", "statbuf")),
        ),
        "newuname": ("long", (("struct new_utsname *", "name"),)),
        "ni_syscall": ("long", ()),
        "nice": ("long", (("int", "increment"),)),
        "old_getrlimit": (
            "long",
            (("unsigned int", "resource"), ("struct rlimit *", "rlim")),
        ),
        "old_mmap": ("long", (("struct mmap_arg_struct *", "arg"),)),
        "old_msgctl": (
            "long",
            (("int", "msqid"), ("int", "cmd"), ("struct msqid_ds *", "buf")),
        ),
        "old_readdir": (
            "long",
            (
                ("unsigned int", "fd"),
                ("struct old_linux_dirent *", "dirp"),
                ("unsigned int", "count"),
            ),
        ),
        "old_select": ("long", (("struct sel_arg_struct *", "arg"),)),
        "old_semctl": (
            "long",
            (
                ("int", "semid"),
                ("int", "semnum"),
                ("int", "cmd"),
                ("unsigned long", "arg"),
            ),
        ),
        "old_shmctl": (
            "long",
            (("int", "shmid"), ("int", "cmd"), ("struct shmid_ds *", "buf")),
        ),
        "oldumount": ("long", (("char char *", "name"),)),
        "olduname": ("long", (("struct oldold_utsname *", "buf"),)),
        "open": (
            "long",
            (
                ("const char *", "filename"),
                ("int", "flags"),
                ("umode_t", "mode"),
            ),
        ),
        "open_by_handle_at": (
            "long",
            (
                ("int", "mountdirfd"),
                ("struct file_handle *", "handle"),
                ("int", "flags"),
            ),
        ),
        "open_tree": (
            "long",
            (("int", "dfd"), ("const char *", "path"), ("unsigned", "flags")),
        ),
        "openat": (
            "long",
            (
                ("int", "dfd"),
                ("const char *", "filename"),
                ("int", "flags"),
                ("umode_t", "mode"),
            ),
        ),
        "openat2": (
            "long",
            (
                ("int", "dfd"),
                ("const char *", "filename"),
                ("struct open_how *", "how"),
                ("size_t", "size"),
            ),
        ),
        "pause": ("long", ()),
        "pciconfig_iobase": (
            "long",
            (
                ("long", "which"),
                ("unsigned long", "bus"),
                ("unsigned long", "devfn"),
            ),
        ),
        "pciconfig_read": (
            "long",
            (
                ("unsigned long", "bus"),
                ("unsigned long", "dfn"),
                ("unsigned long", "off"),
                ("unsigned long", "len"),
                ("void *", "buf"),
            ),
        ),
        "pciconfig_write": (
            "long",
            (
                ("unsigned long", "bus"),
                ("unsigned long", "dfn"),
                ("unsigned long", "off"),
                ("unsigned long", "len"),
                ("void *", "buf"),
            ),
        ),
        "perf_event_open": (
            "long",
            (
                ("struct perf_event_attr *", "attr_uptr"),
                ("pid_t", "pid"),
                ("int", "cpu"),
                ("int", "group_fd"),
                ("unsigned long", "flags"),
            ),
        ),
        "personality": ("long", (("unsigned int", "personality"),)),
        "pidfd_getfd": (
            "long",
            (("int", "pidfd"), ("int", "fd"), ("unsigned int", "flags")),
        ),
        "pidfd_open": ("long", (("pid_t", "pid"), ("unsigned int", "flags"))),
        "pidfd_send_signal": (
            "long",
            (
                ("int", "pidfd"),
                ("int", "sig"),
                ("siginfo_t *", "info"),
                ("unsigned int", "flags"),
            ),
        ),
        "pipe": ("long", (("int *", "fildes"),)),
        "pipe2": ("long", (("int *", "fildes"), ("int", "flags"))),
        "pivot_root": (
            "long",
            (("const char *", "new_root"), ("const char *", "put_old")),
        ),
        "pkey_alloc": (
            "long",
            (("unsigned long", "flags"), ("unsigned long", "init_val")),
        ),
        "pkey_free": ("long", (("int", "pkey"),)),
        "pkey_mprotect": (
            "long",
            (
                ("unsigned long", "start"),
                ("size_t", "len"),
                ("unsigned long", "prot"),
                ("int", "pkey"),
            ),
        ),
        "poll": (
            "long",
            (
                ("struct pollfd *", "ufds"),
                ("unsigned int", "nfds"),
                ("int", "timeout"),
            ),
        ),
        "ppoll": (
            "long",
            (
                ("struct pollfd *", "fds"),
                ("unsigned int", "nfds"),
                ("struct timespec *", "tmo_p"),
                ("const sigset_t *", "sigmask"),
            ),
        ),
        "ppoll_time32": (
            "long",
            (
                ("struct pollfd *", "fds"),
                ("unsigned int", "nfds"),
                ("struct old_timespec *", "tmo_p"),
                ("const sigset_t *", "sigmask"),
            ),
        ),
        "prctl": (
            "long",
            (
                ("int", "option"),
                ("unsigned long", "arg2"),
                ("unsigned long", "arg3"),
                ("unsigned long", "arg4"),
                ("unsigned long", "arg5"),
            ),
        ),
        "pread64": (
            "long",
            (
                ("unsigned int", "fd"),
                ("void *", "buf"),
                ("size_t", "count"),
                ("loff_t", "pos"),
            ),
        ),
        "preadv": (
            "long",
            (
                ("unsigned long", "fd"),
                ("const struct iovec *", "vec"),
                ("unsigned long", "vlen"),
                ("unsigned long", "pos_l"),
                ("unsigned long", "pos_h"),
            ),
        ),
        "preadv2": (
            "long",
            (
                ("unsigned long", "fd"),
                ("const struct iovec *", "vec"),
                ("unsigned long", "vlen"),
                ("unsigned long", "pos_l"),
                ("unsigned long", "pos_h"),
                ("rwf_t", "flags"),
            ),
        ),
        "prlimit64": (
            "long",
            (
                ("pid_t", "pid"),
                ("unsigned int", "resource"),
                ("const struct rlimit64 *", "new_rlim"),
                ("struct rlimit64 *", "old_rlim"),
            ),
        ),
        "process_vm_readv": (
            "long",
            (
                ("pid_t", "pid"),
                ("const struct iovec *", "lvec"),
                ("unsigned long", "liovcnt"),
                ("const struct iovec *", "rvec"),
                ("unsigned long", "riovcnt"),
                ("unsigned long", "flags"),
            ),
        ),
        "process_vm_writev": (
            "long",
            (
                ("pid_t", "pid"),
                ("const struct iovec *", "lvec"),
                ("unsigned long", "liovcnt"),
                ("const struct iovec *", "rvec"),
                ("unsigned long", "riovcnt"),
                ("unsigned long", "flags"),
            ),
        ),
        "pselect6": (
            "long",
            (
                ("int", "nfds"),
                ("fd_set *", "readfds"),
                ("fd_set *", "writefds"),
                ("fd_set *", "exceptfds"),
                ("struct timespec *", "timeout"),
                ("void *", "sigmask"),
            ),
        ),
        "pselect6_time32": (
            "long",
            (
                ("int", "nfds"),
                ("fd_set *", "readfds"),
                ("fd_set *", "writefds"),
                ("fd_set *", "exceptfds"),
                ("struct old_timespec32 *", ""),
                ("void *", "sigmask"),
            ),
        ),
        "ptrace": (
            "long",
            (
                ("long", "request"),
                ("long", "pid"),
                ("unsigned long", "addr"),
                ("unsigned long", "data"),
            ),
        ),
        "pwrite64": (
            "long",
            (
                ("unsigned int", "fd"),
                ("const char *", "buf"),
                ("size_t", "count"),
                ("loff_t", "pos"),
            ),
        ),
        "pwritev": (
            "long",
            (
                ("unsigned long", "fd"),
                ("const struct iovec *", "vec"),
                ("unsigned long", "vlen"),
                ("unsigned long", "pos_l"),
                ("unsigned long", "pos_h"),
            ),
        ),
        "pwritev2": (
            "long",
            (
                ("unsigned long", "fd"),
                ("const struct iovec *", "vec"),
                ("unsigned long", "vlen"),
                ("unsigned long", "pos_l"),
                ("unsigned long", "pos_h"),
                ("rwf_t", "flags"),
            ),
        ),
        "quotactl": (
            "long",
            (
                ("unsigned int", "cmd"),
                ("const char *", "special"),
                ("qid_t", "id"),
                ("void *", "addr"),
            ),
        ),
        "query_module": (
            "long",
            (
                ("const char *", "name"),
                ("int", "which"),
                ("void *", "buf"),
                ("int", "bufsize"),
                ("int *", "ret"),
            ),
        ),
        "read": (
            "long",
            (("unsigned int", "fd"), ("void *", "buf"), ("size_t", "count")),
        ),
        "readahead": (
            "long",
            (("int", "fd"), ("loff_t", "offset"), ("size_t", "count")),
        ),
        "readlink": (
            "long",
            (("const char *", "path"), ("char *", "buf"), ("int", "bufsiz")),
        ),
        "readlinkat": (
            "long",
            (
                ("int", "dfd"),
                ("const char *", "path"),
                ("char *", "buf"),
                ("int", "bufsiz"),
            ),
        ),
        "readv": (
            "long",
            (
                ("unsigned long", "fd"),
                ("const struct iovec *", "vec"),
                ("unsigned long", "vlen"),
            ),
        ),
        "reboot": (
            "long",
            (
                ("int", "magic1"),
                ("int", "magic2"),
                ("unsigned int", "cmd"),
                ("void *", "arg"),
            ),
        ),
        "recv": (
            "long",
            (
                ("int", "sockfd"),
                ("void *", "buf"),
                ("size_t", "len"),
                ("unsigned", "flags"),
            ),
        ),
        "recvfrom": (
            "long",
            (
                ("int", "sockfd"),
                ("void *", "buf"),
                ("size_t", "len"),
                ("unsigned", "flags"),
                ("struct sockaddr *", "src_addr"),
                ("int *", "addrlen"),
            ),
        ),
        "recvmmsg": (
            "long",
            (
                ("int", "fd"),
                ("struct mmsghdr *", "msg"),
                ("unsigned int", "vlen"),
                ("unsigned", "flags"),
                ("struct timespec *", "timeout"),
            ),
        ),
        "recvmmsg_time32": (
            "long",
            (
                ("int", "fd"),
                ("struct mmsghdr *", "msg"),
                ("unsigned int", "vlen"),
                ("unsigned", "flags"),
                ("struct old_timespec32 *", "timeout"),
            ),
        ),
        "recvmsg": (
            "long",
            (
                ("int", "fd"),
                ("struct user_msghdr *", "msg"),
                ("unsigned", "flags"),
            ),
        ),
        "remap_file_pages": (
            "long",
            (
                ("unsigned long", "start"),
                ("unsigned long", "size"),
                ("unsigned long", "prot"),
                ("unsigned long", "pgoff"),
                ("unsigned long", "flags"),
            ),
        ),
        "removexattr": (
            "long",
            (("const char *", "path"), ("const char *", "name")),
        ),
        "rename": (
            "long",
            (("const char *", "oldname"), ("const char *", "newname")),
        ),
        "renameat": (
            "long",
            (
                ("int", "olddfd"),
                ("const char *", "oldname"),
                ("int", "newdfd"),
                ("const char *", "newname"),
            ),
        ),
        "renameat2": (
            "long",
            (
                ("int", "olddfd"),
                ("const char *", "oldname"),
                ("int", "newdfd"),
                ("const char *", "newname"),
                ("unsigned int", "flags"),
            ),
        ),
        "request_key": (
            "long",
            (
                ("const char *", "_type"),
                ("const char *", "_description"),
                ("const char *", "_callout_info"),
                ("key_serial_t", "destringid"),
            ),
        ),
        "restart_syscall": ("long", ()),
        "rmdir": ("long", (("const char *", "pathname"),)),
        "rseq": (
            "long",
            (
                ("struct rseq *", "rseq"),
                ("uint32_t", "rseq_len"),
                ("int", "flags"),
                ("uint32_t", "sig"),
            ),
        ),
        "rt_sigaction": (
            "long",
            (
                ("int", "signum"),
                ("const struct sigaction *", "act"),
                ("struct sigaction *", "oldact"),
                ("size_t", ""),
            ),
        ),
        "rt_sigpending": (
            "long",
            (("sigset_t *", "set"), ("size_t", "sigsetsize")),
        ),
        "rt_sigreturn": ("long", ()),
        "rt_sigprocmask": (
            "long",
            (
                ("int", "how"),
                ("sigset_t *", "set"),
                ("sigset_t *", "oset"),
                ("size_t", "sigsetsize"),
            ),
        ),
        "rt_sigqueueinfo": (
            "long",
            (("int", "pid"), ("int", "sig"), ("siginfo_t *", "uinfo")),
        ),
        "rt_sigsuspend": (
            "long",
            (("sigset_t *", "unewset"), ("size_t", "sigsetsize")),
        ),
        "rt_sigtimedwait": (
            "long",
            (
                ("const sigset_t *", "uthese"),
                ("siginfo_t *", "uinfo"),
                ("const struct timespec *", "uts"),
                ("size_t", "sigsetsize"),
            ),
        ),
        "rt_sigtimedwait_time32": (
            "long",
            (
                ("const sigset_t *", "uthese"),
                ("siginfo_t *", "uinfo"),
                ("const struct old_timespec32 *", "uts"),
                ("size_t", "sigsetsize"),
            ),
        ),
        "rt_tgsigqueueinfo": (
            "long",
            (
                ("pid_t", "tgid"),
                ("pid_t", "pid"),
                ("int", "sig"),
                ("siginfo_t *", "uinfo"),
            ),
        ),
        "sched_get_priority_max": ("long", (("int", "policy"),)),
        "sched_get_priority_min": ("long", (("int", "policy"),)),
        "sched_getaffinity": (
            "long",
            (
                ("pid_t", "pid"),
                ("unsigned int", "len"),
                ("unsigned long *", "user_mask_ptr"),
            ),
        ),
        "sched_getattr": (
            "long",
            (
                ("pid_t", "pid"),
                ("struct sched_attr *", "attr"),
                ("unsigned int", "size"),
                ("unsigned int", "flags"),
            ),
        ),
        "sched_getparam": (
            "long",
            (("pid_t", "pid"), ("struct sched_param *", "param")),
        ),
        "sched_getscheduler": ("long", (("pid_t", "pid"),)),
        "sched_rr_get_interval": (
            "long",
            (("pid_t", "pid"), ("struct timespec *", "interval")),
        ),
        "sched_rr_get_interval_time32": (
            "long",
            (("pid_t", "pid"), ("struct old_timespec32 *", "interval")),
        ),
        "sched_setaffinity": (
            "long",
            (
                ("pid_t", "pid"),
                ("unsigned int", "len"),
                ("unsigned long *", "user_mask_ptr"),
            ),
        ),
        "sched_setattr": (
            "long",
            (
                ("pid_t", "pid"),
                ("struct sched_attr *", "attr"),
                ("unsigned int", "flags"),
            ),
        ),
        "sched_setparam": (
            "long",
            (("pid_t", "pid"), ("struct sched_param *", "param")),
        ),
        "sched_setscheduler": (
            "long",
            (
                ("pid_t", "pid"),
                ("int", "policy"),
                ("struct sched_param *", "param"),
            ),
        ),
        "sched_yield": ("long", ()),
        "seccomp": (
            "long",
            (
                ("unsigned int", "op"),
                ("unsigned int", "flags"),
                ("const char *", "uargs"),
            ),
        ),
        "select": (
            "long",
            (
                ("int", "n"),
                ("fd_set *", "inp"),
                ("fd_set *", "outp"),
                ("fd_set *", "exp"),
                ("struct timeval *", "tvp"),
            ),
        ),
        "newselect": (
            "long",
            (
                ("int", "n"),
                ("fd_set *", "inp"),
                ("fd_set *", "outp"),
                ("fd_set *", "exp"),
                ("struct timeval *", "tvp"),
            ),
        ),
        "semctl": (
            "long",
            (
                ("int", "semid"),
                ("int", "semnum"),
                ("int", "cmd"),
                ("unsigned long", "arg"),
            ),
        ),
        "semget": (
            "long",
            (("key_t", "key"), ("int", "nsems"), ("int", "semflg")),
        ),
        "semop": (
            "long",
            (
                ("int", "semid"),
                ("struct sembuf *", "sops"),
                ("unsigned", "nsops"),
            ),
        ),
        "semtimedop": (
            "long",
            (
                ("int", "semid"),
                ("struct sembuf *", "sops"),
                ("unsigned", "nsops"),
                ("const struct timespec *", "timeout"),
            ),
        ),
        "semtimedop_time32": (
            "long",
            (
                ("int", "semid"),
                ("struct sembuf *", "sops"),
                ("unsigned", "nsops"),
                ("const struct old_timespec32 *", "timeout"),
            ),
        ),
        "send": (
            "long",
            (
                ("int", "sockfd"),
                ("void *", "buf"),
                ("size_t", "len"),
                ("unsigned", "flags"),
            ),
        ),
        "sendfile": (
            "long",
            (
                ("int", "out_fd"),
                ("int", "in_fd"),
                ("off_t *", "offset"),
                ("size_t", "count"),
            ),
        ),
        "sendfile64": (
            "long",
            (
                ("int", "out_fd"),
                ("int", "in_fd"),
                ("loff_t *", "offset"),
                ("size_t", "count"),
            ),
        ),
        "sendmmsg": (
            "long",
            (
                ("int", "fd"),
                ("struct mmsghdr *", "msg"),
                ("unsigned int", "vlen"),
                ("unsigned", "flags"),
            ),
        ),
        "sendmsg": (
            "long",
            (
                ("int", "fd"),
                ("struct user_msghdr *", "msg"),
                ("unsigned", "flags"),
            ),
        ),
        "sendto": (
            "long",
            (
                ("int", "sockfd"),
                ("void *", "buf"),
                ("size_t", "len"),
                ("unsigned", "flags"),
                ("struct sockaddr *", "destAddr"),
                ("int", "addrlen"),
            ),
        ),
        "set_mempolicy": (
            "long",
            (
                ("int", "mode"),
                ("const unsigned long *", "nmask"),
                ("unsigned long", "maxnode"),
            ),
        ),
        "set_robust_list": (
            "long",
            (("struct robust_list_head *", "head"), ("size_t", "len")),
        ),
        "set_tid_address": ("long", (("int *", "tidptr"),)),
        "setdomainname": ("long", (("const char *", "name"), ("int", "len"))),
        "setfsgid": ("long", (("gid_t", "gid"),)),
        "setfsgid16": ("long", (("old_gid_t", "gid"),)),
        "setfsuid": ("long", (("uid_t", "uid"),)),
        "setfsuid16": ("long", (("old_uid_t", "uid"),)),
        "setgid": ("long", (("gid_t", "gid"),)),
        "setgid16": ("long", (("old_gid_t", "gid"),)),
        "setgroups": (
            "long",
            (("int", "gidsetsize"), ("gid_t *", "grouplist")),
        ),
        "setgroups16": (
            "long",
            (("int", "gidsetsize"), ("old_gid_t *", "grouplist")),
        ),
        "sethostname": ("long", (("const char *", "name"), ("int", "len"))),
        "setitimer": (
            "long",
            (
                ("int", "which"),
                ("struct itimerval *", "value"),
                ("struct itimerval *", "ovalue"),
            ),
        ),
        "setns": ("long", (("int", "fd"), ("int", "nstype"))),
        "setpgid": ("long", (("pid_t", "pid"), ("pid_t", "pgid"))),
        "setpriority": (
            "long",
            (("int", "which"), ("int", "who"), ("int", "niceval")),
        ),
        "setregid": ("long", (("gid_t", "rgid"), ("gid_t", "egid"))),
        "setregid16": ("long", (("old_gid_t", "rgid"), ("old_gid_t", "egid"))),
        "setresgid": (
            "long",
            (("gid_t", "rgid"), ("gid_t", "egid"), ("gid_t", "sgid")),
        ),
        "setresgid16": (
            "long",
            (
                ("old_gid_t", "rgid"),
                ("old_gid_t", "egid"),
                ("old_gid_t", "sgid"),
            ),
        ),
        "setresuid": (
            "long",
            (("uid_t", "ruid"), ("uid_t", "euid"), ("uid_t", "suid")),
        ),
        "setresuid16": (
            "long",
            (
                ("old_uid_t", "ruid"),
                ("old_uid_t", "euid"),
                ("old_uid_t", "suid"),
            ),
        ),
        "setreuid": ("long", (("uid_t", "ruid"), ("uid_t", "euid"))),
        "setreuid16": ("long", (("old_uid_t", "ruid"), ("old_uid_t", "euid"))),
        "setrlimit": (
            "long",
            (("unsigned int", "resource"), ("struct rlimit *", "rlim")),
        ),
        "setsid": ("long", ()),
        "setsockopt": (
            "long",
            (
                ("int", "fd"),
                ("int", "level"),
                ("int", "optname"),
                ("const void *", "optval"),
                ("int", "optlen"),
            ),
        ),
        "settimeofday": (
            "long",
            (("struct timeval *", "tv"), ("struct timezone *", "tz")),
        ),
        "setuid": ("long", (("uid_t", "uid"),)),
        "setuid16": ("long", (("old_uid_t", "uid"),)),
        "setxattr": (
            "long",
            (
                ("const char *", "path"),
                ("const char *", "name"),
                ("const void *", "value"),
                ("size_t", "size"),
                ("int", "flags"),
            ),
        ),
        "sgetmask": ("long", ()),
        "shmat": (
            "long",
            (("int", "shmid"), ("const void *", "shmaddr"), ("int", "shmflg")),
        ),
        "shmctl": (
            "long",
            (("int", "shmid"), ("int", "cmd"), ("struct shmid_ds *", "buf")),
        ),
        "shmdt": ("long", (("const void *", "shmaddr"),)),
        "shmget": (
            "long",
            (("key_t", "key"), ("size_t", "size"), ("int", "flag")),
        ),
        "shutdown": ("long", (("int", "sockfd"), ("int", "how"))),
        "sigaction": (
            "long",
            (
                ("int", "signum"),
                ("const struct old_sigaction *", "act"),
                ("struct old_sigaction *", "oldact"),
            ),
        ),
        "sigaltstack": (
            "long",
            (
                ("const struct sigaltstack *", "uss"),
                ("struct sigaltstack *", "uoss"),
            ),
        ),
        "signal": ("long", (("int", "sig"), ("__sighandler_t", "handler"))),
        "signalfd": (
            "long",
            (
                ("int", "ufd"),
                ("sigset_t *", "user_mask"),
                ("size_t", "sizemask"),
            ),
        ),
        "signalfd4": (
            "long",
            (
                ("int", "ufd"),
                ("sigset_t *", "user_mask"),
                ("size_t", "sizemask"),
                ("int", "flags"),
            ),
        ),
        "sigpending": ("long", (("old_sigset_t *", "set"),)),
        "sigprocmask": (
            "long",
            (
                ("int", "how"),
                ("old_sigset_t *", "set"),
                ("old_sigset_t *", "oset"),
            ),
        ),
        "sigsuspend": (
            "long",
            (("int", "unused1"), ("int", "unused2"), ("old_sigset_t", "mask")),
        ),
        "socket": (
            "long",
            (("int", "domain"), ("int", "type"), ("int", "protocol")),
        ),
        "socketcall": ("long", (("int", "call"), ("unsigned long *", "args"))),
        "socketpair": (
            "long",
            (
                ("int", "domain"),
                ("int", "type"),
                ("int", "protocol"),
                ("int *", "sv"),
            ),
        ),
        "splice": (
            "long",
            (
                ("int", "fd_in"),
                ("loff_t *", "off_in"),
                ("int", "fd_out"),
                ("loff_t *", "off_out"),
                ("size_t", "len"),
                ("unsigned int", "flags"),
            ),
        ),
        "spu_create": (
            "long",
            (
                ("const char *", "name"),
                ("unsigned int", "flags"),
                ("umode_t", "mode"),
                ("int", "fd"),
            ),
        ),
        "spu_run": (
            "long",
            (("int", "fd"), ("__u32 *", "unpc"), ("__u32 *", "ustatus")),
        ),
        "ssetmask": ("long", (("int", "newmask"),)),
        "stat": (
            "long",
            (
                ("const char *", "filename"),
                ("struct __old_kernel_stat *", "statbuf"),
            ),
        ),
        "stat64": (
            "long",
            (("const char *", "filename"), ("struct stat64 *", "statbuf")),
        ),
        "statfs": (
            "long",
            (("const char *", "path"), ("struct statfs *", "buf")),
        ),
        "statfs64": (
            "long",
            (
                ("const char *", "path"),
                ("size_t", "sz"),
                ("struct statfs64 *", "buf"),
            ),
        ),
        "statx": (
            "long",
            (
                ("int", "dfd"),
                ("const char *", "path"),
                ("unsigned", "flags"),
                ("unsigned", "mask"),
                ("struct statx *", "statxbuf"),
            ),
        ),
        "stime": ("long", (("old_time_t *", "tptr"),)),
        "stime32": ("long", (("old_time32_t *", "tptr"),)),
        "swapoff": ("long", (("const char *", "specialfile"),)),
        "swapon": (
            "long",
            (("const char *", "specialfile"), ("int", "swap_flags")),
        ),
        "symlink": (
            "long",
            (("const char *", "old"), ("const char *", "new")),
        ),
        "symlinkat": (
            "long",
            (
                ("const char *", "oldname"),
                ("int", "newdfd"),
                ("const char *", "newname"),
            ),
        ),
        "sync": ("long", ()),
        "sync_file_range": (
            "long",
            (
                ("int", "fd"),
                ("loff_t", "offset"),
                ("loff_t", "nbytes"),
                ("unsigned int", "flags"),
            ),
        ),
        "sync_file_range2": (
            "long",
            (
                ("int", "fd"),
                ("unsigned int", "flags"),
                ("loff_t", "offset"),
                ("loff_t", "nbytes"),
            ),
        ),
        "syncfs": ("long", (("int", "fd"),)),
        "sysctl": ("long", (("struct __sysctl_args *", "args"),)),
        "sysfs": (
            "long",
            (
                ("int", "option"),
                ("unsigned long", "arg1"),
                ("unsigned long", "arg2"),
            ),
        ),
        "sysinfo": ("long", (("struct sysinfo *", "info"),)),
        "syslog": (
            "long",
            (("int", "type"), ("char *", "buf"), ("int", "len")),
        ),
        "tee": (
            "long",
            (
                ("int", "fdin"),
                ("int", "fdout"),
                ("size_t", "len"),
                ("unsigned int", "flags"),
            ),
        ),
        "tgkill": ("long", (("int", "tgid"), ("int", "pid"), ("int", "sig"))),
        "time": ("long", (("old_time_t *", "tloc"),)),
        "time32": ("long", (("old_time32_t *", "tloc"),)),
        "timer_create": (
            "long",
            (
                ("clockid_t", "which_clock"),
                ("struct sigevent *", "timer_event_spec"),
                ("timer_t *", "created_timer_id"),
            ),
        ),
        "timer_delete": ("long", (("timer_t", "timer_id"),)),
        "timer_getoverrun": ("long", (("timer_t", "timer_id"),)),
        "timer_gettime": (
            "long",
            (("timer_t", "timer_id"), ("struct itimerspec *", "setting")),
        ),
        "timer_gettime32": (
            "long",
            (
                ("timer_t", "timer_id"),
                ("struct old_itimerspec32 *", "setting"),
            ),
        ),
        "timer_settime": (
            "long",
            (
                ("timer_t", "timer_id"),
                ("int", "flags"),
                ("const struct itimerspec *", "new_setting"),
                ("struct itimerspec *", "old_setting"),
            ),
        ),
        "timer_settime32": (
            "long",
            (
                ("timer_t", "timer_id"),
                ("int", "flags"),
                ("struct old_itimerspec32 *", "new"),
                ("struct old_itimerspec32 *", "old"),
            ),
        ),
        "timerfd_create": ("long", (("int", "clockid"), ("int", "flags"))),
        "timerfd_gettime": (
            "long",
            (("int", "ufd"), ("struct itimerspec *", "otmr")),
        ),
        "timerfd_gettime32": (
            "long",
            (("int", "ufd"), ("struct old_itimerspec32 *", "otmr")),
        ),
        "timerfd_settime": (
            "long",
            (
                ("int", "ufd"),
                ("int", "flags"),
                ("const struct itimerspec *", "utmr"),
                ("struct itimerspec *", "otmr"),
            ),
        ),
        "timerfd_settime32": (
            "long",
            (
                ("int", "ufd"),
                ("int", "flags"),
                ("const struct old_itimerspec32 *", "utmr"),
                ("struct old_itimerspec32 *", "otmr"),
            ),
        ),
        "times": ("long", (("struct tms *", "tbuf"),)),
        "tkill": ("long", (("int", "pid"), ("int", "sig"))),
        "truncate": ("long", (("const char *", "path"), ("long", "length"))),
        "truncate64": (
            "long",
            (("const char *", "path"), ("loff_t", "length")),
        ),
        "umask": ("long", (("int", "mask"),)),
        "umount": ("long", (("const char *", "name"), ("int", "flags"))),
        "umount2": ("long", (("const char *", "name"), ("int", "flags"))),
        "uname": ("long", (("struct old_utsname *", "buf"),)),
        "unlink": ("long", (("const char *", "pathname"),)),
        "unlinkat": (
            "long",
            (("int", "dfd"), ("const char *", "pathname"), ("int", "flag")),
        ),
        "unshare": ("long", (("unsigned long", "unshare_flags"),)),
        "uselib": ("long", (("const char *", "library"),)),
        "userfaultfd": ("long", (("int", "flags"),)),
        "ustat": ("long", (("unsigned", "dev"), ("struct ustat *", "ubuf"))),
        "utime": (
            "long",
            (("const char *", "filename"), ("struct utimbuf *", "times")),
        ),
        "utime32": (
            "long",
            (("const char *", "filename"), ("struct old_utimbuf32 *", "t")),
        ),
        "utimensat": (
            "long",
            (
                ("int", "dfd"),
                ("const char *", "filename"),
                ("struct timespec *", "utimes"),
                ("int", "flags"),
            ),
        ),
        "utimensat_time32": (
            "long",
            (
                ("unsigned int", "dfd"),
                ("const char *", "filename"),
                ("struct old_timespec32 *", "t"),
                ("int", "flags"),
            ),
        ),
        "utimes": (
            "long",
            (("const char *", "filename"), ("struct old_timeval *", "utimes")),
        ),
        "utimes_time32": (
            "long",
            (("const char *", "filename"), ("struct old_timeval32 *", "t")),
        ),
        "vfork": ("long", ()),
        "vhangup": ("long", ()),
        "vmsplice": (
            "long",
            (
                ("int", "fd"),
                ("const struct iovec *", "iov"),
                ("unsigned long", "nr_segs"),
                ("unsigned int", "flags"),
            ),
        ),
        "wait4": (
            "long",
            (
                ("pid_t", "pid"),
                ("int *", "stat_addr"),
                ("int", "options"),
                ("struct rusage *", "ru"),
            ),
        ),
        "waitid": (
            "long",
            (
                ("int", "which"),
                ("pid_t", "pid"),
                ("struct siginfo *", "infop"),
                ("int", "options"),
                ("struct rusage *", "ru"),
            ),
        ),
        "waitpid": (
            "long",
            (("pid_t", "pid"), ("int *", "stat_addr"), ("int", "options")),
        ),
        "write": (
            "long",
            (
                ("unsigned int", "fd"),
                ("const char *", "buf"),
                ("size_t", "count"),
            ),
        ),
        "writev": (
            "long",
            (
                ("unsigned long", "fd"),
                ("const struct iovec *", "vec"),
                ("unsigned long", "vlen"),
            ),
        ),
    }

    """
    update syscalls from https://github.com/strace/src/linux/ARCH/syscallent.h
    1. %s/\[.*= //g
    2. %s/{.*),\s*"/\'sys_/g
    3. %s/".*,/\',/g
    4. paste the processed list
    4. call UtilMgr.printSyscalls(ConfigMgr.SYSCALL_X86)
    """

    # common 32bit syscalls from 403 ~ 423 #
    SYSCALL_COMMON32 = [
        "sys_clock_gettime64",
        "sys_clock_settime64",
        "sys_clock_adjtime64",
        "sys_clock_getres_time64",
        "sys_clock_nanosleep_time64",
        "sys_timer_gettime64",
        "sys_timer_settime64",
        "sys_timerfd_gettime64",
        "sys_timerfd_settime64",
        "sys_utimensat_time64",
        "sys_pselect6_time64",
        "sys_ppoll_time64",
        "sys_unused",
        "sys_io_pgetevents_time64",
        "sys_recvmmsg_time64",
        "sys_mq_timedsend_time64",
        "sys_mq_timedreceive_time64",
        "sys_semtimedop_time64",
        "sys_rt_sigtimedwait_time64",
        "sys_futex_time64",
        "sys_sched_rr_get_interval_time64",
    ]

    # common syscalls from 424 ~ 447 #
    SYSCALL_COMMON = [
        "sys_pidfd_send_signal",
        "sys_io_uring_setup",
        "sys_io_uring_enter",
        "sys_io_uring_register",
        "sys_open_tree",
        "sys_move_mount",
        "sys_fsopen",
        "sys_fsconfig",
        "sys_fsmount",
        "sys_fspick",
        "sys_pidfd_open",
        "sys_clone3",
        "sys_close_range",
        "sys_openat2",
        "sys_pidfd_getfd",
        "sys_faccessat2",
        "sys_process_madvise",
        "sys_epoll_pwait2",
        "sys_mount_setattr",
        "sys_quotactl_fd",
        "sys_landlock_create_ruleset",
        "sys_landlock_add_rule",
        "sys_landlock_restrict_self",
        "sys_memfd_secret",
    ]

    # syscall for ARM #
    SYSCALL_ARM = (
        [
            "sys_restart_syscall",
            "sys_exit",
            "sys_fork",
            "sys_read",
            "sys_write",
            "sys_open",
            "sys_close",
            "sys_waitpid",
            "sys_creat",
            "sys_link",
            "sys_unlink",
            "sys_execve",
            "sys_chdir",
            "sys_time",
            "sys_mknod",
            "sys_chmod",
            "sys_lchown",
            "sys_break",
            "sys_oldstat",
            "sys_lseek",
            "sys_getpid",
            "sys_mount",
            "sys_umount",
            "sys_setuid",
            "sys_getuid",
            "sys_stime",
            "sys_ptrace",
            "sys_alarm",
            "sys_oldfstat",
            "sys_pause",
            "sys_utime",
            "sys_stty",
            "sys_gtty",
            "sys_access",
            "sys_nice",
            "sys_ftime",
            "sys_sync",
            "sys_kill",
            "sys_rename",
            "sys_mkdir",
            "sys_rmdir",
            "sys_dup",
            "sys_pipe",
            "sys_times",
            "sys_prof",
            "sys_brk",
            "sys_setgid",
            "sys_getgid",
            "sys_signal",
            "sys_geteuid",
            "sys_getegid",
            "sys_acct",
            "sys_umount2",
            "sys_lock",
            "sys_ioctl",
            "sys_fcntl",
            "sys_mpx",
            "sys_setpgid",
            "sys_ulimit",
            "sys_oldolduname",
            "sys_umask",
            "sys_chroot",
            "sys_ustat",
            "sys_dup2",
            "sys_getppid",
            "sys_getpgrp",
            "sys_setsid",
            "sys_sigaction",
            "sys_sgetmask",
            "sys_ssetmask",
            "sys_setreuid",
            "sys_setregid",
            "sys_sigsuspend",
            "sys_sigpending",
            "sys_sethostname",
            "sys_setrlimit",
            "sys_getrlimit",
            "sys_getrusage",
            "sys_gettimeofday",
            "sys_settimeofday",
            "sys_getgroups",
            "sys_setgroups",
            "sys_select",
            "sys_symlink",
            "sys_oldlstat",
            "sys_readlink",
            "sys_uselib",
            "sys_swapon",
            "sys_reboot",
            "sys_readdir",
            "sys_mmap",
            "sys_munmap",
            "sys_truncate",
            "sys_ftruncate",
            "sys_fchmod",
            "sys_fchown",
            "sys_getpriority",
            "sys_setpriority",
            "sys_profil",
            "sys_statfs",
            "sys_fstatfs",
            "sys_ioperm",
            "sys_socketcall",
            "sys_syslog",
            "sys_setitimer",
            "sys_getitimer",
            "sys_stat",
            "sys_lstat",
            "sys_fstat",
            "sys_olduname",
            "sys_iopl",
            "sys_vhangup",
            "sys_idle",
            "sys_syscall",
            "sys_wait4",
            "sys_swapoff",
            "sys_sysinfo",
            "sys_ipc",
            "sys_fsync",
            "sys_sigreturn",
            "sys_clone",
            "sys_setdomainname",
            "sys_uname",
            "sys_modify_ldt",
            "sys_adjtimex",
            "sys_mprotect",
            "sys_sigprocmask",
            "sys_create_module",
            "sys_init_module",
            "sys_delete_module",
            "sys_get_kernel_syms",
            "sys_quotactl",
            "sys_getpgid",
            "sys_fchdir",
            "sys_bdflush",
            "sys_sysfs",
            "sys_personality",
            "sys_afs_syscall",
            "sys_setfsuid",
            "sys_setfsgid",
            "sys_llseek",
            "sys_getdents",
            "sys_newselect",
            "sys_flock",
            "sys_msync",
            "sys_readv",
            "sys_writev",
            "sys_getsid",
            "sys_fdatasync",
            "sys_sysctl",
            "sys_mlock",
            "sys_munlock",
            "sys_mlockall",
            "sys_munlockall",
            "sys_sched_setparam",
            "sys_sched_getparam",
            "sys_sched_setscheduler",
            "sys_sched_getscheduler",
            "sys_sched_yield",
            "sys_sched_get_priority_max",
            "sys_sched_get_priority_min",
            "sys_sched_rr_get_interval",
            "sys_nanosleep",
            "sys_mremap",
            "sys_setresuid",
            "sys_getresuid",
            "sys_vm86",
            "sys_query_module",
            "sys_poll",
            "sys_nfsservctl",
            "sys_setresgid",
            "sys_getresgid",
            "sys_prctl",
            "sys_rt_sigreturn",
            "sys_rt_sigaction",
            "sys_rt_sigprocmask",
            "sys_rt_sigpending",
            "sys_rt_sigtimedwait",
            "sys_rt_sigqueueinfo",
            "sys_rt_sigsuspend",
            "sys_pread64",
            "sys_pwrite64",
            "sys_chown",
            "sys_getcwd",
            "sys_capget",
            "sys_capset",
            "sys_sigaltstack",
            "sys_sendfile",
            "sys_getpmsg",
            "sys_putpmsg",
            "sys_vfork",
            "sys_ugetrlimit",
            "sys_mmap2",
            "sys_truncate64",
            "sys_ftruncate64",
            "sys_stat64",
            "sys_lstat64",
            "sys_fstat64",
            "sys_lchown32",
            "sys_getuid32",
            "sys_getgid32",
            "sys_geteuid32",
            "sys_getegid32",
            "sys_setreuid32",
            "sys_setregid32",
            "sys_getgroups32",
            "sys_setgroups32",
            "sys_fchown32",
            "sys_setresuid32",
            "sys_getresuid32",
            "sys_setresgid32",
            "sys_getresgid32",
            "sys_chown32",
            "sys_setuid32",
            "sys_setgid32",
            "sys_setfsuid32",
            "sys_setfsgid32",
            "sys_getdents64",
            "sys_pivot_root",
            "sys_mincore",
            "sys_madvise",
            "sys_fcntl64",
            "sys_tux",
            "sys_unused",
            "sys_gettid",
            "sys_readahead",
            "sys_setxattr",
            "sys_lsetxattr",
            "sys_fsetxattr",
            "sys_getxattr",
            "sys_lgetxattr",
            "sys_fgetxattr",
            "sys_listxattr",
            "sys_llistxattr",
            "sys_flistxattr",
            "sys_removexattr",
            "sys_lremovexattr",
            "sys_fremovexattr",
            "sys_tkill",
            "sys_sendfile64",
            "sys_futex",
            "sys_sched_setaffinity",
            "sys_sched_getaffinity",
            "sys_io_setup",
            "sys_io_destroy",
            "sys_io_getevents",
            "sys_io_submit",
            "sys_io_cancel",
            "sys_exit_group",
            "sys_lookup_dcookie",
            "sys_epoll_create",
            "sys_epoll_ctl",
            "sys_epoll_wait",
            "sys_remap_file_pages",
            "sys_set_thread_area",
            "sys_get_thread_area",
            "sys_set_tid_address",
            "sys_timer_create",
            "sys_timer_settime",
            "sys_timer_gettime",
            "sys_timer_getoverrun",
            "sys_timer_delete",
            "sys_clock_settime",
            "sys_clock_gettime",
            "sys_clock_getres",
            "sys_clock_nanosleep",
            "sys_statfs64",
            "sys_fstatfs64",
            "sys_tgkill",
            "sys_utimes",
            "sys_fadvise64_64",
            "sys_pciconfig_iobase",
            "sys_pciconfig_read",
            "sys_pciconfig_write",
            "sys_mq_open",
            "sys_mq_unlink",
            "sys_mq_timedsend",
            "sys_mq_timedreceive",
            "sys_mq_notify",
            "sys_mq_getsetattr",
            "sys_waitid",
            "sys_socket",
            "sys_bind",
            "sys_connect",
            "sys_listen",
            "sys_accept",
            "sys_getsockname",
            "sys_getpeername",
            "sys_socketpair",
            "sys_send",
            "sys_sendto",
            "sys_recv",
            "sys_recvfrom",
            "sys_shutdown",
            "sys_setsockopt",
            "sys_getsockopt",
            "sys_sendmsg",
            "sys_recvmsg",
            "sys_semop",
            "sys_semget",
            "sys_semctl",
            "sys_msgsnd",
            "sys_msgrcv",
            "sys_msgget",
            "sys_msgctl",
            "sys_shmat",
            "sys_shmdt",
            "sys_shmget",
            "sys_shmctl",
            "sys_add_key",
            "sys_request_key",
            "sys_keyctl",
            "sys_semtimedop",
            "sys_vserver",
            "sys_ioprio_set",
            "sys_ioprio_get",
            "sys_inotify_init",
            "sys_inotify_add_watch",
            "sys_inotify_rm_watch",
            "sys_mbind",
            "sys_get_mempolicy",
            "sys_set_mempolicy",
            "sys_openat",
            "sys_mkdirat",
            "sys_mknodat",
            "sys_fchownat",
            "sys_futimesat",
            "sys_fstatat64",
            "sys_unlinkat",
            "sys_renameat",
            "sys_linkat",
            "sys_symlinkat",
            "sys_readlinkat",
            "sys_fchmodat",
            "sys_faccessat",
            "sys_pselect6",
            "sys_ppoll",
            "sys_unshare",
            "sys_set_robust_list",
            "sys_get_robust_list",
            "sys_splice",
            "sys_sync_file_range2",
            "sys_tee",
            "sys_vmsplice",
            "sys_move_pages",
            "sys_getcpu",
            "sys_epoll_pwait",
            "sys_kexec_load",
            "sys_utimensat",
            "sys_signalfd",
            "sys_timerfd_create",
            "sys_eventfd",
            "sys_fallocate",
            "sys_timerfd_settime",
            "sys_timerfd_gettime",
            "sys_signalfd4",
            "sys_eventfd2",
            "sys_epoll_create1",
            "sys_dup3",
            "sys_pipe2",
            "sys_inotify_init1",
            "sys_preadv",
            "sys_pwritev",
            "sys_rt_tgsigqueueinfo",
            "sys_perf_event_open",
            "sys_recvmmsg",
            "sys_accept4",
            "sys_fanotify_init",
            "sys_fanotify_mark",
            "sys_prlimit64",
            "sys_name_to_handle_at",
            "sys_open_by_handle_at",
            "sys_clock_adjtime",
            "sys_syncfs",
            "sys_sendmmsg",
            "sys_setns",
            "sys_process_vm_readv",
            "sys_process_vm_writev",
            "sys_kcmp",
            "sys_finit_module",
            "sys_sched_setattr",
            "sys_sched_getattr",
            "sys_renameat2",
            "sys_seccomp",
            "sys_getrandom",
            "sys_memfd_create",
            "sys_bpf",
            "sys_execveat",
            "sys_userfaultfd",
            "sys_membarrier",
            "sys_mlock2",
            "sys_copy_file_range",
            "sys_preadv2",
            "sys_pwritev2",
            "sys_pkey_mprotect",
            "sys_pkey_alloc",
            "sys_pkey_free",
            "sys_statx",
            "sys_rseq",
            "sys_io_pgetevents",
            "sys_migrate_pages",
            "sys_kexec_file_load",
            "sys_unused",
        ]
        + SYSCALL_COMMON32
        + SYSCALL_COMMON
    )

    # syscall for AARCH64 #
    SYSCALL_AARCH64 = (
        [
            "sys_io_setup",
            "sys_io_destroy",
            "sys_io_submit",
            "sys_io_cancel",
            "sys_io_getevents",
            "sys_setxattr",
            "sys_lsetxattr",
            "sys_fsetxattr",
            "sys_getxattr",
            "sys_lgetxattr",
            "sys_fgetxattr",
            "sys_listxattr",
            "sys_llistxattr",
            "sys_flistxattr",
            "sys_removexattr",
            "sys_lremovexattr",
            "sys_fremovexattr",
            "sys_getcwd",
            "sys_lookup_dcookie",
            "sys_eventfd2",
            "sys_epoll_create1",
            "sys_epoll_ctl",
            "sys_epoll_pwait",
            "sys_dup",
            "sys_dup3",
            "sys_fcntl",
            "sys_inotify_init1",
            "sys_inotify_add_watch",
            "sys_inotify_rm_watch",
            "sys_ioctl",
            "sys_ioprio_set",
            "sys_ioprio_get",
            "sys_flock",
            "sys_mknodat",
            "sys_mkdirat",
            "sys_unlinkat",
            "sys_symlinkat",
            "sys_linkat",
            "sys_renameat",
            "sys_umount2",
            "sys_mount",
            "sys_pivot_root",
            "sys_nfsservctl",
            "sys_statfs",
            "sys_fstatfs",
            "sys_truncate",
            "sys_ftruncate",
            "sys_fallocate",
            "sys_faccessat",
            "sys_chdir",
            "sys_fchdir",
            "sys_chroot",
            "sys_fchmod",
            "sys_fchmodat",
            "sys_fchownat",
            "sys_fchown",
            "sys_openat",
            "sys_close",
            "sys_vhangup",
            "sys_pipe2",
            "sys_quotactl",
            "sys_getdents64",
            "sys_lseek",
            "sys_read",
            "sys_write",
            "sys_readv",
            "sys_writev",
            "sys_pread64",
            "sys_pwrite64",
            "sys_preadv",
            "sys_pwritev",
            "sys_sendfile",
            "sys_pselect6",
            "sys_ppoll",
            "sys_signalfd4",
            "sys_vmsplice",
            "sys_splice",
            "sys_tee",
            "sys_readlinkat",
            "sys_newfstatat",
            "sys_fstat",
            "sys_sync",
            "sys_fsync",
            "sys_fdatasync",
            "sys_sync_file_range",
            "sys_timerfd_create",
            "sys_timerfd_settime",
            "sys_timerfd_gettime",
            "sys_utimensat",
            "sys_acct",
            "sys_capget",
            "sys_capset",
            "sys_personality",
            "sys_exit",
            "sys_exit_group",
            "sys_waitid",
            "sys_set_tid_address",
            "sys_unshare",
            "sys_futex",
            "sys_set_robust_list",
            "sys_get_robust_list",
            "sys_nanosleep",
            "sys_getitimer",
            "sys_setitimer",
            "sys_kexec_load",
            "sys_init_module",
            "sys_delete_module",
            "sys_timer_create",
            "sys_timer_gettime",
            "sys_timer_getoverrun",
            "sys_timer_settime",
            "sys_timer_delete",
            "sys_clock_settime",
            "sys_clock_gettime",
            "sys_clock_getres",
            "sys_clock_nanosleep",
            "sys_syslog",
            "sys_ptrace",
            "sys_sched_setparam",
            "sys_sched_setscheduler",
            "sys_sched_getscheduler",
            "sys_sched_getparam",
            "sys_sched_setaffinity",
            "sys_sched_getaffinity",
            "sys_sched_yield",
            "sys_sched_get_priority_max",
            "sys_sched_get_priority_min",
            "sys_sched_rr_get_interval",
            "sys_restart_syscall",
            "sys_kill",
            "sys_tkill",
            "sys_tgkill",
            "sys_sigaltstack",
            "sys_rt_sigsuspend",
            "sys_rt_sigaction",
            "sys_rt_sigprocmask",
            "sys_rt_sigpending",
            "sys_rt_sigtimedwait",
            "sys_rt_sigqueueinfo",
            "sys_rt_sigreturn",
            "sys_setpriority",
            "sys_getpriority",
            "sys_reboot",
            "sys_setregid",
            "sys_setgid",
            "sys_setreuid",
            "sys_setuid",
            "sys_setresuid",
            "sys_getresuid",
            "sys_setresgid",
            "sys_getresgid",
            "sys_setfsuid",
            "sys_setfsgid",
            "sys_times",
            "sys_setpgid",
            "sys_getpgid",
            "sys_getsid",
            "sys_setsid",
            "sys_getgroups",
            "sys_setgroups",
            "sys_uname",
            "sys_sethostname",
            "sys_setdomainname",
            "sys_getrlimit",
            "sys_setrlimit",
            "sys_getrusage",
            "sys_umask",
            "sys_prctl",
            "sys_getcpu",
            "sys_gettimeofday",
            "sys_settimeofday",
            "sys_adjtimex",
            "sys_getpid",
            "sys_getppid",
            "sys_getuid",
            "sys_geteuid",
            "sys_getgid",
            "sys_getegid",
            "sys_gettid",
            "sys_sysinfo",
            "sys_mq_open",
            "sys_mq_unlink",
            "sys_mq_timedsend",
            "sys_mq_timedreceive",
            "sys_mq_notify",
            "sys_mq_getsetattr",
            "sys_msgget",
            "sys_msgctl",
            "sys_msgrcv",
            "sys_msgsnd",
            "sys_semget",
            "sys_semctl",
            "sys_semtimedop",
            "sys_semop",
            "sys_shmget",
            "sys_shmctl",
            "sys_shmat",
            "sys_shmdt",
            "sys_socket",
            "sys_socketpair",
            "sys_bind",
            "sys_listen",
            "sys_accept",
            "sys_connect",
            "sys_getsockname",
            "sys_getpeername",
            "sys_sendto",
            "sys_recvfrom",
            "sys_setsockopt",
            "sys_getsockopt",
            "sys_shutdown",
            "sys_sendmsg",
            "sys_recvmsg",
            "sys_readahead",
            "sys_brk",
            "sys_munmap",
            "sys_mremap",
            "sys_add_key",
            "sys_request_key",
            "sys_keyctl",
            "sys_clone",
            "sys_execve",
            "sys_mmap",
            "sys_fadvise64",
            "sys_swapon",
            "sys_swapoff",
            "sys_mprotect",
            "sys_msync",
            "sys_mlock",
            "sys_munlock",
            "sys_mlockall",
            "sys_munlockall",
            "sys_mincore",
            "sys_madvise",
            "sys_remap_file_pages",
            "sys_mbind",
            "sys_get_mempolicy",
            "sys_set_mempolicy",
            "sys_migrate_pages",
            "sys_move_pages",
            "sys_rt_tgsigqueueinfo",
            "sys_perf_event_open",
            "sys_accept4",
            "sys_recvmmsg",
            "sys_reserved",
            "sys_reserved",
            "sys_reserved",
            "sys_reserved",
            "sys_reserved",
            "sys_reserved",
            "sys_reserved",
            "sys_reserved",
            "sys_reserved",
            "sys_reserved",
            "sys_reserved",
            "sys_reserved",
            "sys_reserved",
            "sys_reserved",
            "sys_reserved",
            "sys_reserved",
            "sys_wait4",
            "sys_prlimit64",
            "sys_fanotify_init",
            "sys_fanotify_mark",
            "sys_name_to_handle_at",
            "sys_open_by_handle_at",
            "sys_clock_adjtime",
            "sys_syncfs",
            "sys_setns",
            "sys_sendmmsg",
            "sys_process_vm_readv",
            "sys_process_vm_writev",
            "sys_kcmp",
            "sys_finit_module",
            "sys_sched_setattr",
            "sys_sched_getattr",
            "sys_renameat2",
            "sys_seccomp",
            "sys_getrandom",
            "sys_memfd_create",
            "sys_bpf",
            "sys_execveat",
            "sys_userfaultfd",
            "sys_membarrier",
            "sys_mlock2",
            "sys_copy_file_range",
            "sys_preadv2",
            "sys_pwritev2",
            "sys_pkey_mprotect",
            "sys_pkey_alloc",
            "sys_pkey_free",
            "sys_statx",
            "sys_io_pgetevents",
            "sys_rseq",
            "sys_kexec_file_load",
        ]
        + ["sys_null" for idx in xrange(295, 423, 1)]
        + SYSCALL_COMMON
    )

    # syscall for x86 #
    SYSCALL_X86 = (
        [
            "sys_restart_syscall",
            "sys_exit",
            "sys_fork",
            "sys_read",
            "sys_write",
            "sys_open",
            "sys_close",
            "sys_waitpid",
            "sys_creat",
            "sys_link",
            "sys_unlink",
            "sys_execve",
            "sys_chdir",
            "sys_time",
            "sys_mknod",
            "sys_chmod",
            "sys_lchown",
            "sys_break",
            "sys_oldstat",
            "sys_lseek",
            "sys_getpid",
            "sys_mount",
            "sys_umount",
            "sys_setuid",
            "sys_getuid",
            "sys_stime",
            "sys_ptrace",
            "sys_alarm",
            "sys_oldfstat",
            "sys_pause",
            "sys_utime",
            "sys_stty",
            "sys_gtty",
            "sys_access",
            "sys_nice",
            "sys_ftime",
            "sys_sync",
            "sys_kill",
            "sys_rename",
            "sys_mkdir",
            "sys_rmdir",
            "sys_dup",
            "sys_pipe",
            "sys_times",
            "sys_prof",
            "sys_brk",
            "sys_setgid",
            "sys_getgid",
            "sys_signal",
            "sys_geteuid",
            "sys_getegid",
            "sys_acct",
            "sys_umount2",
            "sys_lock",
            "sys_ioctl",
            "sys_fcntl",
            "sys_mpx",
            "sys_setpgid",
            "sys_ulimit",
            "sys_oldolduname",
            "sys_umask",
            "sys_chroot",
            "sys_ustat",
            "sys_dup2",
            "sys_getppid",
            "sys_getpgrp",
            "sys_setsid",
            "sys_sigaction",
            "sys_sgetmask",
            "sys_ssetmask",
            "sys_setreuid",
            "sys_setregid",
            "sys_sigsuspend",
            "sys_sigpending",
            "sys_sethostname",
            "sys_setrlimit",
            "sys_getrlimit",
            "sys_getrusage",
            "sys_gettimeofday",
            "sys_settimeofday",
            "sys_getgroups",
            "sys_setgroups",
            "sys_select",
            "sys_symlink",
            "sys_oldlstat",
            "sys_readlink",
            "sys_uselib",
            "sys_swapon",
            "sys_reboot",
            "sys_readdir",
            "sys_mmap",
            "sys_munmap",
            "sys_truncate",
            "sys_ftruncate",
            "sys_fchmod",
            "sys_fchown",
            "sys_getpriority",
            "sys_setpriority",
            "sys_profil",
            "sys_statfs",
            "sys_fstatfs",
            "sys_ioperm",
            "sys_socketcall",
            "sys_syslog",
            "sys_setitimer",
            "sys_getitimer",
            "sys_stat",
            "sys_lstat",
            "sys_fstat",
            "sys_olduname",
            "sys_iopl",
            "sys_vhangup",
            "sys_idle",
            "sys_vm86old",
            "sys_wait4",
            "sys_swapoff",
            "sys_sysinfo",
            "sys_ipc",
            "sys_fsync",
            "sys_sigreturn",
            "sys_clone",
            "sys_setdomainname",
            "sys_uname",
            "sys_modify_ldt",
            "sys_adjtimex",
            "sys_mprotect",
            "sys_sigprocmask",
            "sys_create_module",
            "sys_init_module",
            "sys_delete_module",
            "sys_get_kernel_syms",
            "sys_quotactl",
            "sys_getpgid",
            "sys_fchdir",
            "sys_bdflush",
            "sys_sysfs",
            "sys_personality",
            "sys_afs_syscall",
            "sys_setfsuid",
            "sys_setfsgid",
            "sys_llseek",
            "sys_getdents",
            "sys_newselect",
            "sys_flock",
            "sys_msync",
            "sys_readv",
            "sys_writev",
            "sys_getsid",
            "sys_fdatasync",
            "sys_sysctl",
            "sys_mlock",
            "sys_munlock",
            "sys_mlockall",
            "sys_munlockall",
            "sys_sched_setparam",
            "sys_sched_getparam",
            "sys_sched_setscheduler",
            "sys_sched_getscheduler",
            "sys_sched_yield",
            "sys_sched_get_priority_max",
            "sys_sched_get_priority_min",
            "sys_sched_rr_get_interval",
            "sys_nanosleep",
            "sys_mremap",
            "sys_setresuid",
            "sys_getresuid",
            "sys_vm86",
            "sys_query_module",
            "sys_poll",
            "sys_nfsservctl",
            "sys_setresgid",
            "sys_getresgid",
            "sys_prctl",
            "sys_rt_sigreturn",
            "sys_rt_sigaction",
            "sys_rt_sigprocmask",
            "sys_rt_sigpending",
            "sys_rt_sigtimedwait",
            "sys_rt_sigqueueinfo",
            "sys_rt_sigsuspend",
            "sys_pread64",
            "sys_pwrite64",
            "sys_chown",
            "sys_getcwd",
            "sys_capget",
            "sys_capset",
            "sys_sigaltstack",
            "sys_sendfile",
            "sys_getpmsg",
            "sys_putpmsg",
            "sys_vfork",
            "sys_ugetrlimit",
            "sys_mmap2",
            "sys_truncate64",
            "sys_ftruncate64",
            "sys_stat64",
            "sys_lstat64",
            "sys_fstat64",
            "sys_lchown32",
            "sys_getuid32",
            "sys_getgid32",
            "sys_geteuid32",
            "sys_getegid32",
            "sys_setreuid32",
            "sys_setregid32",
            "sys_getgroups32",
            "sys_setgroups32",
            "sys_fchown32",
            "sys_setresuid32",
            "sys_getresuid32",
            "sys_setresgid32",
            "sys_getresgid32",
            "sys_chown32",
            "sys_setuid32",
            "sys_setgid32",
            "sys_setfsuid32",
            "sys_setfsgid32",
            "sys_pivot_root",
            "sys_mincore",
            "sys_madvise",
            "sys_getdents64",
            "sys_fcntl64",
            "sys_null",
            "sys_null",
            "sys_gettid",
            "sys_readahead",
            "sys_setxattr",
            "sys_lsetxattr",
            "sys_fsetxattr",
            "sys_getxattr",
            "sys_lgetxattr",
            "sys_fgetxattr",
            "sys_listxattr",
            "sys_llistxattr",
            "sys_flistxattr",
            "sys_removexattr",
            "sys_lremovexattr",
            "sys_fremovexattr",
            "sys_tkill",
            "sys_sendfile64",
            "sys_futex",
            "sys_sched_setaffinity",
            "sys_sched_getaffinity",
            "sys_set_thread_area",
            "sys_get_thread_area",
            "sys_io_setup",
            "sys_io_destroy",
            "sys_io_getevents",
            "sys_io_submit",
            "sys_io_cancel",
            "sys_fadvise64",
            "sys_set_zone_reclaim",
            "sys_exit_group",
            "sys_lookup_dcookie",
            "sys_epoll_create",
            "sys_epoll_ctl",
            "sys_epoll_wait",
            "sys_remap_file_pages",
            "sys_set_tid_address",
            "sys_timer_create",
            "sys_timer_settime",
            "sys_timer_gettime",
            "sys_timer_getoverrun",
            "sys_timer_delete",
            "sys_clock_settime",
            "sys_clock_gettime",
            "sys_clock_getres",
            "sys_clock_nanosleep",
            "sys_statfs64",
            "sys_fstatfs64",
            "sys_tgkill",
            "sys_utimes",
            "sys_fadvise64_64",
            "sys_vserver",
            "sys_mbind",
            "sys_get_mempolicy",
            "sys_set_mempolicy",
            "sys_mq_open",
            "sys_mq_unlink",
            "sys_mq_timedsend",
            "sys_mq_timedreceive",
            "sys_mq_notify",
            "sys_mq_getsetattr",
            "sys_kexec_load",
            "sys_waitid",
            "sys_setaltroot",
            "sys_add_key",
            "sys_request_key",
            "sys_keyctl",
            "sys_ioprio_set",
            "sys_ioprio_get",
            "sys_inotify_init",
            "sys_inotify_add_watch",
            "sys_inotify_rm_watch",
            "sys_migrate_pages",
            "sys_openat",
            "sys_mkdirat",
            "sys_mknodat",
            "sys_fchownat",
            "sys_futimesat",
            "sys_fstatat64",
            "sys_unlinkat",
            "sys_renameat",
            "sys_linkat",
            "sys_symlinkat",
            "sys_readlinkat",
            "sys_fchmodat",
            "sys_faccessat",
            "sys_pselect6",
            "sys_ppoll",
            "sys_unshare",
            "sys_set_robust_list",
            "sys_get_robust_list",
            "sys_splice",
            "sys_sync_file_range",
            "sys_tee",
            "sys_vmsplice",
            "sys_move_pages",
            "sys_getcpu",
            "sys_epoll_pwait",
            "sys_utimensat",
            "sys_signalfd",
            "sys_timerfd_create",
            "sys_eventfd",
            "sys_fallocate",
            "sys_timerfd_settime",
            "sys_timerfd_gettime",
            "sys_signalfd4",
            "sys_eventfd2",
            "sys_epoll_create1",
            "sys_dup3",
            "sys_pipe2",
            "sys_inotify_init1",
            "sys_preadv",
            "sys_pwritev",
            "sys_rt_tgsigqueueinfo",
            "sys_perf_event_open",
            "sys_recvmmsg",
            "sys_fanotify_init",
            "sys_fanotify_mark",
            "sys_prlimit64",
            "sys_name_to_handle_at",
            "sys_open_by_handle_at",
            "sys_clock_adjtime",
            "sys_syncfs",
            "sys_sendmmsg",
            "sys_setns",
            "sys_process_vm_readv",
            "sys_process_vm_writev",
            "sys_kcmp",
            "sys_finit_module",
            "sys_sched_setattr",
            "sys_sched_getattr",
            "sys_renameat2",
            "sys_seccomp",
            "sys_getrandom",
            "sys_memfd_create",
            "sys_bpf",
            "sys_execveat",
            "sys_socket",
            "sys_socketpair",
            "sys_bind",
            "sys_connect",
            "sys_listen",
            "sys_accept4",
            "sys_getsockopt",
            "sys_setsockopt",
            "sys_getsockname",
            "sys_getpeername",
            "sys_sendto",
            "sys_sendmsg",
            "sys_recvfrom",
            "sys_recvmsg",
            "sys_shutdown",
            "sys_userfaultfd",
            "sys_membarrier",
            "sys_mlock2",
            "sys_copy_file_range",
            "sys_preadv2",
            "sys_pwritev2",
            "sys_pkey_mprotect",
            "sys_pkey_alloc",
            "sys_pkey_free",
            "sys_statx",
            "sys_arch_prctl",
            "sys_io_pgetevents",
            "sys_rseq",
            "sys_reserved",
            "sys_reserved",
            "sys_reserved",
            "sys_reserved",
            "sys_reserved",
            "sys_reserved",
            "sys_semget",
            "sys_semctl",
            "sys_shmget",
            "sys_shmctl",
            "sys_shmat",
            "sys_shmdt",
            "sys_msgget",
            "sys_msgsnd",
            "sys_msgrcv",
            "sys_msgctl",
        ]
        + SYSCALL_COMMON32
        + SYSCALL_COMMON
    )

    # syscall for x86_64 #
    SYSCALL_X64 = (
        [
            "sys_read",
            "sys_write",
            "sys_open",
            "sys_close",
            "sys_stat",
            "sys_fstat",
            "sys_lstat",
            "sys_poll",
            "sys_lseek",
            "sys_mmap",
            "sys_mprotect",
            "sys_munmap",
            "sys_brk",
            "sys_rt_sigaction",
            "sys_rt_sigprocmask",
            "sys_rt_sigreturn",
            "sys_ioctl",
            "sys_pread64",
            "sys_pwrite64",
            "sys_readv",
            "sys_writev",
            "sys_access",
            "sys_pipe",
            "sys_select",
            "sys_sched_yield",
            "sys_mremap",
            "sys_msync",
            "sys_mincore",
            "sys_madvise",
            "sys_shmget",
            "sys_shmat",
            "sys_shmctl",
            "sys_dup",
            "sys_dup2",
            "sys_pause",
            "sys_nanosleep",
            "sys_getitimer",
            "sys_alarm",
            "sys_setitimer",
            "sys_getpid",
            "sys_sendfile",
            "sys_socket",
            "sys_connect",
            "sys_accept",
            "sys_sendto",
            "sys_recvfrom",
            "sys_sendmsg",
            "sys_recvmsg",
            "sys_shutdown",
            "sys_bind",
            "sys_listen",
            "sys_getsockname",
            "sys_getpeername",
            "sys_socketpair",
            "sys_setsockopt",
            "sys_getsockopt",
            "sys_clone",
            "sys_fork",
            "sys_vfork",
            "sys_execve",
            "sys_exit",
            "sys_wait4",
            "sys_kill",
            "sys_uname",
            "sys_semget",
            "sys_semop",
            "sys_semctl",
            "sys_shmdt",
            "sys_msgget",
            "sys_msgsnd",
            "sys_msgrcv",
            "sys_msgctl",
            "sys_fcntl",
            "sys_flock",
            "sys_fsync",
            "sys_fdatasync",
            "sys_truncate",
            "sys_ftruncate",
            "sys_getdents",
            "sys_getcwd",
            "sys_chdir",
            "sys_fchdir",
            "sys_rename",
            "sys_mkdir",
            "sys_rmdir",
            "sys_creat",
            "sys_link",
            "sys_unlink",
            "sys_symlink",
            "sys_readlink",
            "sys_chmod",
            "sys_fchmod",
            "sys_chown",
            "sys_fchown",
            "sys_lchown",
            "sys_umask",
            "sys_gettimeofday",
            "sys_getrlimit",
            "sys_getrusage",
            "sys_sysinfo",
            "sys_times",
            "sys_ptrace",
            "sys_getuid",
            "sys_syslog",
            "sys_getgid",
            "sys_setuid",
            "sys_setgid",
            "sys_geteuid",
            "sys_getegid",
            "sys_setpgid",
            "sys_getppid",
            "sys_getpgrp",
            "sys_setsid",
            "sys_setreuid",
            "sys_setregid",
            "sys_getgroups",
            "sys_setgroups",
            "sys_setresuid",
            "sys_getresuid",
            "sys_setresgid",
            "sys_getresgid",
            "sys_getpgid",
            "sys_setfsuid",
            "sys_setfsgid",
            "sys_getsid",
            "sys_capget",
            "sys_capset",
            "sys_rt_sigpending",
            "sys_rt_sigtimedwait",
            "sys_rt_sigqueueinfo",
            "sys_rt_sigsuspend",
            "sys_sigaltstack",
            "sys_utime",
            "sys_mknod",
            "sys_uselib",
            "sys_personality",
            "sys_ustat",
            "sys_statfs",
            "sys_fstatfs",
            "sys_sysfs",
            "sys_getpriority",
            "sys_setpriority",
            "sys_sched_setparam",
            "sys_sched_getparam",
            "sys_sched_setscheduler",
            "sys_sched_getscheduler",
            "sys_sched_get_priority_max",
            "sys_sched_get_priority_min",
            "sys_sched_rr_get_interval",
            "sys_mlock",
            "sys_munlock",
            "sys_mlockall",
            "sys_munlockall",
            "sys_vhangup",
            "sys_modify_ldt",
            "sys_pivot_root",
            "sys_sysctl",
            "sys_prctl",
            "sys_arch_prctl",
            "sys_adjtimex",
            "sys_setrlimit",
            "sys_chroot",
            "sys_sync",
            "sys_acct",
            "sys_settimeofday",
            "sys_mount",
            "sys_umount2",
            "sys_swapon",
            "sys_swapoff",
            "sys_reboot",
            "sys_sethostname",
            "sys_setdomainname",
            "sys_iopl",
            "sys_ioperm",
            "sys_create_module",
            "sys_init_module",
            "sys_delete_module",
            "sys_get_kernel_syms",
            "sys_query_module",
            "sys_quotactl",
            "sys_nfsservctl",
            "sys_getpmsg",
            "sys_putpmsg",
            "sys_afs_syscall",
            "sys_tuxcall",
            "sys_security",
            "sys_gettid",
            "sys_readahead",
            "sys_setxattr",
            "sys_lsetxattr",
            "sys_fsetxattr",
            "sys_getxattr",
            "sys_lgetxattr",
            "sys_fgetxattr",
            "sys_listxattr",
            "sys_llistxattr",
            "sys_flistxattr",
            "sys_removexattr",
            "sys_lremovexattr",
            "sys_fremovexattr",
            "sys_tkill",
            "sys_time",
            "sys_futex",
            "sys_sched_setaffinity",
            "sys_sched_getaffinity",
            "sys_set_thread_area",
            "sys_io_setup",
            "sys_io_destroy",
            "sys_io_getevents",
            "sys_io_submit",
            "sys_io_cancel",
            "sys_get_thread_area",
            "sys_lookup_dcookie",
            "sys_epoll_create",
            "sys_epoll_ctl_old",
            "sys_epoll_wait_old",
            "sys_remap_file_pages",
            "sys_getdents64",
            "sys_set_tid_address",
            "sys_restart_syscall",
            "sys_semtimedop",
            "sys_fadvise64",
            "sys_timer_create",
            "sys_timer_settime",
            "sys_timer_gettime",
            "sys_timer_getoverrun",
            "sys_timer_delete",
            "sys_clock_settime",
            "sys_clock_gettime",
            "sys_clock_getres",
            "sys_clock_nanosleep",
            "sys_exit_group",
            "sys_epoll_wait",
            "sys_epoll_ctl",
            "sys_tgkill",
            "sys_utimes",
            "sys_vserver",
            "sys_mbind",
            "sys_set_mempolicy",
            "sys_get_mempolicy",
            "sys_mq_open",
            "sys_mq_unlink",
            "sys_mq_timedsend",
            "sys_mq_timedreceive",
            "sys_mq_notify",
            "sys_mq_getsetattr",
            "sys_kexec_load",
            "sys_waitid",
            "sys_add_key",
            "sys_request_key",
            "sys_keyctl",
            "sys_ioprio_set",
            "sys_ioprio_get",
            "sys_inotify_init",
            "sys_inotify_add_watch",
            "sys_inotify_rm_watch",
            "sys_migrate_pages",
            "sys_openat",
            "sys_mkdirat",
            "sys_mknodat",
            "sys_fchownat",
            "sys_futimesat",
            "sys_newfstatat",
            "sys_unlinkat",
            "sys_renameat",
            "sys_linkat",
            "sys_symlinkat",
            "sys_readlinkat",
            "sys_fchmodat",
            "sys_faccessat",
            "sys_pselect6",
            "sys_ppoll",
            "sys_unshare",
            "sys_set_robust_list",
            "sys_get_robust_list",
            "sys_splice",
            "sys_tee",
            "sys_sync_file_range",
            "sys_vmsplice",
            "sys_move_pages",
            "sys_utimensat",
            "sys_epoll_pwait",
            "sys_signalfd",
            "sys_timerfd_create",
            "sys_eventfd",
            "sys_fallocate",
            "sys_timerfd_settime",
            "sys_timerfd_gettime",
            "sys_accept4",
            "sys_signalfd4",
            "sys_eventfd2",
            "sys_epoll_create1",
            "sys_dup3",
            "sys_pipe2",
            "sys_inotify_init1",
            "sys_preadv",
            "sys_pwritev",
            "sys_rt_tgsigqueueinfo",
            "sys_perf_event_open",
            "sys_recvmmsg",
            "sys_fanotify_init",
            "sys_fanotify_mark",
            "sys_prlimit64",
            "sys_name_to_handle_at",
            "sys_open_by_handle_at",
            "sys_clock_adjtime",
            "sys_syncfs",
            "sys_sendmmsg",
            "sys_setns",
            "sys_getcpu",
            "sys_process_vm_readv",
            "sys_process_vm_writev",
            "sys_kcmp",
            "sys_finit_module",
            "sys_sched_setattr",
            "sys_sched_getattr",
            "sys_renameat2",
            "sys_seccomp",
            "sys_getrandom",
            "sys_memfd_create",
            "sys_kexec_file_load",
            "sys_bpf",
            "sys_execveat",
            "sys_userfaultfd",
            "sys_membarrier",
            "sys_mlock2",
            "sys_copy_file_range",
            "sys_preadv2",
            "sys_pwritev2",
            "sys_pkey_mprotect",
            "sys_pkey_alloc",
            "sys_pkey_free",
            "sys_statx",
            "sys_io_pgetevents",
            "sys_rseq",
        ]
        + ["sys_null" for idx in xrange(335, 423, 1)]
        + SYSCALL_COMMON
    )

    # default syscall list #
    sysList = []

    # default register list #
    regList = []

    # registers sorted by number #
    REGS_X86 = [
        "eax",
        "ecx",
        "edx",
        "ebx",
        "esp",
        "ebp",  # 5 #
        "esi",
        "edi",
        "eip",
        "eflags",
        "<none>",  # 10 #
        "st0",
        "st1",
        "st2",
        "st3",
        "st4",  # 15 #
        "st5",
        "st6",
        "st7",
        "<none>",
        "<none>",  # 20 #
        "xmm0",
        "xmm1",
        "xmm2",
        "xmm3",
        "xmm4",  # 25 #
        "xmm5",
        "xmm6",
        "xmm7",
        "mm0",
        "mm1",  # 30 #
        "mm2",
        "mm3",
        "mm4",
        "mm5",
        "mm6",  # 35 #
        "mm7",
        "fcw",
        "fsw",
        "mxcsr",
        "es",  # 40 #
        "cs",
        "ss",
        "ds",
        "fs",
        "gs",  # 45 #
        "<none>",
        "<none>",
        "tr",
        "ldtr",
    ]

    REGS_X64 = [
        "rax",
        "rdx",
        "rcx",
        "rbx",
        "rsi",
        "rdi",  # 5 #
        "rbp",
        "rsp",
        "r8",
        "r9",
        "r10",  # 10 #
        "r11",
        "r12",
        "r13",
        "r14",
        "r15",  # 15 #
        "rip",
        "xmm0",
        "xmm1",
        "xmm2",
        "xmm3",  # 20 #
        "xmm4",
        "xmm5",
        "xmm6",
        "xmm7",
        "xmm8",  # 25 #
        "xmm9",
        "xmm10",
        "xmm11",
        "xmm12",
        "xmm13",  # 30 #
        "xmm14",
        "xmm15",
        "st0",
        "st1",
        "st2",  # 35 #
        "st3",
        "st4",
        "st5",
        "st6",
        "st7",  # 40 #
        "mm0",
        "mm1",
        "mm2",
        "mm3",
        "mm4",  # 45 #
        "mm5",
        "mm6",
        "mm7",
        "rflags",
        "es",  # 50 #
        "cs",
        "ss",
        "ds",
        "fs",
        "gs",  # 55 #
        "<none>",
        "<none>",
        "fs.base",
        "gs.base",
        "<none>",  # 60 #
        "<none>",
        "tr",
        "ldtr",
        "mxcsr",
        "fcw",  # 65 #
        "fsw",
    ]

    REGS_ARM = ["r%d" % idx for idx in xrange(16)]

    REGS_AARCH64 = (
        ["x%d" % idx for idx in xrange(31)]
        + ["sp", "pc", "ELP_mode", "RA_SIGN_STATE", "<none>", "<none>"]
        + ["reserved" for idx in xrange(37, 46, 1)]
        + ["VG", "FFR"]
        + ["p%d" % idx for idx in xrange(16)]
        + ["v%d" % idx for idx in xrange(32)]
        + ["z%d" % idx for idx in xrange(32)]
    )

    pcRegIndex = {
        "arm": REGS_ARM.index("r14"),
        "aarch64": REGS_AARCH64.index("pc"),
        "x86": REGS_X86.index("eip"),
        "x64": REGS_X64.index("rip"),
    }

    # syscall register #
    SYSREG_LIST = {
        "powerpc": "gpr0",
        "arm": "r7",
        "aarch64": "x8",
        "x64": "orig_rax",
        "x86": "orig_eax",
    }

    # return register #
    RET_LIST = {
        "powerpc": "result",
        "arm": "r0",
        "aarch64": "x0",
        "x64": "rax",
        "x86": "eax",
    }

    # signal for Linux #
    SIG_LIST = [
        "0",
        "SIGHUP",
        "SIGINT",
        "SIGQUIT",
        "SIGILL",  # 4
        "SIGTRAP",
        "SIGABRT",
        "SIGBUS",
        "SIGFPE",  # 8
        "SIGKILL",
        "SIGUSR1",
        "SIGSEGV",
        "SIGUSR2",  # 12
        "SIGPIPE",
        "SIGALRM",
        "SIGTERM",
        "SIGSTKFLT",  # 16
        "SIGCHLD",
        "SIGCONT",
        "SIGSTOP",
        "SIGTSTP",  # 20
        "SIGTTIN",
        "SIGTTOU",
        "SIGURG",
        "SIGXCPU",  # 24
        "SIGXFSZ",
        "SIGVTALRM",
        "SIGPROF",
        "SIGWINCH",  # 28
        "SIGIO",
        "SIGPWR",
        "SIGSYS",
        "NONE",
        "NONE",
    ] + ["SIGRT%d" % idx for idx in xrange(32)]
    SIGKILL = SIG_LIST.index("SIGKILL")

    # signal for MacOS #
    SIG_LIST_MACOS = [
        "0",
        "SIGHUP",
        "SIGINT",
        "SIGQUIT",
        "SIGILL",  # 4
        "SIGTRAP",
        "SIGABRT",
        "SIGEMT",
        "SIGFPE",  # 8
        "SIGKILL",
        "SIGBUS",
        "SIGSEGV",
        "SIGSYS",  # 12
        "SIGPIPE",
        "SIGALRM",
        "SIGTERM",
        "SIGURG",  # 16
        "SIGSTOP",
        "SIGTSTP",
        "SIGCONT",
        "SIGCHLD",  # 20
        "SIGTTIN",
        "SIGTTOU",
        "SIGIO",
        "SIGXCPU",  # 24
        "SIGXFSZ",
        "SIGVTALRM",
        "SIGPROF",
        "SIGWINCH",  # 28
        "SIGINFO",
        "SIGUSR1",
        "SIGUSR2",  # 31
    ]

    # SIGCHLD si_codes #
    SIGCHLD_CODE = [
        "N/A",
        "CLD_EXITED",  # /* child has exited */
        "CLD_KILLED",  # /* child was killed */
        "CLD_DUMPED",  # /* child terminated abnormally */
        "CLD_TRAPPED",  # /* traced child has trapped */
        "CLD_STOPPED",  # /* child has stopped */
        "CLD_CONTINUED",  # /* stopped child has continued */
    ]

    # SIGSEGV si_codes #
    SIGSEGV_CODE = [
        "N/A",
        "SEGV_MAPERR",  # /* address not mapped to object */
        "SEGV_ACCERR",  # /* invalid permissions for mapped object */
        "SEGV_BNDERR",  # /* failed address bound checks */
        "SEGV_PSTKOVF",  # /* paragraph stack overflow */
        "SEGV_ACCADI",  # /* ADI not enabled for mapped object */
        "SEGV_ADIDERR",  # /* Disrupting MCD error */
        "SEGV_ADIPERR",  # /* Precise MCD exception */
        "SEGV_MTEAERR",  # /* Asynchronous ARM MTE error */
        "SEGV_MTESERR",  # /* Synchronous ARM MTE exception */
    ]

    # SIGILL si_codes #
    SIGILL_CODE = [
        "N/A",
        "ILL_ILLOPC",  # /* illegal opcode */
        "ILL_ILLOPN",  # /* illegal operand */
        "ILL_ILLADR",  # /* illegal addressing mode */
        "ILL_ILLTRP",  # /* illegal trap */
        "ILL_PRVOPC",  # /* privileged opcode */
        "ILL_PRVREG",  # /* privileged register */
        "ILL_COPROC",  # /* coprocessor error */
        "ILL_BADSTK",  # /* internal stack error */
        "ILL_BADIADDR",  # /* unimplemented instruction address */
        "__ILL_BREAK",  # /* illegal break */
        "__ILL_BNDMOD",  # /* bundle-update (modification) in progress */
    ]

    # SIGTRAP si_codes #
    SIGTRAP_CODE = [
        "N/A",
        "TRAP_BRKPT",  # /* process breakpoint */
        "TRAP_TRACE",  # /* process trace trap */
        "TRAP_BRANCH",  # /* process taken branch trap */
        "TRAP_HWBKPT",  # /* hardware breakpoint/watchpoint */
        "TRAP_UNK",  # /* undiagnosed trap */
    ]

    # SIGFPE si_codes #
    SIGFPE_CODE = [
        "N/A",
        "FPE_INTDIV",  # /* integer divide by zero */
        "FPE_INTOVF",  # /* integer overflow */
        "FPE_FLTDIV",  # /* floating point divide by zero */
        "FPE_FLTOVF",  # /* floating point overflow */
        "FPE_FLTUND",  # /* floating point underflow */
        "FPE_FLTRES",  # /* floating point inexact result */
        "FPE_FLTINV",  # /* floating point invalid operation */
        "FPE_FLTSUB",  # /* subscript out of range */
        "__FPE_DECOVF",  # /* decimal overflow */
        "__FPE_DECDIV",  # /* decimal division by zero */
        "__FPE_DECERR",  # /* packed decimal error */
        "__FPE_INVASC",  # /* invalid ASCII digit */
        "__FPE_INVDEC",  # /* invalid decimal digit */
        "FPE_FLTUNK",  # /* undiagnosed floating-point exception */
        "FPE_CONDTRAP",  # /* trap on condition */
    ]

    # si_codes #
    SI_CODE = {
        0: "SI_USER",  # /* sent by kill, sigsend, raise */
        0x80: "SI_KERNEL",  # /* sent by the kernel from somewhere */
        -1: "SI_QUEUE",  # /* sent by sigqueue */
        -2: "SI_TIMER",  # /* sent by timer expiration */
        -3: "SI_MESGQ",  # /* sent by real time mesq state change */
        -4: "SI_ASYNCIO",  # /* sent by AIO completion */
        -5: "SI_SIGIO",  # /* sent by queued SIGIO */
        -6: "SI_TKILL",  # /* sent by tkill system call */
        -7: "SI_DETHREAD",  # /* sent by execve() killing subsidiary threads */
        -60: "SI_ASYNCNL",  # /* sent by glibc async name lookup completion */
    }

    # stat fields from http://linux.die.net/man/5/proc #
    STAT_ATTR = [
        "PID",
        "COMM",
        "STATE",
        "PPID",
        "PGRP",
        "SESSIONID",  # 5
        "NRTTY",
        "TPGID",
        "FLAGS",
        "MINFLT",
        "CMINFLT",  # 10
        "MAJFLT",
        "CMAJFLT",
        "UTIME",
        "STIME",
        "CUTIME",  # 15
        "CSTIME",
        "PRIORITY",
        "NICE",
        "NRTHREAD",
        "ITERALVAL",  # 20
        "STARTTIME",
        "VSIZE",
        "RSS",
        "RSSLIM",
        "STARTCODE",  # 25
        "ENDCODE",
        "STARTSTACK",
        "SP",
        "PC",
        "SIGNAL",  # 30
        "BLOCKED",
        "SIGIGNORE",
        "SIGCATCH",
        "WCHEN",
        "NSWAP",  # 35
        "CNSWAP",
        "EXITSIGNAL",
        "PROCESSOR",
        "RTPRIORITY",  # 39
        "POLICY",
        "DELAYBLKTICK",
        "GUESTTIME",
        "CGUESTTIME",
        "STARTDATA",  # 44
        "ENDDATA",
        "STARTBRK",
        "ARGSTART",
        "ARGEND",  # 48
        "ENVSTART",
        "ENVEND",
        "EXITCODE",  # 51
    ]

    # sched policy #
    SCHED_POLICY = [
        "C",  # 0: CFS #
        "F",  # 1: FIFO #
        "R",  # 2: RR #
        "B",  # 3: BATCH #
        "N",  # 4: NONE #
        "I",  # 5: IDLE #
        "D",  # 6: DEADLINE #
    ]

    # sched policy for Windows #
    SCHED_POLICY_WINDOWS = {
        "ABOVE_NORMAL_PRIORITY_CLASS": "ANOR",
        "BELOW_NORMAL_PRIORITY_CLASS": "BNOR",
        "HIGH_PRIORITY_CLASS": "HIGH",
        "IDLE_PRIORITY_CLASS": "IDLE",
        "NORMAL_PRIORITY_CLASS": "NORM",
        "PROCESS_MODE_BACKGROUND_BEGIN": "BGBE",
        "PROCESS_MODE_BACKGROUND_END": "BGEN",
        "REALTIME_PRIORITY_CLASS": "RT",
    }

    # I/O sched class #
    IOSCHED_CLASS = [
        "NONE",
        "IOPRIO_CLASS_RT",
        "IOPRIO_CLASS_BE",
        "IOPRIO_CLASS_IDLE",
    ]

    # I/O sched target #
    IOSCHED_TARGET = [
        "NONE",
        "IOPRIO_WHO_PROCESS",
        "IOPRIO_WHO_PGRP",
        "IOPRIO_WHO_USER",
    ]

    # statm fields #
    STATM_TYPE = [
        "TOTAL",  # 0 #
        "RSS",  # 1 #
        "SHR",  # 2 #
        "TEXT",  # 3 #
        "DATA",  # 4 #
        "LIB",  # 5 #
        "DIRTY",  # 6 #
    ]

    # error types #
    ERR_TYPE = [
        "EPERM",  # Operation not permitted #
        "ENOENT",  # No such file or directory #
        "ESRCH",  # No such process #
        "EINTR",  # Interrupted system call #
        "EIO",  # I/O error #
        "ENXIO",  # No such device or address #
        "E2BIG",  # Argument list too long #
        "ENOEXEC",  # Exec format error #
        "EBADF",  # Bad file number #
        "ECHILD",  # No child processes #
        "EAGAIN",  # Try again #
        "ENOMEM",  # Out of memory #
        "EACCES",  # Permission denied #
        "EFAULT",  # Bad address #
        "ENOTBLK",  # Block device required #
        "EBUSY",  # Device or resource busy #
        "EEXIST",  # File exists #
        "EXDEV",  # Cross-device link #
        "ENODEV",  # No such device #
        "ENOTDIR",  # Not a directory #
        "EISDIR",  # Is a directory #
        "EINVAL",  # Invalid argument #
        "ENFILE",  # File table overflow #
        "EMFILE",  # Too many open files #
        "ENOTTY",  # Not a typewriter #
        "ETXTBSY",  # Text file busy #
        "EFBIG",  # File too large #
        "ENOSPC",  # No space left on device #
        "ESPIPE",  # Illegal seek #
        "EROFS",  # Read-only file system #
        "EMLINK",  # Too many links #
        "EPIPE",  # Broken pipe #
        "EDOM",  # Math argument out of domain of func #
        "ERANGE",  # Math result not representable #
        "EDEADLK",  # Resource deadlock would occur #
        "ENAMETOOLONG",  # File name too long #
        "ENOLCK",  # No record locks available #
        "ENOSYS",  # Function not implemented #
        "ENOTEMPTY",  # Directory not empty #
        "ELOOP",  # Too many symbolic links encountered #
        "EWOULDBLOCK",  # Operation would block #
        "ENOMSG",  # No message of desired type #
        "EIDRM",  # Identifier removed #
        "ECHRNG",  # Channel number out of range #
        "EL2NSYNC",  # Level 2 not synchronized #
        "EL3HLT",  # Level 3 halted #
        "EL3RST",  # Level 3 reset #
        "ELNRNG",  # Link number out of range #
        "EUNATCH",  # Protocol driver not attached #
        "ENOCSI",  # No CSI structure available #
        "EL2HLT",  # Level 2 halted #
        "EBADE",  # Invalid exchange #
        "EBADR",  # Invalid request descriptor #
        "EXFULL",  # Exchange full #
        "ENOANO",  # No anode #
        "EBADRQC",  # Invalid request code #
        "EBADSLT ",  # Invalid slot #
        "EDEADLOCK",
        "EBFONT",  # Bad font file format #
        "ENOSTR",  # Device not a stream #
        "ENODATA",  # No data available #
        "ETIME",  # Timer expired #
        "ENOSR",  # Out of streams resources #
        "ENONET",  # Machine is not on the network #
        "ENOPKG",  # Package not installed #
        "EREMOTE",  # Object is remote #
        "ENOLINK",  # Link has been severed #
        "EADV",  # Advertise error #
        "ESRMNT",  # Srmount error #
        "ECOMM",  # Communication error on send #
        "EPROTO",  # Protocol error #
        "EMULTIHOP",  # Multihop attempted #
        "EDOTDOT",  # RFS specific error #
        "EBADMSG",  # Not a data message #
        "EOVERFLOW",  # Value too large for defined data type #
        "ENOTUNIQ",  # Name not unique on network #
        "EBADFD",  # File descriptor in bad state #
        "EREMCHG",  # Remote address changed #
        "ELIBACC",  # Can not access a needed shared library #
        "ELIBBAD",  # Accessing a corrupted shared library #
        "ELIBSCN",  # .lib section in a.out corrupted #
        "ELIBMAX",  # Attempting to link in too many shared libraries #
        "ELIBEXEC",  # Cannot exec a shared library directly #
        "EILSEQ",  # Illegal byte sequence #
        "ERESTART",  # Interrupted system call should be restarted #
        "ESTRPIPE",  # Streams pipe error #
        "EUSERS",  # Too many users #
        "ENOTSOCK",  # Socket operation on non-socket #
        "EDESTADDRREQ",  # Destination address required #
        "EMSGSIZE",  # Message too long #
        "EPROTOTYPE",  # Protocol wrong type for socket #
        "EPROTOTYPE",  # Protocol wrong type for socket #
        "ENOPROTOOPT",  # Protocol not available #
        "EPROTONOSUPPORT",  # Protocol not supported #
        "ESOCKTNOSUPPORT",  # Socket type not supported #
        "EOPNOTSUPP",  # Operation not supported on transport endpoint #
        "EPFNOSUPPORT",  # Protocol family not supported #
        "EAFNOSUPPORT ",  # Address family not supported by protocol #
        "EADDRINUSE ",  # Address already in use #
        "EADDRNOTAVAIL",  # Cannot assign requested address #
        "ENETDOWN",  # Network is down #
        "ENETUNREACH",  # Network is unreachable #
        "ENETRESET",  # Network dropped connection because of reset #
        "ECONNABORTED",  # Software caused connection abort #
        "ECONNRESET",  # Connection reset by peer #
        "ENOBUFS",  # No buffer space available #
        "EISCONN",  # Transport endpoint is already connected #
        "ENOTCONN",  # Transport endpoint is not connected #
        "ESHUTDOWN",  # Cannot send after transport endpoint shutdown #
        "ETOOMANYREFS",  # Too many references: cannot splice #
        "ETIMEDOUT",  # Connection timed out #
        "ECONNREFUSED",  # Connection refused #
        "EHOSTDOWN",  # Host is down #
        "EHOSTUNREACH",  # No route to host #
        "EALREADY",  # Operation already in progress #
        "EINPROGRESS",  # Operation now in progress #
        "ESTALE",  # Stale NFS file handle #
        "EUCLEAN",  # Structure needs cleaning #
        "ENOTNAM",  # Not a XENIX named type file #
        "ENAVAIL",  # No XENIX semaphores available #
        "EISNAM",  # Is a named type file #
        "EREMOTEIO",  # Remote I/O error #
        "EDQUOT",  # Quota exceeded #
        "ENOMEDIUM",  # No medium found #
        "EMEDIUMTYPE",  # Wrong medium type #
        "ECANCELED",  # Operation Canceled #
        "ENOKEY",  # Required key not available #
        "EKEYEXPIRED",  # Key has expired #
        "EKEYREVOKED",  # Key has been revoked #
        "EKEYREJECTED",  # Key was rejected by service #
        "EOWNERDEAD",  # Owner died #
        "ENOTRECOVERABLE",  # State not recoverable #
        "ERFKILL",  # Operation not possible due to RF-kill #
        "EHWPOISON",  # Memory page has hardware error #
    ]

    # rlimit types #
    RLIMIT_TYPE = [
        "RLIMIT_CPU",
        "RLIMIT_FSIZE",
        "RLIMIT_DATA",
        "RLIMIT_STACK",
        "RLIMIT_CORE",
        "RLIMIT_RSS",
        "RLIMIT_NPROC",
        "RLIMIT_NOFILE",
        "RLIMIT_MEMLOCK",
        "RLIMIT_AS",
        "RLIMIT_LOCKS",
        "RLIMIT_SIGPENDING",
        "RLIMIT_MSGQUEUE",
        "RLIMIT_NICE",
        "RLIMIT_RTPRIO",
        "RLIMIT_RTTIME",
        "RLIMIT_NLIMITS",
    ]

    # UDP/TCP format #
    PROTOCOL_ATTR = [
        "sl",
        "local_address",
        "rem_address",
        "st",
        "tx_rx_queue",
        "tr_tm->when",
        "retrnsmt",
        "uid",
        "timeout",
        "inode",
        "ref",
        "pointer",
        "drops",
    ]

    # UDS format #
    UDS_ATTR = [
        "Num",
        "RefCount",
        "Protocol",
        "Flags",
        "Type",
        "St",
        "Inode",
        "Path",
    ]

    TCP_STAT = [
        "N/A",
        "ESTABLISHED",
        "SYN_SENT",
        "SYN_RECV",
        "FIN_WAIT1",
        "FIN_WAIT2",
        "TIME_WAIT",
        "CLOSE",
        "CLOSE_WAIT",
        "LAST_ACK",
        "LISTEN",
        "CLOSING",
    ]

    # futex operation flags #
    FUTEX_TYPE = [
        "FUTEX_WAIT",
        "FUTEX_WAKE",
        "FUTEX_FD",
        "FUTEX_REQUEUE",
        "FUTEX_CMP_REQUEUE",
        "FUTEX_WAKE_OP",
        "FUTEX_LOCK_PI",
        "FUTEX_UNLOCK_PI",
        "FUTEX_TRYLOCK_PI",
        "FUTEX_WAIT_BITSET",
        "FUTEX_WAKE_BITSET",
        "FUTEX_WAIT_REQUEUE_PI",
        "FUTEX_CMP_REQUEUE_PI",
    ]

    # fcntl command flags #
    FCNTL_TYPE = [
        "F_DUPFD",
        "F_GETFD",
        "F_SETFD",
        "F_GETFL",
        "F_SETFL",
        "F_GETOWN",
        "F_SETOWN",
        "F_GETLK",
        "F_SETLK",
        "F_SETLKW",
    ]

    # ipc call flags #
    IPC_TYPE = {
        1: "SEMOP",
        2: "SEMGET",
        3: "SEMCTL",
        4: "SEMTIMEDOP",
        11: "MSGSND",
        12: "MSGRCV",
        13: "MSGGET",
        14: "MSGCTL",
        21: "SHMAT",
        22: "SHMDT",
        23: "SHMGET",
        24: "SHMCTL",
    }

    # ptrace request type #
    PTRACE_TYPE = [
        "PTRACE_TRACEME",  # 0
        "PTRACE_PEEKTEXT",
        "PTRACE_PEEKDATA",
        "PTRACE_PEEKUSR",
        "PTRACE_POKETEXT",
        "PTRACE_POKEDATA",
        "PTRACE_POKEUSR",
        "PTRACE_CONT",
        "PTRACE_KILL",
        "PTRACE_SINGLESTEP",  # 9
        "",
        "",
        "PTRACE_GETREGS",  # 12
        "PTRACE_SETREGS",  # 13
        "PTRACE_GETFPREGS",  # 14
        "PTRACE_SETFPREGS",  # 15
        "PTRACE_ATTACH",  # 16
        "PTRACE_DETACH",  # 17
        "PTRACE_GETFPXREGS",  # 18
        "PTRACE_SETFPXREGS",  # 19
        "",
        "",
        "",
        "PTRACE_SET_SYSCALL",  # 23
        "PTRACE_SYSCALL",  # 24
        "",
        "",
        "",
        "",
        "",
        "",
        "PTRACE_SYSEMU",  # 31
        "PTRACE_SYSEMU_SINGLESTEP",  # 32
    ]

    # ptrace event types #
    PTRACE_EVENT_TYPE = (
        [
            "PTRACE_EVENT_NONE",
            "PTRACE_EVENT_FORK",
            "PTRACE_EVENT_VFORK",
            "PTRACE_EVENT_CLONE",
            "PTRACE_EVENT_EXEC",
            "PTRACE_EVENT_VFORK_DONE",
            "PTRACE_EVENT_EXIT",
            "PTRACE_EVENT_SECCOMP",
        ]
        + ["NONE" for idx in xrange(120)]
        + ["PTRACE_EVENT_STOP"]
    )
    PERF_EVENT_TYPE = [
        "PERF_TYPE_HARDWARE",
        "PERF_TYPE_SOFTWARE",
        "PERF_TYPE_TRACEPOINT",
        "PERF_TYPE_HW_CACHE",
        "PERF_TYPE_RAW",
        "PERF_TYPE_BREAKPOINT",
    ]
    PERF_HW_EVENT_TYPE = [
        "PERF_COUNT_HW_CPU_CYCLES",
        "PERF_COUNT_HW_INSTRUCTIONS",
        "PERF_COUNT_HW_CACHE_REFERENCES",
        "PERF_COUNT_HW_CACHE_MISSES",
        "PERF_COUNT_HW_BRANCH_INSTRUCTIONS",
        "PERF_COUNT_HW_BRANCH_MISSES",
        "PERF_COUNT_HW_BUS_CYCLES",
        "PERF_COUNT_HW_STALLED_CYCLES_FRONTEND",
        "PERF_COUNT_HW_STALLED_CYCLES_BACKEND",
        "PERF_COUNT_HW_REF_CPU_CYCLES",
    ]
    PERF_SW_EVENT_TYPE = [
        "PERF_COUNT_SW_CPU_CLOCK",
        "PERF_COUNT_SW_TASK_CLOCK",
        "PERF_COUNT_SW_PAGE_FAULTS",
        "PERF_COUNT_SW_CONTEXT_SWITCHES",
        "PERF_COUNT_SW_CPU_MIGRATIONS",
        "PERF_COUNT_SW_PAGE_FAULTS_MIN",
        "PERF_COUNT_SW_PAGE_FAULTS_MAJ",
        "PERF_COUNT_SW_ALIGNMENT_FAULTS",
        "PERF_COUNT_SW_EMULATION_FAULTS",
        "PERF_COUNT_SW_DUMMY",
        "PERF_COUNT_SW_BPF_OUTPUT",
    ]
    PERF_CACHE_EVENT_TYPE = [
        "PERF_COUNT_HW_CACHE_L1D",
        "PERF_COUNT_HW_CACHE_L1I",
        "PERF_COUNT_HW_CACHE_LL",
        "PERF_COUNT_HW_CACHE_DTLB",
        "PERF_COUNT_HW_CACHE_ITLB",
        "PERF_COUNT_HW_CACHE_BPU",
        "PERF_COUNT_HW_CACHE_NODE",
    ]
    PERF_CACHE_EVENT_OP = [
        "PERF_COUNT_HW_CACHE_OP_READ",
        "PERF_COUNT_HW_CACHE_OP_WRITE",
        "PERF_COUNT_HW_CACHE_OP_PREFETCH",
    ]
    PERF_CACHE_EVENT_OPRES = [
        "PERF_COUNT_HW_CACHE_RESULT_ACCESS",
        "PERF_COUNT_HW_CACHE_RESULT_MISS",
    ]

    @staticmethod
    def getMmapId():
        if SysMgr.arch == "arm":
            return SysMgr.getNrSyscall("sys_mmap2")
        else:
            return SysMgr.getNrSyscall("sys_mmap")

    def __init__(self, mode):
        pass

    def __del__(self):
        pass


class UtilMgr(object):
    """Manager for utilities"""

    """
    [ TIPS ]
    - vim replacement
        - PROBLEM: replace all "type(???) is long" with "isinstance(???, (int, long))"
        - SOLUTION: %s/type(\(.*\)) is long/isinstance(\1, (int, long)/g
    """

    curTime = 0
    progressCnt = 0
    progressStr = 0
    progressChar = {0: "|", 1: "/", 2: "-", 3: "\\"}

    @staticmethod
    def convHtmlChar(string):
        chars = {"<": "&lt;", ">": "&gt;", "&": "&amp;"}

        for key, val in chars.items():
            string = string.replace(key, val)

        return string

    @staticmethod
    def removeColor(string):
        if not SysMgr.ansiObj:
            ansi = r"(?:\x1B[@-_]|[\x80-\x9F])[0-?]*[ -/]*[@-~]"
            SysMgr.ansiObj = re.compile(ansi)
        return SysMgr.ansiObj.sub("", string)

    @staticmethod
    def convFloat2Str(val):
        val = ("%f" % val).rstrip("0")
        if val.endswith("."):
            val += "0"
        return val

    @staticmethod
    def convStr2Bytes(string):
        # build string #
        res = ""
        for byte in string:
            if type(byte) is str:
                byte = long(repr(struct.unpack("B", byte)[0]))
            bstr = "%x" % byte
            res = "{0:s}{1:0>2} ".format(res, bstr)
        return res

    @staticmethod
    def saveTime():
        UtilMgr.printTime(update=True, verb=False)

    @staticmethod
    def deepcopy(data):
        json = SysMgr.getPkg("marshal", False)
        if not json:
            json = SysMgr.getPkg("json", False)
        if json:
            return json.loads(json.dumps(data))
        else:
            return deepcopy(data)

    @staticmethod
    def printTime(name=None, update=True, verb=True):
        # get current time #
        now = time.time()
        if not UtilMgr.curTime and update:
            UtilMgr.curTime = now
            return

        diff = now - UtilMgr.curTime

        # update timestamp #
        if update:
            UtilMgr.curTime = now

        if not verb:
            return

        # add name #
        if name:
            prefix = "/ %s" % name
        else:
            prefix = ""

        # print time diff #
        string = "[ELAPSED] %f sec %s" % (diff, prefix)
        SysMgr.printWarn(string, True)

    @staticmethod
    def getCommonPart(strings):
        try:
            return os.path.commonprefix(strings)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to get common part of %s" % strings)
            sys.exit(-1)

    @staticmethod
    def callPyFunc(path, fname, *args):
        try:
            # get function pointer #
            fullname = "%s_%s" % (path, fname)
            if fullname in SysMgr.externList:
                func = SysMgr.externList[fullname]
            elif sys.version_info < (3, 0, 0):
                execfile(path)  # pylint: disable=undefined-variable
                SysMgr.externList[fullname] = locals()[fname]
                func = SysMgr.externList[fullname]
            else:
                exec(open(path).read())
                SysMgr.externList[fullname] = locals()[fname]
                func = SysMgr.externList[fullname]

            # call the function and return #
            return func(args)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to call '%s()' from '%s'" % (func, path), True
            )
            sys.exit(-1)

    @staticmethod
    def isGzipFile(path):
        try:
            with open(path, "rb") as fd:
                data = fd.read(2)
                if struct.unpack("BB", data) == (0x1F, 0x8B):
                    return True
                else:
                    return False
        except SystemExit:
            sys.exit(0)
        except:
            return False

    @staticmethod
    def compareSyscallSuperset():
        syscallList = (
            ConfigMgr.SYSCALL_COMMON
            + ConfigMgr.SYSCALL_COMMON32
            + ConfigMgr.SYSCALL_X86
            + ConfigMgr.SYSCALL_X64
            + ConfigMgr.SYSCALL_ARM
            + ConfigMgr.SYSCALL_AARCH64
        )
        syscallList = set(syscallList)

        protoList = set(
            ["sys_%s" % name for name in ConfigMgr.SYSCALL_PROTOTYPES]
        )

        # print final diff list #
        SysMgr.printPipe("--- NO PROTOTYPE ---")
        for name in sorted(list(syscallList - protoList)):
            SysMgr.printPipe(name)

        SysMgr.printPipe("\n--- NO DEFINITION ---")
        for name in sorted(list(protoList - syscallList)):
            SysMgr.printPipe(name)

    @staticmethod
    def isBitEnabled(num, bits):
        if not bits:
            return None

        try:
            num = long(num)
        except SystemExit:
            sys.exit(0)
        except:
            num = long(num, 16)

        try:
            bits = long(bits)
        except SystemExit:
            sys.exit(0)
        except:
            bits = long(bits, 16)

        if bits & (1 << num - 1):
            return True
        else:
            return False

    @staticmethod
    def convxrange(targetList):
        result = []

        for item in targetList:
            try:
                nums = item.split(":")
                if len(nums) == 1:
                    result.append(item)
                elif len(nums) == 2:
                    for num in xrange(long(nums[0]), long(nums[1]) + 1):
                        result.append(str(num))
                else:
                    raise Exception()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("wrong number range '%s'" % item, True)
                sys.exit(-1)

        return result

    @staticmethod
    def unionItem(targetList):
        result = []
        dictionary = {}

        for item in targetList:
            if item in dictionary:
                continue

            result.append(item)
            dictionary[item] = None

        return result

    @staticmethod
    def cleanItem(targetList, union=True):
        targetType = type(targetList)

        if targetType is str:
            targetStr = ""
            for val in targetList:
                if val:
                    targetStr += val
            return targetStr
        elif targetType is list:
            # remove redundant values #
            if union:
                targetList = UtilMgr.unionItem(targetList)

            # remove empty values #
            newList = []
            for val in targetList:
                val = val.strip()
                if val:
                    newList.append(val)

            return newList
        else:
            return targetList

    @staticmethod
    def genRangeDict(prefix, startIdx, endIdx, valStart):
        dictList = {}
        for index in xrange(startIdx, endIdx + 1):
            name = "%s%s" % (prefix, index)
            value = valStart + index - startIdx
            dictList[name] = value
        return dictList

    @staticmethod
    def printHist(table, title, unit, printer=None, newline=""):
        if not table:
            return

        convNum = UtilMgr.convNum
        if not printer:
            printer = SysMgr.printPipe

        # pop stats #
        try:
            statmin = table.pop("min", None)
            statmax = table.pop("max", None)
            statcnt = table.pop("cnt", None)
            statsum = table.pop("sum", None)
        except SystemExit:
            sys.exit(0)
        except:
            pass

        printer(
            "\n[%s Histogram] (unit:%s)\n%s%s"
            % (title, unit, twoLine, newline)
        )
        printer(
            "{0:^21}   {1:^17}\n{2:1}{3:1}".format(
                "Range", "Count", oneLine, newline
            )
        )

        for digit, cnt in sorted(table.items()):
            srange = long(pow(2, digit - 1))

            if srange == 0:
                erange = 1
            else:
                erange = long((srange << 1) - 1)

            printer(
                "{0:10}-{1:>10}   {2:>10}({3:5.1f}%){4:1}".format(
                    convNum(srange),
                    convNum(erange),
                    convNum(cnt),
                    cnt / float(statcnt) * 100,
                    newline,
                )
            )

        try:
            printer(
                (
                    "{0:1}\n{1:^21}   {2:>17}\n{3:^21}   {4:>17}\n"
                    "{5:^21}   {6:>17}\n{7:^21}   {8:>17}\n{0:1}\n"
                ).format(
                    oneLine,
                    "Min",
                    convNum(statmin),
                    "Max",
                    convNum(statmax),
                    "Cnt",
                    convNum(statcnt),
                    "Sum",
                    convNum(statsum),
                )
            )
        except SystemExit:
            sys.exit(0)
        except:
            pass

    @staticmethod
    def ungzip(path):
        gzip = SysMgr.getPkg("gzip")
        return gzip.open(path, "rb").read()

    @staticmethod
    def unzip(fd, name):
        # get pkg #
        zlib = SysMgr.getPkg("zlib", False)
        if not zlib:
            return None, None

        # check format #
        magic = fd.read(4)
        if magic != b"ZLIB":
            SysMgr.printWarn(
                "wrong zlib magic number '%s' for %s section" % (magic, name)
            )
            return None, None

        compSize = struct.unpack(">Q", fd.read(8))[0]

        uncompBytes = b""
        decompressor = zlib.decompressobj()

        while 1:
            chunk = fd.read(SysMgr.PAGESIZE)
            if not chunk:
                break
            uncompBytes += decompressor.decompress(chunk)

        uncompBytes += decompressor.flush()

        if len(uncompBytes) != compSize:
            SysMgr.printWarn(
                (
                    "failed to decompress %s section because "
                    "decompressed size is wrong [record: %s, actual: %s]"
                )
                % (name, compSize, len(uncompBytes))
            )

        return uncompBytes, len(uncompBytes)

    @staticmethod
    def convList2Histo(items, dtype="float", mult=1):
        def _getRangeIdx(value):
            if value <= 1:
                return 0

            digit = 0
            while 1:
                digit += 1
                value = value >> 1
                if value == 0:
                    return digit

        if not items:
            return None

        # convert type #
        if dtype == "float":
            if type(items[0]) != float:
                items = list(map(float, items))
        elif dtype == "long":
            if type(items[0]) != long:
                items = list(map(long, items))
        else:
            return None

        # convert unit #
        items = list(map(lambda x: long(x * mult), items))

        # get stats #
        histDict = {
            "max": max(items),
            "min": min(items),
            "cnt": len(items),
            "sum": sum(items),
        }

        for value in items:
            digit = _getRangeIdx(value)
            histDict.setdefault(digit, 0)
            histDict[digit] += 1

        return histDict

    @staticmethod
    def getSigList():
        sigList = dict(
            (k, v)
            for v, k in reversed(sorted(signal.__dict__.items()))
            if v.startswith("SIG") and not v.startswith("SIG_")
        )
        return sigList

    @staticmethod
    def getEnvironNum(name, exit=True, default=None, verb=True, isInt=False):
        try:
            value = SysMgr.environList[name][0]

            # return by type #
            if isInt:
                return int(value)
            else:
                return long(value)
        except SystemExit:
            sys.exit(0)
        except:
            if verb:
                SysMgr.printErr(
                    "failed to get the number of %s variable" % name, True
                )
            if exit:
                sys.exit(-1)
            return default

    @staticmethod
    def parseCommand(option):
        stringList = {}

        # process strings in "" #
        strings = re.findall('"(.*?)"', option)
        if strings:
            # create an dictionary for strings #
            for idx, item in enumerate(strings):
                if not item:
                    continue

                val = "#%s#" % idx
                stringList.setdefault(item.strip('"'), val)

            # replace strings #
            for string, value in stringList.items():
                option = option.replace('"%s"' % string, value)

        # split the option string #
        option = option.split(" ")
        for string, value in stringList.items():
            for idx, item in enumerate(deepcopy(option)):
                if value in item:
                    option[idx] = item.replace(value, string)

        return option

    @staticmethod
    def convList2Dict(optList, sep=":", cap=False):
        newDict = {}
        for item in optList:
            try:
                # get values #
                values = item.split(sep, 1)
                if len(values) == 1:
                    key = values[0]
                    value = "SET"
                else:
                    key, value = values

                # change to capital #
                if cap:
                    key = key.upper()

                # set values #
                if key in newDict:
                    newDict[key].append(value)
                else:
                    newDict[key] = [value]
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn(
                    "failed to parse %s by separator %s" % (item, sep)
                )
                continue

        return newDict

    @staticmethod
    def getStdev(data):
        def _variance(data, ddof=0):
            n = len(data)
            mean = sum(data) / n
            return sum((x - mean) ** 2 for x in data) / (n - ddof)

        var = _variance(data)
        math = SysMgr.getPkg("math")
        stdDev = math.sqrt(var)
        return stdDev

    @staticmethod
    def splitString(string):
        string = string.replace("\,", "$%")

        clist = string.split(",")

        for idx, item in enumerate(list(clist)):
            clist[idx] = item.replace("$%", ",").strip()

        return clist

    @staticmethod
    def getDrawOutputPath(inputPath, name, suffix=False):
        # set output path #
        if SysMgr.outPath:
            outputPath = SysMgr.outPath

            # check dir #
            if os.path.isdir(outputPath):
                outputFileName = (
                    "%s.svg" % os.path.splitext(os.path.basename(inputPath))[0]
                )
                outputPath = os.path.join(outputPath, outputFileName)
            elif suffix:
                dirName = os.path.dirname(os.path.realpath(inputPath))
                fileName = "%s_%s.svg" % (
                    os.path.splitext(os.path.basename(inputPath))[0],
                    name,
                )
                outputPath = os.path.join(dirName, fileName)
        else:
            outputPath = UtilMgr.prepareForImageFile(inputPath, name)

        return os.path.realpath(outputPath)

    @staticmethod
    def printSyscalls(systable):
        bufstring = ""
        for idx, syscall in enumerate(systable):
            if idx % 4 == 0:
                bufstring += "\n"
            bufstring = "%s'%s', " % (bufstring, syscall)

        sys.exit("%s\ntotal: %s" % (bufstring, len(systable)))

    @staticmethod
    def isValidStr(string, key=None, inc=False, ignCap=False):
        if not key:
            key = SysMgr.filterGroup

        if not key:
            return True

        if ignCap:
            string = string.lower()

        for cond in list(key):
            if not cond:
                continue

            if ignCap:
                cond = cond.lower()

            if inc:
                if cond in string:
                    return True
            else:
                if cond == "*":
                    return True
                elif (
                    cond.startswith("*")
                    and cond.endswith("*")
                    and cond.strip("*") in string
                ):
                    return True
                elif cond.startswith("*") and string.endswith(cond[1:]):
                    return True
                elif cond.endswith("*") and string.startswith(cond[:-1]):
                    return True
                elif cond == string:
                    return True

        return False

    @staticmethod
    def convWord2Str(word):
        try:
            return struct.pack("L", word)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to convert word %s to string" % word, True)
            return None

    @staticmethod
    def lstrip(string, wordList):
        """
        str.lstrip() removes all heading characters including all characters
        in the string argument.
        ex) '12345'.lstrip('321') -> '45'
        ex) '12345'.lstrip('31') -> '2345'
        """

        if type(wordList) != list:
            wordList = [wordList]

        for word in wordList:
            if string.startswith(word):
                string = string[len(word) :]

        return string

    @staticmethod
    def rstrip(string, wordList):
        """
        str.rstrip() removes all ending characters including all characters
        in the string argument.
        ex) '12345'.rstrip('543') -> '12'
        ex) '12345'.rstrip('53') -> '1234'
        """

        if type(wordList) != list:
            wordList = [wordList]

        for word in wordList:
            if string.endswith(word):
                return string[: -len(word)]

        return string

    @staticmethod
    def strip(string, wordList):
        ret = UtilMgr.lstrip(string, wordList)
        ret = UtilMgr.rstrip(string, wordList)
        return ret

    @staticmethod
    def getInodes(
        path, inodeFilter=[], nameFilter=[], fileAttr=None, verb=True
    ):

        inodeList = {}

        for r, d, f in os.walk(path):
            # get full path for upper dir #
            fdir = os.path.realpath(r)
            if not FileAnalyzer.isValidFile(fdir):
                continue

            # print progress #
            UtilMgr.printProgress()

            for name in f + d:
                # get full path for file ##
                fpath = os.path.join(fdir, name)

                # check name filter #
                if nameFilter and not UtilMgr.isValidStr(name, nameFilter):
                    continue

                # check inode filter #
                try:
                    fstat = os.stat(fpath)
                    if not fstat:
                        continue
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printWarn(
                        "failed to get stat for %s" % fpath, reason=True
                    )
                    continue

                # get inode #
                inode = str(fstat.st_ino)
                if inodeFilter and not inode in inodeFilter:
                    continue

                # make device ID #
                major = os.major(fstat.st_dev)
                minor = os.minor(fstat.st_dev)
                devid = "%s:%s" % (major, minor)
                fpath = os.path.join(fdir, name)

                # register inode #
                inodeList.setdefault(devid, {})
                inodeList[devid][inode] = fpath

                # register file attribute #
                if type(fileAttr) is dict:
                    fileAttr[fpath] = fstat

        return inodeList

    @staticmethod
    def gerPermutation(inputList, union=False):
        visited = [0 for _ in xrange(len(inputList))]
        returnList = []

        def dfs(cnt, items):
            if cnt == len(inputList):
                returnList.append(items[:])
                return

            for i, val in enumerate(inputList):
                # check union #
                if union and visited[i] == 1:
                    continue

                # add item and check visit flag #
                items.append(val)
                visited[i] = 1

                dfs(cnt + 1, items)

                # remove item and uncheck visit flag #
                items.pop()
                visited[i] = 0

        dfs(0, [])

        return returnList

    @staticmethod
    def getPath(path):
        # get file info #
        filename = os.path.basename(path)
        dirname = os.path.dirname(path)
        if not dirname:
            dirname = "."
        return dirname, filename

    @staticmethod
    def getFiles(path, name=None, incFile=True, incDir=False, recursive=True):
        flist = []

        for r, d, f in os.walk(path):
            if incFile:
                for sfile in f:
                    if name and not UtilMgr.isValidStr(sfile, name):
                        continue
                    flist.append(os.path.join(r, sfile))

            if incDir:
                for sdir in d:
                    if name and not UtilMgr.isValidStr(sdir, name):
                        continue
                    flist.append(os.path.join(r, sdir))

            if not recursive:
                break

        return flist

    @staticmethod
    def getUTCTime():
        datetime = SysMgr.getPkg("datetime", False)
        if datetime:
            return datetime.datetime.utcnow().strftime("%Y-%m-%dT%H:%M:%SZ")
        else:
            return None

    @staticmethod
    def getFileList(flist, sort=False, exceptDir=False):
        if not flist or type(flist) is not list:
            return []

        rlist = []
        for item in flist:
            item = item.strip()
            if item.startswith("-"):
                break

            # apply regular expression for path #
            ilist = UtilMgr.convPath(item)
            if not ilist:
                SysMgr.printWarn(
                    "failed to find any file related to '%s'" % item, True
                )
            elif UtilMgr.isString(ilist):
                rlist.append(ilist)
            elif type(ilist) is list:
                rlist += ilist

        # check redundant files #
        if len(rlist) != len(set(rlist)):
            SysMgr.printWarn(
                "detected redundant files in [ %s ]" % ", ".join(rlist), True
            )

        # exclude dir #
        if exceptDir:
            newlist = []
            for fname in rlist:
                if os.path.isdir(fname):
                    continue
                newlist.append(fname)
            rlist = newlist

        # remove redundant files #
        if sort:
            return sorted(rlist)
        else:
            return rlist

    @staticmethod
    def decodeArg(value):
        try:
            text = repr(value.decode())
        except SystemExit:
            sys.exit(0)
        except:
            text = value

        # define start index by encoding type #
        if type(text) is bytes:
            start = 2
        else:
            start = 1

        return text[start:].rstrip("'")

    @staticmethod
    def convBin2Str(path, pos=False):
        try:
            if sys.version_info < (3, 0):
                fd = open(path, "rb")
            else:
                fd = open(path, encoding="latin-1")

            content = fd.read()
            strList = list(re.findall("[^\x00-\x1F\x7F-\xFF]{4,}", content))

            # add position #
            if pos:
                lastPos = 0
                dictList = {}
                for item in strList:
                    dictList.setdefault(item, content.find(item, lastPos))
                    lastPos = dictList[item]
                return dictList

            return strList
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to convert '%s' to strings" % path, True)
            return False

    @staticmethod
    def bisect_left(a, x, lo=0, hi=None):
        # copied from python standard library bisect.py #
        if lo < 0:
            raise ValueError("lo must be non-negative")
        if not hi:
            hi = len(a)
        while lo < hi:
            mid = (lo + hi) // 2
            if a[mid] <= x:
                lo = mid + 1
            else:
                hi = mid
        return lo

    @staticmethod
    def getFlagBit(vlist, flist):
        num = 0

        for flag in flist:
            try:
                num |= vlist[flag]
            except:
                SysMgr.printErr(
                    "failed to get %s in [%s]" % (flag, "|".join(list(vlist)))
                )
                sys.exit(-1)

        return num

    @staticmethod
    def getFlagList(value, flist, num="hex"):
        rlist = []
        numVal = long(value)
        for name, bits in list(flist.items()):
            if numVal & bits:
                rlist.append(name)
        return rlist

    @staticmethod
    def getFlagString(value, flist, num="hex"):
        string = ""
        numVal = long(value)
        for bit in list(flist):
            try:
                if numVal - bit < 0:
                    break
                elif numVal & bit:
                    string = "%s%s|" % (string, flist[bit])
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn(
                    "failed to get flag info for %s" % value, reason=True
                )

        # check value for 0 index #
        if 0 in flist:
            if num == "hex" and numVal & 0xF == 0:
                string = "%s|%s" % (flist[bit], string)
            elif num == "oct" and numVal & 0o7 == 0:
                string = "%s|%s" % (flist[bit], string)
            elif num == "bin" and numVal & 0 == 0:
                string = "%s|%s" % (flist[bit], string)

        if string:
            return string[:-1]
        else:
            return value

    @staticmethod
    def encodeBase64(value):
        base64 = SysMgr.getPkg("base64", False)

        try:
            return base64.b64encode(value)
        except SystemExit:
            sys.exit(0)
        except:
            return value

    @staticmethod
    def readLEB128(fd):
        data = None
        while 1:
            char = fd.read(1)
            if ord(char) & 0x80 == 0:
                break
            elif not data:
                data = char
            else:
                data += char
        return data

    @staticmethod
    def decodeSLEB128(obj):
        size = 1
        value = 0

        # get size #
        for i, b in enumerate(obj):
            b = b if type(b) == long else ord(b)
            value += (b & 0x7F) << (i * 7)
            if (b & 0x80) == 0:
                break
            size += 1

        # decode data #
        obj = obj[:size]
        if ord(obj[-1]) & 0x40:
            # negative -> sign extend
            value |= -(1 << (7 * len(obj)))

        return value, size

    @staticmethod
    def decodeULEB128(obj):
        size = 1
        value = 0

        # get size #
        for b in obj:
            val = b if type(b) == long else ord(b)
            if (val & 0x80) == 0:
                break
            size += 1

        # decode data #
        for b in reversed(obj[:size]):
            b = b if type(b) == long else ord(b)
            value = (value << 7) + (b & 0x7F)

        return value, size

    @staticmethod
    def isCompressed(fname=None, fd=None):
        # file name #
        if fname:
            try:
                fd = open(fname, "rb")
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenErr(fname)
                sys.exit(-1)

        # file descriptor #
        if fd:
            data = fd.read(2)
            fd.seek(0, 0)
            if struct.unpack("BB", data) == (0x1F, 0x8B):
                return True
            else:
                return False

        # no value #
        return False

    @staticmethod
    def conv2BitStr(content):
        return bin(content)

    @staticmethod
    def decodeBase64(value):
        base64 = SysMgr.getPkg("base64", False)

        try:
            return base64.b64decode(value)
        except SystemExit:
            sys.exit(0)
        except:
            return value

    @staticmethod
    def encodeStr(value):
        try:
            return value.encode()
        except SystemExit:
            sys.exit(0)
        except:
            try:
                return value.encode("utf8", "surrogateescape")
            except SystemExit:
                sys.exit(0)
            except:
                return value

    @staticmethod
    def isString(value):
        if isinstance(value, str):
            return True
        elif sys.version_info >= (3, 0, 0):
            if isinstance(value, bytes):
                return True
        elif isinstance(value, unicode):  # pylint: disable=undefined-variable
            return True
        return False

    @staticmethod
    def isFloat(value):
        if type(value) is float:
            return True
        elif type(value) is str:
            try:
                float(value)
                return True
            except SystemExit:
                sys.exit(0)
            except:
                return False
        else:
            return False

    @staticmethod
    def isNumber(value):
        if isinstance(value, (int, long)):
            return True
        elif type(value) is str:
            if value.isdigit():
                return True

            try:
                if value.startswith("0x") and long(value, 16):
                    return True
                else:
                    return False
            except SystemExit:
                sys.exit(0)
            except:
                return False
        else:
            return False

    @staticmethod
    def getTextLines(fname, verb=False, retfd=False, load=True):
        buf = []

        if verb:
            # get output size #
            fsize = UtilMgr.getFileSizeStr(fname)

            # set job type #
            if load:
                job = "loading"
            else:
                job = "checking"

            SysMgr.printStat(r"start %s '%s'%s..." % (job, fname, fsize))

        # open gzip file #
        try:
            # check gzip magic number #
            if not UtilMgr.isGzipFile(fname):
                raise Exception()

            compressor = SysMgr.getPkg("gzip", False)
            fd = compressor.open(fname, "rt")
        except SystemExit:
            sys.exit(0)
        except:
            fd = None

        # open normal file #
        try:
            if not fd:
                fd = open(fname, "r", encoding="utf-8")
        except SystemExit:
            sys.exit(0)
        except:
            fd = open(fname, "r")

        # just return fd #
        if retfd:
            return fd

        # get total size #
        try:
            totalSize = os.stat(fname).st_size
        except SystemExit:
            sys.exit(0)
        except:
            totalSize = 0

        # read data from a file #
        while 1:
            try:
                data = fd.readline()
                if not data:
                    break

                buf.append(data)

                if verb:
                    UtilMgr.printProgress(fd.tell(), totalSize)
            except SystemExit:
                sys.exit(0)
            except:
                break

        if verb:
            UtilMgr.deleteProgress()

        try:
            fd.close()
        except:
            pass

        return buf

    @staticmethod
    def convPath(value, retStr=False, isExit=False, separator=" ", warn=True):
        # strip path #
        value = value.strip()

        glob = SysMgr.getPkg("glob", False)
        if glob:
            """
            # sort option #
            glob(value, key=os.path.getctime)
            glob(value, key=os.path.getatime)
            glob(value, key=os.path.getmtime)
            glob(value, key=os.path.getsize)
            """

            # check recursive path for specific version(>=python 3.5) #
            if "**" in value and sys.version_info >= (3, 5):
                res = glob.glob(value, recursive=True)
            else:
                res = glob.glob(value)

            if not res and isExit:
                SysMgr.printErr("failed to find a file matching '%s'" % value)
                sys.exit(-1)

            # str #
            if retStr:
                return sorted(separator.join(res))
            # list #
            else:
                return sorted(res)
        elif warn:
            if "*" in value:
                SysMgr.printWarn(
                    "failed to handle * character in the path "
                    "because of no glob package",
                    True,
                )

        # str #
        if retStr:
            return value
        # list #
        else:
            return [value]

    @staticmethod
    def convStr2Word(bstring):
        try:
            return struct.unpack("L", bstring)[0]
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to convert string %s to word" % bstring)
            return None

    @staticmethod
    def convOverlayPath(path, overlayfsList):
        fileList = []
        itemList = ["lowerdir", "upperdir"]

        for pos, info in overlayfsList.items():
            if not pos in path:
                continue

            for target in itemList:
                for item in info[target]:
                    fullpath = item + path
                    if os.path.exists(fullpath):
                        fileList.append(fullpath)

        # return recent path #
        if fileList:
            return fileList[-1]
        else:
            return path

    @staticmethod
    def convStr2Num(string, verb=True, onlyHex=False):
        try:
            if isinstance(string, (int, long)):
                return string
            elif not onlyHex and string.isdigit():
                string = long(string)
            else:
                string = long(string, 16)
        except SystemExit:
            sys.exit(0)
        except:
            if verb:
                SysMgr.printErr(
                    "failed to convert %s to number" % string, True
                )
            return None

        return string

    @staticmethod
    def convNum(number, isFloat=False, floatDigit=1):
        try:
            if isFloat:
                return format(round(float(number), 1), ",")
            else:
                return format(long(number), ",")
        except SystemExit:
            sys.exit(0)
        except:
            return number

    @staticmethod
    def convCpuColor(value, string=None, size=1, align="right"):
        if string is None:
            string = value

        if value >= SysMgr.cpuPerHighThreshold:
            return UtilMgr.convColor(string, "RED", size, align)
        elif value > 0:
            return UtilMgr.convColor(string, "YELLOW", size, align)
        else:
            return str(string)

    @staticmethod
    def convColor(string, color="LIGHT", size=1, align="right", force=False):
        # check skip condition #
        if not color:
            return str(string)
        elif force and not SysMgr.isWindows:
            pass
        elif not SysMgr.colorEnable:
            return str(string)
        elif SysMgr.outPath or SysMgr.jsonEnable:
            SysMgr.colorEnable = False
            return str(string)

        # direction #
        if align == "right":
            string = "{0:>{size}}".format(str(string), size=size)
        else:
            string = "{0:<{size}}".format(str(string), size=size)

        # add color characters #
        try:
            return "%s%s%s" % (
                ConfigMgr.COLOR_LIST[color],
                string,
                ConfigMgr.ENDC,
            )
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn(
                "failed to convert color for %s" % color, reason=True
            )
            return str(string)

    @staticmethod
    def convSize2UnitIgn(size, isInt=False, unit=None):
        return str(size)

    @staticmethod
    def convSize2Unit(size, isInt=False, unit=None):
        sizeKB = 1024
        sizeMB = 1048576
        sizeGB = 1073741824
        sizeTB = 1099511627776
        sizePB = 1125899906842624
        sizeEB = 1152921504606846976
        # sizeZB = 1180591620717411303424
        # sizeYB = 120892581961462917470617

        # convert to ABS value #
        try:
            sizeAbs = abs(size)
        except SystemExit:
            sys.exit(0)
        except:
            return "?"

        if unit:
            factor = 1 if isInt else 1.0

            upperUnit = unit.upper()
            if upperUnit == "K":
                val = size / sizeKB * factor
            elif upperUnit == "M":
                val = size / sizeMB * factor
            elif upperUnit == "G":
                val = size / sizeGB * factor
            elif upperUnit == "T":
                val = size / sizeTB * factor
            elif upperUnit == "P":
                val = size / sizePB * factor
            elif upperUnit == "E":
                val = size / sizeEB * factor
            else:
                SysMgr.printErr("no support size unit '%s'" % unit)
                sys.exit(-1)

            if isInt:
                num = UtilMgr.convNum(long(val))
            else:
                num = UtilMgr.convNum(round(float(val), 1), isFloat=True)

            return "%s%s" % (num, upperUnit)

        # Int type #
        if isInt:
            try:
                if sizeAbs >= sizeEB:
                    return "%dE" % (size >> 60)
                elif sizeAbs >= sizePB:
                    return "%dP" % (size >> 50)
                elif sizeAbs >= sizeTB:
                    return "%dT" % (size >> 40)
                elif sizeAbs >= sizeGB:
                    return "%dG" % (size >> 30)
                elif sizeAbs >= sizeMB:
                    return "%dM" % (size >> 20)
                elif sizeAbs >= sizeKB:
                    return "%dK" % (size >> 10)
                else:
                    return "%d" % size
            except SystemExit:
                sys.exit(0)
            except:
                return "?"
        # Float type #
        else:
            try:
                if sizeAbs >= sizeEB:
                    return "%.1fE" % ((size >> 50) / 1024.0)
                elif sizeAbs >= sizePB:
                    return "%.1fP" % ((size >> 40) / 1024.0)
                elif sizeAbs >= sizeTB:
                    return "%.1fT" % ((size >> 30) / 1024.0)
                elif sizeAbs >= sizeGB:
                    return "%.1fG" % ((size >> 20) / 1024.0)
                elif sizeAbs >= sizeMB:
                    return "%.1fM" % ((size >> 10) / 1024.0)
                elif sizeAbs >= sizeKB:
                    return "%.1fK" % (size / 1024.0)
                else:
                    return "%d" % (size)
            except SystemExit:
                sys.exit(0)
            except:
                return "?"

    @staticmethod
    def convTime2Sec(time):
        # convert time to seconds #
        try:
            sec = 0

            nums = time.strip().split(":")
            if len(nums) == 3:
                y = d = 0
                times = nums
            elif len(nums) == 4:
                y = 0
                d = int(nums[0].rstrip("d"))
                times = nums[1:]
            elif len(nums) == 5:
                y = int(nums[0].rstrip("y"))
                d = int(nums[0].rstrip("d"))
                times = nums[1:]
            else:
                raise Exception()

            # convert type #
            h, m, s = list(map(int, times))

            # convert items to seconds #
            sec += s
            sec += m * 60
            sec += h * 3600
            if d:
                sec += d * 86400
            if y:
                sec += y * 31536000
        except SystemExit:
            sys.exit(0)
        except:
            pass

        return sec

    @staticmethod
    def convTime(time, remainder=False):
        try:
            if not remainder:
                raise Exception("integer")
            remain = ".%02d" % long(time * 100 % 100)
        except SystemExit:
            sys.exit(0)
        except:
            remain = ""

        # convert seconds to time #
        try:
            m, s = divmod(time, 60)
            h, m = divmod(m, 60)

            # hour #
            if h >= 24:
                d, h = divmod(h, 24)

                # year #
                if d >= 365:
                    y, d = divmod(d, 365)
                    d = "%dy:%dd:" % (y, d)
                else:
                    d = "%dd:" % d
            else:
                d = ""

            ctime = "%s%02d:%02d:%02d%s" % (d, h, m, s, remain)
        except SystemExit:
            sys.exit(0)
        except:
            ctime = "%s%02s:%02s:%02s%s" % ("", "?", "?", "?", remain)

        return ctime.strip()

    @staticmethod
    def prepareForImageFile(logFile, itype="", outFile=None):
        # build output file name #
        if outFile:
            outputFile = outFile
        else:
            if SysMgr.outPath:
                outputFile = os.path.normpath(SysMgr.outPath)
            else:
                outputFile = os.path.normpath(logFile)

            # convert output path #
            if os.path.isdir(outputFile):
                filename = os.path.basename(logFile)
                filename = os.path.splitext(filename)[0]
                name = "%s/%s" % (outputFile, filename)
            else:
                name = os.path.splitext(outputFile)[0]

            outputFile = "%s_%s.%s" % (name, itype, SysMgr.drawFormat)

        try:
            # backup an exist image file #
            if os.path.isfile(outputFile):
                name, ext = os.path.splitext(outputFile)

                oldPath = "%s_old%s" % (name, ext)
                if os.path.isfile(oldPath):
                    os.remove(oldPath)

                os.rename(outputFile, oldPath)

                SysMgr.printInfo(
                    "renamed '%s' to '%s' for backup" % (outputFile, oldPath)
                )
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to backup '%s' to '%s'" % (outputFile, oldPath), True
            )

        return outputFile

    @staticmethod
    def convUnit2Time(data):
        if str(data).isdigit():
            ret = long(data)
        elif data.upper().endswith("S"):
            ret = long(data[:-1])
        elif data.upper().endswith("M"):
            ret = long(data[:-1]) * 60
        elif data.upper().endswith("H"):
            ret = long(data[:-1]) * 60 * 60
        elif data.upper().endswith("D"):
            ret = long(data[:-1]) * 60 * 60 * 24
        elif data.upper().endswith("W"):
            ret = long(data[:-1]) * 60 * 60 * 24 * 7
        else:
            ret = 0
            SysMgr.printErr("failed to convert '%s' to seconds" % data)

        return ret

    @staticmethod
    def convUnit2Size(value):
        sizeKB = 1024
        sizeMB = 1048576
        sizeGB = 1073741824
        sizeTB = 1099511627776
        sizePB = 1125899906842624
        sizeEB = 1152921504606846976
        # sizeZB = 1180591620717411303424
        # sizeYB = 120892581961462917470617

        if str(value).isdigit():
            return long(value)

        # convert unit character to capital #
        value = value.upper()

        try:
            if value.endswith("K"):
                return long(float(value[:-1]) * sizeKB)
            if value.endswith("KB"):
                return long(float(value[:-2]) * sizeKB)

            if value.endswith("M"):
                return long(float(value[:-1]) * sizeMB)
            if value.endswith("MB"):
                return long(float(value[:-2]) * sizeMB)

            if value.endswith("G"):
                return long(float(value[:-1]) * sizeGB)
            if value.endswith("GB"):
                return long(float(value[:-2]) * sizeGB)

            if value.endswith("T"):
                return long(float(value[:-1]) * sizeTB)
            if value.endswith("TB"):
                return long(float(value[:-2]) * sizeTB)

            if value.endswith("P"):
                return long(float(value[:-1]) * sizePB)
            if value.endswith("PB"):
                return long(float(value[:-2]) * sizePB)

            if value.endswith("E"):
                return long(float(value[:-1]) * sizeEB)
            if value.endswith("EB"):
                return long(float(value[:-2]) * sizeEB)

            SysMgr.printErr("failed to convert '%s' to bytes" % value)

            assert False
        except SystemExit:
            sys.exit(0)
        except AssertionError:
            raise Exception("wrong number unit")
        except:
            return value

    @staticmethod
    def saveStr2File(string, path):
        # open the file #
        try:
            with open(path, "w") as fd:
                fd.truncate()
                fd.write(string)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to write JSON format data to %s" % path, True
            )
            sys.exit(-1)

    @staticmethod
    def writeJsonObject(jsonObj, fd=None, trunc=False, path=None):
        if fd:
            try:
                if trunc:
                    fd.seek(0, 0)
                    fd.truncate()
            except SystemExit:
                sys.exit(0)
            except:
                pass

            try:
                fd.write(jsonObj)
                fd.flush()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn(
                    "failed to write JSON format data", reason=True
                )
            return

        # check write option #
        if trunc:
            perm = "w"
        else:
            perm = "a"

        # open the file #
        try:
            with open(path, perm) as fd:
                fd.write(jsonObj)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to write JSON format data to %s" % path, True
            )
            sys.exit(-1)

    @staticmethod
    def saveObject2File(obj, path):
        if not obj:
            return False

        pickle = SysMgr.getPicklePkg(False)
        if not pickle:
            return False

        # compress by gzip #
        if "COMPCACHE" in SysMgr.environList:
            compressor = SysMgr.getPkg("gzip", False)
        else:
            compressor = False

        # original object #
        try:
            if compressor:
                with compressor.open(path, "wb") as fd:
                    pickle.dump(obj, fd, -1)
            else:
                with open(path, "wb") as fd:
                    pickle.dump(obj, fd, -1)
            os.chmod(path, 0o777)
            return True
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn(
                "failed to save %s object to %s"
                % (obj.__class__.__name__, path),
                reason=True,
            )
            return False

    @staticmethod
    def loadObjectFromFile(path):
        # check object exists #
        if not os.path.isfile(path):
            return None

        # load pickle object #
        pickle = SysMgr.getPicklePkg(False)
        if not pickle:
            return None

        try:
            # try to load compressed cache #
            with SysMgr.getPkg("gzip", False).open(path, "rb") as fd:
                return pickle.load(fd)
        except SystemExit:
            sys.exit(0)
        except:
            try:
                with open(path, "rb") as fd:
                    return pickle.load(fd)
            except SystemExit:
                sys.exit(0)
            except:
                return None

    @staticmethod
    def printProgress(current=0, dest=0):
        if not SysMgr.printEnable or dest == sys.maxsize:
            return

        # just output #
        if not current and not dest:
            if UtilMgr.progressCnt >= len(UtilMgr.progressChar) - 1:
                UtilMgr.progressCnt = 0
            else:
                UtilMgr.progressCnt += 1

            mod = UtilMgr.progressCnt

            progressStr = ".... %s%s" % (UtilMgr.progressChar[mod], "\b" * 6)
        else:
            try:
                div = round((current / float(dest)) * 100, 1)
            except SystemExit:
                sys.exit(0)
            except:
                div = 0

            percent = long(div)

            mod = percent & 3

            progressStr = "%3d%% %s%s" % (
                percent,
                UtilMgr.progressChar[mod],
                "\b" * 6,
            )

        # handle reentrant call exception #
        try:
            if progressStr == UtilMgr.progressStr:
                return

            UtilMgr.progressStr = progressStr
            sys.stdout.write(progressStr)
            sys.stdout.flush()
        except SystemExit:
            sys.exit(0)
        except:
            return

    @staticmethod
    def writeFlamegraph(path, samples, title, depth=20):
        # flamegraph from https://github.com/rbspy/rbspy/tree/master/src/ui/flamegraph.rs #
        # fixed font size: 12, bar height: 15 #
        barHeight = 15
        titleHeight = (title.count("<tspan ") + 1) * barHeight
        height = barHeight * depth + 100 + titleHeight
        width = "1"
        flameCode = (
            (
                """<?xml version="1.0" standalone="no"?>
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" width="%s" height="%s" onload="init(evt)" viewBox="0 0 %s %s"
        """
                % (width, height, width, height)
            )
            + """
        xmlns="http://www.w3.org/2000/svg"
        xmlns:xlink="http://www.w3.org/1999/xlink">
        <!--Flame graph stack visualization. See https://github.com/brendangregg/FlameGraph for latest version, and http://www.brendangregg.com/flamegraphs.html for examples.-->
        <!--NOTES: -->
        <defs>
                <linearGradient id="background" y1="0" y2="1" x1="0" x2="0">
                        <stop stop-color="#eeeeee" offset="5%"/>
                        <stop stop-color="#eeeeb0" offset="95%"/>
                </linearGradient>
        </defs>
        <style type="text/css">
            text { font-family:"Verdana"; font-size:12px; fill:rgb(0,0,0); }
            #title { text-anchor:middle; font-size:17px; }
            #search { opacity:0.1; cursor:pointer; }
            #search:hover, #search.show { opacity:1; }
            #subtitle { text-anchor:left; font-color:rgb(160,160,160); }
            #unzoom { cursor:pointer; }
            #frames > *:hover { stroke:black; stroke-width:0.5; cursor:pointer; }
            .hide { display:none; }
            .parent { opacity:0.5; }
        </style>
        <script type="text/ecmascript">
                <![CDATA[var nametype = 'Function:';
var fontsize = 12;
var fontwidth = 0.59;
var xpad = 10;
var inverted = true;
var searchcolor = 'rgb(255,0,0)';
var searchstroke = 'rgb(0,0,0)';
var fluiddrawing = true;
var truncate_text_right = true;]]>
                <![CDATA["use strict";
var details, searchbtn, unzoombtn, matchedtxt, svg, searching, frames;
function init(evt) {
    details = document.getElementById("details").firstChild;
    searchbtn = document.getElementById("search");
    unzoombtn = document.getElementById("unzoom");
    matchedtxt = document.getElementById("matched");
    svg = document.getElementsByTagName("svg")[0];
    frames = document.getElementById("frames");
    searching = 0;

    // Use GET parameters to restore a flamegraph's state.
    var restore_state = function() {
        var params = get_params();
        if (params.x && params.y)
            zoom(find_group(document.querySelector('[x="' + params.x + '"][y="' + params.y + '"]')));
        if (params.s)
            search(params.s);
    };

    if (fluiddrawing) {
        // Make width dynamic so the SVG fits its parent's width.
        svg.removeAttribute("width");
        // Edge requires us to have a viewBox that gets updated with size changes
        var isEdge = /Edge\/\d./i.test(navigator.userAgent);
        if (!isEdge) {
          svg.removeAttribute("viewBox");
        }
        var update_for_width_change = function() {
            if (isEdge) {
                svg.attributes.viewBox.value = "0 0 " + svg.width.baseVal.value + " " + svg.height.baseVal.value;
            }

            // Keep consistent padding on left and right of frames container.
            frames.attributes.width.value = svg.width.baseVal.value - xpad * 2;

            // Text truncation needs to be adjusted for the current width.
            var el = frames.children;
            for(var i = 0; i < el.length; i++) {
                update_text(el[i]);
            }

            // Keep search elements at a fixed distance from right edge.
            var svgWidth = svg.width.baseVal.value;
            searchbtn.attributes.x.value = svgWidth - xpad - 100;
            matchedtxt.attributes.x.value = svgWidth - xpad - 100;
        };
        window.addEventListener('resize', function() {
            update_for_width_change();
        });
        // This needs to be done asynchronously for Safari to work.
        setTimeout(function() {
            unzoom();
            update_for_width_change();
            restore_state();
        }, 0);
    } else {
        restore_state();
    }
}
// event listeners
window.addEventListener("click", function(e) {
    var target = find_group(e.target);
    if (target) {
        if (target.nodeName == "a") {
            if (e.ctrlKey === false) return;
            e.preventDefault();
        }
        if (target.classList.contains("parent")) unzoom();
        zoom(target);

        // set parameters for zoom state
        var el = target.querySelector("rect");
        if (el && el.attributes && el.attributes.y && el.attributes._orig_x) {
            var params = get_params()
            params.x = el.attributes._orig_x.value;
            params.y = el.attributes.y.value;
            history.replaceState(null, null, parse_params(params));
        }
    }
    else if (e.target.id == "unzoom") {
        unzoom();

        // remove zoom state
        var params = get_params();
        if (params.x) delete params.x;
        if (params.y) delete params.y;
        history.replaceState(null, null, parse_params(params));
    }
    else if (e.target.id == "search") search_prompt();
}, false)
// mouse-over for info
// show
window.addEventListener("mouseover", function(e) {
    var target = find_group(e.target);
    if (target && details) {
        details.nodeValue = nametype + " " + g_to_text(target);
    }
}, false)
// clear
window.addEventListener("mouseout", function(e) {
    var target = find_group(e.target);
    if (target && details) {
        details.nodeValue = ' ';
    }
}, false)
// F3 / ctrl-F for search, ESC for reset search or zoom
window.addEventListener("keydown",function (e) {
    if (e.keyCode === 114 || (e.ctrlKey && e.keyCode === 70)) {
        e.preventDefault();
        search_prompt();
    } else if (e.keyCode === 27 || (e.ctrlKey && e.keyCode === 90)) {
        e.preventDefault();
        reset_search();
        unzoom()
    }
}, false)
// functions
function get_params() {
    var params = {};
    var paramsarr = window.location.search.substr(1).split('&');
    for (var i = 0; i < paramsarr.length; ++i) {
        var tmp = paramsarr[i].split("=");
        if (!tmp[0] || !tmp[1]) continue;
        params[tmp[0]] = decodeURIComponent(tmp[1]);
    }
    return params;
}
function parse_params(params) {
    var uri = "?";
    for (var key in params) {
        uri += key + '=' + encodeURIComponent(params[key]) + '&';
    }
    if (uri.slice(-1) == "&")
        uri = uri.substring(0, uri.length - 1);
    if (uri == '?')
        uri = window.location.href.split('?')[0];
    return uri;
}
function find_child(node, selector) {
    var children = node.querySelectorAll(selector);
    if (children.length) return children[0];
    return;
}
function find_group(node) {
    var parent = node.parentElement;
    if (!parent) return;
    if (parent.id == "frames") return node;
    return find_group(parent);
}
function orig_save(e, attr, val) {
    if (e.attributes["_orig_" + attr] != undefined) return;
    if (e.attributes[attr] == undefined) return;
    if (val == undefined) val = e.attributes[attr].value;
    e.setAttribute("_orig_" + attr, val);
}
function orig_load(e, attr) {
    if (e.attributes["_orig_"+attr] == undefined) return;
    e.attributes[attr].value = e.attributes["_orig_" + attr].value;
    e.removeAttribute("_orig_" + attr);
}
function g_to_text(e) {
    var text = find_child(e, "title").firstChild.nodeValue;
    return (text)
}
function g_to_func(e) {
    var func = g_to_text(e);
    // if there's any manipulation we want to do to the function
    // name before it's searched, do it here before returning.
    return (func);
}
function update_text(e) {
    var r = find_child(e, "rect");
    var t = find_child(e, "text");
    var w = parseFloat(r.attributes.width.value) * frames.attributes.width.value / 100 - 3;
    var txt = find_child(e, "title").textContent.replace(/&lt;/g,'<').replace(/&gt;/g,'>').replace(/&amp;/g,'&');
    t.attributes.x.value = format_percent((parseFloat(r.attributes.x.value) + (100 * 3 / frames.attributes.width.value)));
    // Smaller than this size won't fit anything
    if (w < 2 * fontsize * fontwidth) {
        t.textContent = "";
        return;
    }
    t.textContent = txt;
    // Fit in full text width
    if (/^ *\$/.test(txt) || t.getComputedTextLength() < w)
        return;
    if (truncate_text_right) {
        // Truncate the right side of the text.
        for (var x = txt.length - 2; x > 0; x--) {
            if (t.getSubStringLength(0, x + 2) <= w) {
                t.textContent = txt.substring(0, x) + "..";
                return;
            }
        }
    } else {
        // Truncate the left side of the text.
        for (var x = 2; x < txt.length; x++) {
            if (t.getSubStringLength(x - 2, txt.length) <= w) {
                t.textContent = ".." + txt.substring(x, txt.length);
                return;
            }
        }
    }
    t.textContent = "";
}
// zoom
function zoom_reset(e) {
    if (e.attributes != undefined) {
        orig_load(e, "x");
        orig_load(e, "width");
    }
    if (e.childNodes == undefined) return;
    for(var i = 0, c = e.childNodes; i < c.length; i++) {
        zoom_reset(c[i]);
    }
}
function zoom_child(e, x, ratio) {
    if (e.attributes != undefined) {
        if (e.attributes.x != undefined) {
            orig_save(e, "x");
            e.attributes.x.value = format_percent((parseFloat(e.attributes.x.value) - x) * ratio);
            if (e.tagName == "text") {
                e.attributes.x.value = format_percent(parseFloat(find_child(e.parentNode, "rect[x]").attributes.x.value) + (100 * 3 / frames.attributes.width.value));
            }
        }
        if (e.attributes.width != undefined) {
            orig_save(e, "width");
            e.attributes.width.value = format_percent(parseFloat(e.attributes.width.value) * ratio);
        }
    }
    if (e.childNodes == undefined) return;
    for(var i = 0, c = e.childNodes; i < c.length; i++) {
        zoom_child(c[i], x, ratio);
    }
}
function zoom_parent(e) {
    if (e.attributes) {
        if (e.attributes.x != undefined) {
            orig_save(e, "x");
            e.attributes.x.value = "0.0%";
        }
        if (e.attributes.width != undefined) {
            orig_save(e, "width");
            e.attributes.width.value = "100.0%";
        }
    }
    if (e.childNodes == undefined) return;
    for(var i = 0, c = e.childNodes; i < c.length; i++) {
        zoom_parent(c[i]);
    }
}
function zoom(node) {
    var attr = find_child(node, "rect").attributes;
    var width = parseFloat(attr.width.value);
    var xmin = parseFloat(attr.x.value);
    var xmax = xmin + width;
    var ymin = parseFloat(attr.y.value);
    var ratio = 100 / width;
    // XXX: Workaround for JavaScript float issues (fix me)
    var fudge = 0.001;
    unzoombtn.classList.remove("hide");
    var el = frames.children;
    for (var i = 0; i < el.length; i++) {
        var e = el[i];
        var a = find_child(e, "rect").attributes;
        var ex = parseFloat(a.x.value);
        var ew = parseFloat(a.width.value);
        // Is it an ancestor
        if (!inverted) {
            var upstack = parseFloat(a.y.value) > ymin;
        } else {
            var upstack = parseFloat(a.y.value) < ymin;
        }
        if (upstack) {
            // Direct ancestor
            if (ex <= xmin && (ex+ew+fudge) >= xmax) {
                e.classList.add("parent");
                zoom_parent(e);
                update_text(e);
            }
            // not in current path
            else
                e.classList.add("hide");
        }
        // Children maybe
        else {
            // no common path
            if (ex < xmin || ex + fudge >= xmax) {
                e.classList.add("hide");
            }
            else {
                zoom_child(e, xmin, ratio);
                update_text(e);
            }
        }
    }
}
function unzoom() {
    unzoombtn.classList.add("hide");
    var el = frames.children;
    for(var i = 0; i < el.length; i++) {
        el[i].classList.remove("parent");
        el[i].classList.remove("hide");
        zoom_reset(el[i]);
        update_text(el[i]);
    }
}
// search
function reset_search() {
    var el = document.querySelectorAll("#frames rect");
    for (var i = 0; i < el.length; i++) {
        orig_load(el[i], "fill")
        el[i].setAttribute("stroke-width", "0")
    }
    var params = get_params();
    delete params.s;
    history.replaceState(null, null, parse_params(params));
}
function search_prompt() {
    if (!searching) {
        var term = prompt("Enter a search term (regexp " +
            "allowed, eg: ^ext4_)", "");
        if (term != null) {
            search(term)
        }
    } else {
        reset_search();
        searching = 0;
        searchbtn.classList.remove("show");
        if (searchbtn.firstChild) {
            searchbtn.firstChild.nodeValue = "Search (F3)"
        }
        matchedtxt.classList.add("hide");
        if (matchedtxt.firstChild) {
            matchedtxt.firstChild.nodeValue = ""
        }
    }
}
function search(term) {
    var re = new RegExp(term);
    var el = frames.children;
    var matches = new Object();
    var maxwidth = 0;
    for (var i = 0; i < el.length; i++) {
        var e = el[i];
        var func = g_to_func(e);
        var rect = find_child(e, "rect");
        if (func == null || rect == null)
            continue;
        // Save max width. Only works as we have a root frame
        var w = parseFloat(rect.attributes.width.value);
        if (w > maxwidth)
            maxwidth = w;
        if (func.match(re)) {
            // highlight
            var x = parseFloat(rect.attributes.x.value);
            orig_save(rect, "fill");
            rect.setAttribute("fill", searchcolor);
            rect.setAttribute("stroke", searchstroke);
            rect.setAttribute("stroke-width", "3");
            // remember matches
            if (matches[x] == undefined) {
                matches[x] = w;
            } else {
                if (w > matches[x]) {
                    // overwrite with parent
                    matches[x] = w;
                }
            }
            searching = 1;
        }
    }
    if (!searching)
        return;
    var params = get_params();
    params.s = term;
    history.replaceState(null, null, parse_params(params));

    searchbtn.classList.add("show");
    if (searchbtn.firstChild) {
        searchbtn.firstChild.nodeValue = "Reset Search (F3)";
    }
    // calculate percent matched, excluding vertical overlap
    var count = 0;
    var lastx = -1;
    var lastw = 0;
    var keys = Array();
    for (k in matches) {
        if (matches.hasOwnProperty(k))
            keys.push(k);
    }
    // sort the matched frames by their x location
    // ascending, then width descending
    keys.sort(function(a, b){
        return a - b;
    });
    // Step through frames saving only the biggest bottom-up frames
    // thanks to the sort order. This relies on the tree property
    // where children are always smaller than their parents.
    var fudge = 0.0001;    // JavaScript floating point
    for (var k in keys) {
        var x = parseFloat(keys[k]);
        var w = matches[keys[k]];
        if (x >= lastx + lastw - fudge) {
            count += w;
            lastx = x;
            lastw = w;
        }
    }
    // display matched percent
    matchedtxt.classList.remove("hide");
    var pct = 100 * count / maxwidth;
    if (pct != 100) pct = pct.toFixed(1);
    if (matchedtxt.firstChild) {
        matchedtxt.firstChild.nodeValue = "Matched: " + pct + "%";
    }
}
function format_percent(n) {
    return n.toFixed(4) + "%";
}
]]>
        </script>
"""
        )
        attrCode = """
    <rect x="0" y="0" width="100%%" height="%s" fill="url(#background)"/>
    <text id="title" x="50.0000%%" y="24.00">Guider Flame Graph</text>
    <text id="subtitle" x="0.0000%%" y="50.00">%s</text>
    <text id="details" x="10" y="213.00"></text>
    <text id="unzoom" class="hide" x="10" y="24.00">Reset Zoom (ESC)</text>
    <text id="search" x="1090" y="24.00">Search (F3)</text>
    <text id="matched" x="1090" y="213.00"></text>
    <svg id="frames" x="10" y="%s" width="%s">
""" % (
            height,
            "\r\n%s" % title if title else "",
            titleHeight,
            width,
        )

        # complete code for flamegraph #
        finalCode = flameCode + attrCode + samples + "\n</svg></svg>"

        # write flamegraph to file #
        try:
            with open(path, "w") as fd:
                fd.write(finalCode)

            os.chmod(path, 0o777)

            # get output size #
            fsize = UtilMgr.getFileSizeStr(path)

            SysMgr.printInfo(
                "saved flamegraph into '%s'%s successfully" % (path, fsize)
            )
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to write flamegraph to %s" % path, True)
            sys.exit(-1)

    @staticmethod
    def getFileSizeStr(path, string=True):
        fsize = UtilMgr.getFileSize(path)
        if fsize and fsize != "0":
            fsize = " [%s]" % fsize
        else:
            fsize = ""
        return fsize

    @staticmethod
    def getFileSize(path, string=True):
        try:
            fsize = long(os.path.getsize(path))
            if string:
                return UtilMgr.convSize2Unit(fsize)
            else:
                return fsize
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("failed to get file size for '%s'" % path)

            if string:
                return "?"
            else:
                return 0

    @staticmethod
    def printFile(path):
        try:
            with open(path, "r") as fd:
                for line in fd:
                    print(line.rstrip())
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to print %s" % path, reason=True)

    @staticmethod
    def deleteProgress():
        if not SysMgr.printEnable:
            return

        sys.stdout.write(" " * 6)
        sys.stdout.write("\b" * 6)

        # handle reentrant call exception #
        try:
            sys.stdout.flush()
        except SystemExit:
            sys.exit(0)
        except:
            return

    @staticmethod
    def which(cmd):
        if not "PATH" in os.environ:
            return None

        pathList = []
        for path in os.environ["PATH"].split(os.pathsep):
            if os.path.exists(os.path.join(path, cmd)):
                pathList.append(os.path.join(path, cmd))

        if pathList:
            return pathList
        else:
            return None

    @staticmethod
    def convDict2Str(dictObj, pretty=True, indent=2, ignore=False):
        try:
            if ignore:
                jsonStr = SysMgr.getPkg("json").dumps(
                    dictObj,
                    indent=indent,
                    ensure_ascii=False,
                    default=lambda o: "<not serializable>",
                )
            else:
                jsonStr = SysMgr.getPkg("json").dumps(
                    dictObj, indent=indent, ensure_ascii=False
                )

            if pretty:
                return jsonStr
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("failed to convert dict to string", reason=True)

            """
            # for debugging #
            SysMgr.printWarn(
                "failed to convert %s to string" % [dictObj], reason=True)
            """

            return None

        # when encode flag is disabled, remove whitespace [\t\n\r\f\v] #
        if not SysMgr.encodeEnable:
            jsonStr = re.sub("\s", "", jsonStr) + "\n"

        return jsonStr

    @staticmethod
    def convUlong2Long(retval):
        retval = retval & 0xFFFFFFFFFFFFFFFF
        if retval & 0x8000000000000000:
            retval = retval - 0x10000000000000000
        return retval

    @staticmethod
    def convStr2Dict(strObj, verb=False):
        try:
            return SysMgr.getPkg("json").loads(strObj)
        except SystemExit:
            sys.exit(0)
        except:
            try:
                strObj = strObj.replace("'", '"')
                return SysMgr.getPkg("json").loads(strObj)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn(
                    "failed to convert %s to dict" % [strObj],
                    always=verb,
                    reason=True,
                )
                return None


class NetworkMgr(object):
    """Manager for remote communication"""

    # define valid request list #
    REQUEST_LIST = {
        "BROADCAST": None,
        "CLEAR": None,
        "DOWNLOAD": None,
        "JOBS": None,
        "LIST": None,
        "NEW": None,
        "NOTIFY": None,
        "PING": None,
        "RESTART": None,
        "RUN": None,
        "UPLOAD": None,
        "UPSTREAM": None,
    }

    def __init__(
        self,
        mode,
        ip,
        port,
        blocking=True,
        tcp=False,
        anyPort=False,
        bind=True,
        netlink=False,
        reuse=True,
    ):

        self.mode = mode
        self.ip = None
        self.port = None
        self.socket = None
        self.request = None
        self.status = None
        self.ignore = 0
        self.fileno = -1
        self.time = None
        self.sendSize = 32767
        self.recvSize = 32767
        self.tcp = tcp
        self.netlink = netlink
        self.connected = False

        # get socket object #
        socket = SysMgr.getPkg("socket")

        try:
            from socket import (
                socket,
                AF_INET,
                SOCK_DGRAM,
                SOCK_STREAM,
                SOL_SOCKET,
                SO_REUSEADDR,
                SO_SNDBUF,
                SO_RCVBUF,
                SOL_TCP,
                SO_RCVTIMEO,
                SO_SNDTIMEO,
                SOCK_RAW,
            )
        except:
            SysMgr.printWarn("failed to import socket", True, reason=True)
            return None

        try:
            # set socket type #
            if tcp:
                self.socket = socket(AF_INET, SOCK_STREAM)
            elif netlink:
                try:
                    from socket import (
                        socket,
                        AF_NETLINK,
                    )  # pylint: disable=no-name-in-module

                    self.socket = socket(
                        AF_NETLINK,
                        SOCK_RAW,
                        ConfigMgr.NETLINK_TYPE["NETLINK_GENERIC"],
                    )
                except:
                    SysMgr.printWarn(
                        "failed to create NETLINK socket", True, reason=True
                    )
                    return None
            else:
                self.socket = socket(AF_INET, SOCK_DGRAM)

            self.fileno = self.socket.fileno()

            # increate socket buffer size to 1MB #
            self.socket.setsockopt(SOL_SOCKET, SO_SNDBUF, 1 << 20)
            self.socket.setsockopt(SOL_SOCKET, SO_RCVBUF, 1 << 20)

            # get buffer size #
            self.sendSize = self.socket.getsockopt(SOL_SOCKET, SO_SNDBUF)
            self.recvSize = self.socket.getsockopt(SOL_SOCKET, SO_RCVBUF)

            # set REUSEADDR #
            if reuse:
                self.socket.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)

            # set REUSEPORT #
            """
            from socket import SO_REUSEPORT
            self.socket.setsockopt(SOL_SOCKET, SO_REUSEPORT, 0)
            """

            # set NODELAY #
            """
            self.setNoDelay()
            """

            # set SENDTIMEOUT #
            """
            sec = 1
            usec = 0
            timeval = struct.pack('ll', sec, usec)
            self.socket.setsockopt(SOL_SOCKET, SO_SNDTIMEO, timeval)
            """

            # convert IP #
            if ip == "*":
                ip = "0.0.0.0"

            # set IP & PORT #
            self.ip = ip
            self.port = port

            if mode == "server":
                # IP #
                if ip is None:
                    self.ip = "0.0.0.0"

                # PORT #
                if anyPort:
                    self.port = 0
                elif port is None:
                    self.port = SysMgr.defaultServPort

                # bind #
                if bind:
                    try:
                        self.socket.bind((self.ip, self.port))
                    except OSError as e:
                        if e.errno == errno.EADDRINUSE:
                            self.port = 0
                            self.socket.bind((self.ip, self.port))
                        else:
                            raise e
                    except SystemExit:
                        sys.exit(0)
                    except:
                        self.socket.bind((self.ip, self.port))

                    # get bind port #
                    self.port = self.socket.getsockname()[1]

            if not blocking:
                self.socket.setblocking(0)
        except:
            err = SysMgr.getErrMsg()
            if err.startswith("13") and not SysMgr.isRoot() and port < 1024:
                feedback = ", use port bigger than 1024"
            else:
                feedback = ""

            # check mode to print error message #
            if (
                SysMgr.warnEnable
                or SysMgr.checkMode("server")
                or SysMgr.checkMode("cli")
            ):
                SysMgr.printErr(
                    (
                        "failed to create a socket for %s:%s as server "
                        "because %s%s"
                    )
                    % (self.ip, self.port, err, feedback)
                )

            """
            if error "99 Cannot assign requested address" occurs:
                add "net.ipv4.ip_nonlocal_bind = 1" in /etc/sysctl.conf
                execute sysctl -p /etc/sysctl.conf
            """

            self.ip = None
            self.port = None

            return None

    def __str__(self):
        return "%s object at %x, IP: %s, PORT: %s" % (
            self.__class__,
            id(self),
            self.ip,
            self.port,
        )

    def listen(self, nrQueue=5):
        return self.socket.listen(nrQueue)

    def accept(self):
        return self.socket.accept()

    def bind(self, ip, port):
        return self.socket.bind((ip, port))

    def write(self, message):
        return self.send(message, write=True)

    def close(self):
        if self.socket:
            ret = self.socket.close()
        else:
            ret = False

        self.socket = None

        return ret

    def flush(self):
        pass

    def timeout(self, sec=3):
        if "TIMEOUT" in SysMgr.environList:
            sec = UtilMgr.getEnvironNum("TIMEOUT")

        self.socket.settimeout(sec)

    @staticmethod
    def sendFile(sock, ip, port, src, des):
        # verify path #
        target = src
        sdir, name = UtilMgr.getPath(target)

        # get file list #
        targetList = UtilMgr.getFiles(sdir, [name])
        if not targetList:
            SysMgr.printWarn("failed to find %s to transfer" % target, True)

            return False

        for target in targetList:
            target = os.path.realpath(os.path.expanduser(target))

            SysMgr.printInfo(
                "start uploading %s[%s] to %s:%s... "
                % (target, UtilMgr.getFileSize(target), sock.ip, sock.port),
                suffix=False,
            )

            # send file info #
            totalSize = os.stat(target).st_size
            fileInfo = "%s#%s" % (target, totalSize)
            sock.send(UtilMgr.encodeStr(fileInfo))

            # read for ACK #
            while 1:
                ret = sock.recv(3)
                if ret is None:
                    continue
                elif ret is False:
                    raise Exception("no response")
                else:
                    break

            # send a file #
            with open(target, "rb") as fd:
                buf = fd.read(sock.sendSize)
                curSize = 0
                while buf:
                    # send a chunk #
                    sock.send(buf)
                    curSize += len(buf)

                    # read for ACK #
                    while 1:
                        ret = sock.recv(3)
                        if ret is None:
                            continue
                        elif ret is False:
                            raise Exception("no response")
                        else:
                            break

                    # read a chunk #
                    buf = fd.read(sock.sendSize)

            # read for ACK #
            while 1:
                ret = sock.recv(3)
                if ret is None:
                    continue
                elif ret is False:
                    raise Exception("no response")
                else:
                    break

            SysMgr.printInfo(
                "uploaded %s[%s] to %s:%s successfully"
                % (target, UtilMgr.getFileSize(target), sock.ip, sock.port)
            )

        return True

    @staticmethod
    def recvFile(sock, ip, port, src, des):
        # get select object #
        selectObj = SysMgr.getPkg("select")

        while 1:
            curSize = 0
            totalSize = None

            # receive file info #
            while 1:
                fileInfo = sock.recv(sock.recvSize)
                if not fileInfo:
                    continue

                # check termination condition #
                name, size = fileInfo.decode().split("#", 1)
                if name == "@DONE":
                    return True
                elif not size:
                    continue

                # send ACK for file info #
                totalSize = long(size)
                sock.send("ACK".encode())
                break

            # set destination path #
            fname = os.path.basename(name)
            if des:
                if os.path.isdir(des):
                    target = os.path.join(des, fname)
                else:
                    target = des
            else:
                target = name

            # make dirs #
            dirPos = target.rfind("/")
            if dirPos >= 0 and not os.path.isdir(target[:dirPos]):
                os.makedirs(target[:dirPos])

            # convert path #
            target = os.path.realpath(os.path.expanduser(target))
            if os.path.isdir(target):
                target = os.path.join(target, fname)

            SysMgr.printInfo(
                "start downloading %s[%s]@%s:%s to %s..."
                % (name, UtilMgr.convSize2Unit(totalSize), ip, port, target),
                suffix=False,
            )

            # receive a file #
            with open(target, "wb") as fd:
                # change permission #
                os.chmod(target, 0o777)

                sent = 0
                while 1:
                    selectObj.select([sock.socket], [], [], 3)

                    # receive a chunk #
                    buf = sock.recv(sock.recvSize)
                    if not buf:
                        break

                    # update stat and write a chunk to file #
                    curSize += len(buf)
                    sent += len(buf)
                    fd.write(buf)

                    # check received size #
                    if curSize >= totalSize:
                        sock.send("ACK".encode())
                        break

                    # send ACK for a complete chunk #
                    if sent == sock.recvSize:
                        sock.send("ACK".encode())
                        sent = 0

                    # print progress #
                    UtilMgr.printProgress(curSize, totalSize)

            # remove progress #
            UtilMgr.deleteProgress()

            # check received size #
            if curSize < totalSize:
                raise Exception("broken connection")

            SysMgr.printInfo(
                "downloaded %s[%s]@%s:%s to %s successfully\n"
                % (target, UtilMgr.getFileSize(target), ip, port, name),
                suffix=False,
            )

            # send ACK #
            sock.send("ACK".encode())

        return True

    def customBind(self):
        # get bind info #
        ipList = portList = []
        if "CLIIP" in SysMgr.environList:
            ipList = SysMgr.environList["CLIIP"]
        if "CLIPORT" in SysMgr.environList:
            portList = SysMgr.environList["CLIPORT"]

        # check bind address #
        if not ipList and not portList:
            return True

        # set default IP #
        if not ipList:
            ipList = ["0"]

        # convert PORT list #
        if portList:
            newPortList = []
            for item in portList:
                if not "-" in item:
                    newPortList.append(long(item))
                    continue

                try:
                    start, end = item.split("-")
                    if end == "":
                        end = 65535
                    for idx in xrange(long(start), long(end) + 1):
                        newPortList.append(idx)
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr("failed to bind client socket", True)
                    return False

            portList = list(set(newPortList))
        else:
            portList = [0]

        # disable REUSEADDR flag #
        socket = SysMgr.getPkg("socket")
        self.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 0)

        # bind #
        isBound = False
        for ip in ipList:
            for port in portList:
                try:
                    self.bind(ip, port)
                    SysMgr.printWarn(
                        "succeed to bind client socket to %s:%s" % (ip, port)
                    )
                    isBound = True
                    break
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printWarn(
                        "failed to bind client socket to %s:%s" % (ip, port),
                        reason=True,
                    )

        # check result #
        if isBound:
            return True
        else:
            SysMgr.printErr("failed to bind local address for client socket")
            return False

    def connect(self, addr=None):
        if addr is None:
            addr = (self.ip, self.port)

        # bind to specific address #
        if not self.customBind():
            raise Exception("bind failure")

        self.socket.connect(addr)

        self.connected = True

    def handleServerRequest(self, req, onlySocket=False):
        def _onDownload(req):
            # parse path #
            reqList = req.split("|", 1)[1]
            path = UtilMgr.cleanItem(reqList.split("@"), False)
            if len(path) == 2:
                origPath, desPath = path
                if origPath and not desPath:
                    origPath = desPath
            else:
                origPath = path[0]
                desPath = None

            res = False

            # receive file #
            try:
                res = NetworkMgr.recvFile(
                    self, self.ip, self.port, origPath, desPath
                )
            except:
                res = False
                SysMgr.printErr(
                    "failed to download %s from %s in %s:%s"
                    % (origPath, desPath, self.ip, self.port),
                    True,
                )
            finally:
                try:
                    self.close()
                except:
                    pass
                finally:
                    return res

        def _onUpstream(req):
            pass

        def _onNotify(req):
            return True

        def _onUpload(req):
            # parse path #
            reqList = req.split("|", 1)[1]
            path = UtilMgr.cleanItem(reqList.split("@"), False)
            if len(path) == 2:
                origPath, targetPath = path
                if origPath and not targetPath:
                    origPath = targetPath
            else:
                origPath = targetPath = path[0]

            res = False

            # transfer file #
            try:
                res = NetworkMgr.sendFile(
                    self, self.ip, self.port, origPath, targetPath
                )
            except:
                res = False
                SysMgr.printErr(
                    "failed to upload %s to %s in %s:%s"
                    % (origPath, targetPath, self.ip, self.port),
                    True,
                )
            finally:
                try:
                    self.send("@DONE#0".encode())
                    self.close()
                except:
                    pass
                finally:
                    return res

        def _onList(req):
            SysMgr.printInfo(UtilMgr.lstrip(req, "LIST:"))
            return True

        def _onClear(req):
            SysMgr.printInfo(UtilMgr.lstrip(req, "CLEAR:"))
            return True

        def _onJobs(req):
            SysMgr.printInfo(UtilMgr.lstrip(req, "JOBS:"))
            return True

        def _onRun(req, onlySocket):
            # parse command #
            command = req.split("|", 1)[1]

            # parse addr #
            addr = "%s:%s" % (self.ip, self.port)

            if not onlySocket:
                SysMgr.printInfo("executed '%s' from %s\n" % (command, addr))

            # return just the connected socket #
            if onlySocket:
                return self

            # get select object #
            selectObj = SysMgr.getPkg("select")

            # set print flag #
            printFlag = SysMgr.getPrintFlag()

            if printFlag:
                print(oneLine)

            # run mainloop #
            isPrint = False
            while 1:
                try:
                    selectObj.select([self.socket], [], [])

                    # receive packet #
                    output = self.getData()
                    if not output:
                        break

                    if printFlag:
                        print(output[:-1])
                    isPrint = True
                except:
                    break

            # print output from server #
            if not isPrint:
                print("no response")

            if printFlag:
                print(oneLine)

            # close connection #
            try:
                self.close()
            except:
                pass

        # get select object to check reply #
        SysMgr.getPkg("select")

        # unmarshalling #
        if type(req) is tuple:
            try:
                req = req[0].decode()
            except:
                req = req[0]

            # check request #
            if not req:
                return

            # handle request #
            reqUpper = req.upper()

            if reqUpper.startswith("DOWNLOAD"):
                return _onDownload(req)

            elif reqUpper.startswith("UPLOAD"):
                return _onUpload(req)

            elif reqUpper.startswith("RUN"):
                return _onRun(req, onlySocket)

            elif reqUpper.startswith("LIST:"):
                return _onList(req)

            elif reqUpper.startswith("CLEAR"):
                return _onClear(req)

            elif reqUpper.startswith("JOBS"):
                return _onJobs(req)

            elif reqUpper.startswith("NOTIFY"):
                return _onNotify(req)

            elif reqUpper.startswith("ERROR"):
                err = req.split("|", 1)[1]
                errToken = err.find("':")
                errMsg = "%s' from %s" % (err[:errToken], err[errToken + 2 :])
                SysMgr.printErr(errMsg)

            else:
                SysMgr.printErr("failed to recognize '%s' request" % req)

        elif not req:
            SysMgr.printErr("no response from server")

        else:
            SysMgr.printErr("received wrong reply '%s'" % req)

    def send(self, message, write=False):
        if self.ip is None or self.port is None:
            SysMgr.printWarn(
                "failed to use IP address for client because it is not set"
            )
            return False
        elif not self.socket:
            SysMgr.printErr(
                "failed to use socket for client because it is not set"
            )
            return False

        # encode message #
        if UtilMgr.isString(message):
            message = UtilMgr.encodeStr(message)

        # convert list to bytes #
        if type(message) is list:
            if not message:
                message = "".encode()
            elif message[0][-1] == "\n":
                message = "".join(message).encode()
            else:
                message = "\n".join(message).encode()

        try:
            # send data #
            if self.tcp or self.netlink:
                ret = self.socket.send(message)
            elif not write and SysMgr.localServObj:
                ret = SysMgr.localServObj.socket.sendto(
                    message, (self.ip, self.port)
                )
            else:
                ret = self.socket.sendto(message, (self.ip, self.port))

            # check result #
            if ret < 0:
                raise Exception("send error")
            elif self.status != "ALWAYS":
                self.status = "SENT"
            return True
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to send data to %s:%d as server"
                % (self.ip, self.port),
                True,
            )
            return False

    def sendto(self, message, ip, port):
        if not ip or not port:
            SysMgr.printWarn(
                "failed to use IP address for client because it is not set"
            )
            return False
        elif not self.socket:
            SysMgr.printErr(
                "failed to use socket for client because it is not set"
            )
            return False

        # encode message #
        if UtilMgr.isString(message):
            message = UtilMgr.encodeStr(message)

        try:
            self.socket.sendto(message, (ip, port))
            return True
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to send data to %s:%d as client"
                % (self.ip, self.port),
                True,
            )
            return False

    def recv(self, size=0):
        if self.ip is None or self.port is None:
            SysMgr.printWarn(
                "failed to use IP address for server because it is not set"
            )
            return False
        elif not self.socket:
            SysMgr.printErr(
                "failed to use socket for client because it is not set"
            )
            return False

        # set recv size #
        if size == 0:
            size = self.recvSize

        try:
            return self.socket.recv(size)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn(
                "failed to receive data from %s:%d as client"
                % (self.ip, self.port),
                reason=True,
            )
            return False

    def getData(self, noTimeout=True):
        try:
            data = b""

            # receive and composite packets #
            while 1:
                output = self.recvfrom(noTimeout=noTimeout)

                # handle error #
                if not output:
                    continue

                # handle timeout #
                if not noTimeout and (not output[0] and not output[1]):
                    if data:
                        return data
                    else:
                        return None

                # get only data #
                output = output[0]

                # composite packets #
                data += output

                if not output:
                    break

                # decode data #
                try:
                    output = output.decode()
                except:
                    pass

                if len(output) < self.recvSize and output[-1] == "\n":
                    break
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to get data from %s:%d as client"
                % (self.ip, self.port),
                True,
            )
            return None

        # decode data #
        try:
            retstr = data.decode()
            return retstr
        except:
            return data

    def setNoDelay(self):
        from socket import socket, SOL_TCP, TCP_NODELAY

        # set NODELAY for NAGLE #
        self.socket.setsockopt(SOL_TCP, TCP_NODELAY, 1)

    def recvfrom(self, size=0, noTimeout=False, verb=True):
        if self.ip is None or self.port is None:
            SysMgr.printWarn(
                "failed to use IP address for server because it is not set"
            )
            return False
        elif not self.socket:
            SysMgr.printErr(
                "failed to use socket for client because it is not set"
            )
            return False

        # get socket object #
        socket = SysMgr.getPkg("socket", False)
        if not socket:
            return

        # set recv size #
        if size == 0:
            size = self.recvSize

        while 1:
            try:
                message, address = self.socket.recvfrom(size)
                return (message, address)
            except socket.timeout:
                if noTimeout:
                    continue

                SysMgr.printWarn(
                    (
                        "failed to receive data from %s:%d as client"
                        "because of %s"
                    )
                    % (self.ip, self.port, "timeout")
                )
                return None
            except KeyboardInterrupt:
                sys.exit(0)
            except SystemExit:
                sys.exit(0)
            except:
                if verb:
                    SysMgr.printWarn(
                        "failed to receive data from %s:%d as client"
                        % (self.ip, self.port),
                        reason=True,
                    )
                return None

    @staticmethod
    def getDataType(data):
        if not data:
            return "None"

        data = data.lstrip()

        if data.startswith("{"):
            return "JSON"
        elif (
            "[INFO" in data[:10]
            or "[ERROR" in data[:10]
            or "[WARN" in data[:10]
            or "[STEP" in data[:10]
        ):
            return "LOG"
        else:
            return "CONSOLE"

    @staticmethod
    def requestCmd(connObj, cmd):
        if not connObj:
            return

        # send request to server #
        connObj.send(cmd)

        # receive reply from server #
        reply = connObj.recvfrom()

        # handle reply from server #
        try:
            connObj.handleServerRequest(reply)
        except:
            return

    @staticmethod
    def requestPing(addr=None, verb=True, cmd=None):
        if cmd:
            cmd = cmd.upper()
            cmd = "%s:%s" % (cmd, cmd)
        else:
            cmd = "PING:PING"

        return NetworkMgr.execRemoteCmd(cmd, addr=addr, verb=verb)

    @staticmethod
    def getCmdPipe(connObj, cmd):
        if not cmd:
            return None

        # add command prefix #
        reqCmd = cmd.split(":", 1)[0].upper()
        if reqCmd in NetworkMgr.REQUEST_LIST:
            pass
        elif not cmd.startswith("run:"):
            cmd = "run:%s" % cmd

        # send request to server #
        connObj.send(cmd)

        # receive reply from server #
        reply = connObj.recvfrom()
        try:
            if not reply:
                raise Exception()

            msg = reply[0].decode()
            if not msg:
                pass
            elif msg == "PONG":
                return True
            elif msg == "NO_SERV_NODE":
                SysMgr.printErr(
                    "no service node to %s:%s" % (connObj.ip, connObj.port)
                )
                return True
            elif msg.startswith("MSG:"):
                # print message in the packet #
                SysMgr.printInfo(UtilMgr.lstrip(msg, "MSG:"))

                # send ACK to prevent receiving two packegs at once #
                connObj.send("ACK")

                # wait for a request again #
                reply = connObj.recvfrom()
            elif msg.startswith("LIST:"):
                reply = (msg,)
            elif msg.startswith("NOTIFY:"):
                return True
        except:
            pass

        # handle reply from server #
        try:
            return connObj.handleServerRequest(reply, onlySocket=True)
        except:
            return None

    @staticmethod
    def execRemoteCmd(command, addr=None, verb=True):
        # get new connection #
        connObj = NetworkMgr.getServerConn(addr, verb)
        if not connObj:
            return None

        # launch remote command #
        pipe = NetworkMgr.getCmdPipe(connObj, command)
        return pipe

    @staticmethod
    def getServerConn(addr=None, verb=True):
        def _printErr():
            SysMgr.printErr("no running server or wrong server address")

        # set server address in local #
        if addr:
            # classify IP and PORT #
            service, ip, port = NetworkMgr.parseAddr(addr)
            if service == ip == port == None:
                _printErr()
                return None
            else:
                NetworkMgr.setRemoteServer("%s:%s" % (ip, port), tcp=True)
        elif SysMgr.isLinux and not SysMgr.remoteServObj:
            try:
                addr = SysMgr.getProcNetAddrs(__module__)
            except:
                addr = None

            if not addr:
                return None

            # classify IP and PORT #
            service, ip, port = NetworkMgr.parseAddr(addr)
            if service == ip == port == None:
                _printErr()
                return None
            else:
                NetworkMgr.setRemoteServer(addr, tcp=True)
        # set server address again #
        elif SysMgr.remoteServObj:
            servObj = SysMgr.remoteServObj
            ip = servObj.ip
            port = servObj.port
            NetworkMgr.setRemoteServer("%s:%s" % (ip, port), tcp=True)

        # check server address #
        if not SysMgr.remoteServObj:
            _printErr()
            return None

        # bind local socket for UDP #
        try:
            if not SysMgr.remoteServObj.tcp and SysMgr.localServObj:
                lip = SysMgr.localServObj.ip
                lport = SysMgr.localServObj.port
                SysMgr.remoteServObj.socket.bind((lip, lport))
        except:
            SysMgr.printErr(
                "failed to bind socket to %s:%s for connection" % (lip, lport),
                True,
            )

        # do connect to server #
        try:
            connObj = SysMgr.remoteServObj

            if not "NOTIMEOUT" in SysMgr.environList:
                connObj.timeout()

            # set immediately exit flag to prevent hang on connect #
            origFlag = SysMgr.exitFlag
            SysMgr.exitFlag = True

            # connect with handling CLOSE_WAIT #
            while 1:
                try:
                    connObj.connect()
                    break
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printWarn(
                        "failed to connect to %s:%s" % (ip, port),
                        reason=True,
                        always=verb,
                    )

                    # handle error #
                    _, err, to = sys.exc_info()
                    if err.args and err.args[0] == 99:
                        time.sleep(0.1)
                        continue
                    else:
                        raise Exception(err.args[0])
                finally:
                    SysMgr.exitFlag = origFlag

            return connObj
        except SystemExit:
            sys.exit(0)
        except:
            if verb:
                SysMgr.printErr("failed to set socket for connection", True)
            return None

    @staticmethod
    def parseAddr(value):
        service = None
        ip = None
        port = None

        if not UtilMgr.isString(value):
            return (service, ip, port)

        # get request and address #
        cmdList = value.split("@")
        if len(cmdList) >= 2:
            service = cmdList[0]
            addr = cmdList[1]
        else:
            addr = value

        # get IP and PORT #
        addrList = addr.split(":")
        if len(addrList) >= 2:
            try:
                if addrList[0]:
                    ip = addrList[0]
                if addrList[1]:
                    port = long(addrList[1])
            except:
                pass
        else:
            try:
                if "." in addrList[0]:
                    ip = addrList[0]
                else:
                    port = long(addrList[0])
            except:
                pass

        return (service, ip, port)

    @staticmethod
    def setRemoteServer(value, tcp=False, verb=True):
        # receive mode #
        if not value:
            SysMgr.remoteServObj = "NONE"
            return

        # request mode #
        service, ip, port = NetworkMgr.parseAddr(value)

        # set PRINT as default #
        if not service:
            service = "PRINT"

        if not ip:
            ip = NetworkMgr.getPublicIp()

        if port is None:
            port = SysMgr.defaultServPort

        # check server addresses #
        if (
            SysMgr.localServObj
            and SysMgr.localServObj.ip == ip
            and SysMgr.localServObj.port == port
        ):
            SysMgr.printErr(
                (
                    "wrong value for remote connection, "
                    "local address and remote address are same "
                    "(%s:%s)"
                )
                % (ip, port)
            )
            sys.exit(-1)

        # check request #
        if not ip or not port or not SysMgr.isValidRequest(service):
            reqList = ""
            for req in TaskAnalyzer.requestType:
                reqList += req + "|"

            SysMgr.printErr(
                (
                    "wrong input address, "
                    "input [%s]@IP:PORT as remote address"
                )
                % reqList[:-1]
            )
            sys.exit(-1)

        # create a socket #
        networkObject = NetworkMgr("client", ip, port, tcp=tcp)
        if not networkObject.ip:
            sys.exit(-1)
        else:
            networkObject.request = service
            SysMgr.remoteServObj = networkObject

        # set protocol #
        if tcp:
            proto = "TCP"
        else:
            proto = "UDP"

        if verb:
            SysMgr.printInfo(
                "use %s:%d(%s) as remote address" % (ip, port, proto)
            )

        return SysMgr.remoteServObj

    @staticmethod
    def setRemoteNetwork(service, ip, port):
        # set default service #
        if not service:
            service = "PRINT"

        errMsg = (
            "wrong value for remote server, "
            "input in the format [%s]@IP:PORT"
        ) % "|".join(TaskAnalyzer.requestType)

        if not ip or not SysMgr.isValidRequest(service):
            SysMgr.printErr(errMsg)
            sys.exit(-1)

        if port is None:
            port = SysMgr.defaultServPort

        # create a new object #
        netObj = NetworkMgr("client", ip, port)
        if not netObj.ip:
            sys.exit(-1)
        else:
            netObj.status = "ALWAYS"
            netObj.request = service
            naddr = "%s:%s" % (ip, str(port))

            if service == "PRINT":
                SysMgr.addrListForPrint[naddr] = netObj
            elif service.startswith("REPORT_"):
                SysMgr.reportEnable = True
                SysMgr.addrListForReport[naddr] = netObj
            else:
                SysMgr.printErr(errMsg)

        SysMgr.printInfo(
            "use %s:%d as remote address to request %s" % (ip, port, service)
        )

    @staticmethod
    def setServerNetwork(
        ip,
        port,
        force=False,
        blocking=False,
        tcp=False,
        anyPort=False,
        reuse=True,
        weakPort=False,
        verb=False,
    ):

        if SysMgr.localServObj and not force:
            SysMgr.printWarn(
                "ignored to set server network because its already set", verb
            )
            return

        # get internet available IP first #
        if not ip:
            ip = NetworkMgr.getPublicIp()

        # set default port #
        if port is None:
            if SysMgr.checkMode("cli"):
                port = SysMgr.defaultCliPort
            else:
                port = SysMgr.defaultServPort

        # print available IP list #
        try:
            iplist = sorted(NetworkMgr.getUsingIps())
            if iplist:
                SysMgr.printWarn(
                    "available IP list [ %s ]" % ", ".join(iplist), verb
                )
        except:
            pass

        # check server setting #
        localObj = SysMgr.localServObj
        if (
            localObj
            and localObj.socket
            and localObj.ip == ip
            and localObj.port == port
        ):
            if blocking:
                localObj.socket.setblocking(1)
            else:
                localObj.socket.setblocking(0)
            return

        # create a new server setting #
        networkObject = NetworkMgr(
            "server", ip, port, blocking, tcp, anyPort, reuse=reuse
        )
        if not networkObject.ip and weakPort:
            networkObject = NetworkMgr(
                "server", ip, port, blocking, tcp, True, reuse=reuse
            )
        if not networkObject.ip:
            SysMgr.printWarn("failed to set server IP", verb)
            return

        # set protocol #
        if tcp:
            proto = "TCP"
        else:
            proto = "UDP"

        localObj = SysMgr.localServObj = networkObject

        if not SysMgr.masterPid:
            SysMgr.printInfo(
                "use %s:%d(%s) as local address"
                % (localObj.ip, localObj.port, proto)
            )

        return networkObject

    @staticmethod
    def prepareServerConn(cliAddr, servAddr):
        # set local address #
        if not cliAddr:
            NetworkMgr.setServerNetwork(None, None, anyPort=True)
        else:
            service, ip, port = NetworkMgr.parseAddr(cliAddr)

            NetworkMgr.setServerNetwork(ip, port)

        # set remote address #
        if servAddr:
            NetworkMgr.setRemoteServer(servAddr)

        # set client address #
        if SysMgr.localServObj:
            cliIp = SysMgr.localServObj.ip
            cliPort = SysMgr.localServObj.port
        else:
            cliIp = None
            cliPort = None

        # set server address #
        if SysMgr.remoteServObj.ip:
            servIp = SysMgr.remoteServObj.ip
            servPort = SysMgr.remoteServObj.port
        else:
            servIp = None
            servPort = None

        return (cliIp, cliPort), (servIp, servPort)

    @staticmethod
    def getDevByIp(ip):
        # get device data #
        data = SysMgr.getNetDevData()
        if not data:
            return

        # create a new socket #
        try:
            fcntl = SysMgr.getPkg("fcntl", False)
            socket = SysMgr.getPkg("socket", False)
            sobj = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        except SystemExit:
            sys.exit(0)
        except:
            return

        # scan IP device and address #
        for line in data:
            try:
                dev, stats = line.split(":")

                dev = dev.strip()

                res = fcntl.ioctl(
                    sobj.fileno(),
                    0x8915,  # SIOCGIFADDR
                    struct.pack("256s", dev[:15].encode("utf-8")),
                )

                ipaddr = socket.inet_ntoa(res[20:24])
                if ipaddr == ip:
                    return dev
            except SystemExit:
                sys.exit(0)
            except:
                pass

    @staticmethod
    def getMainMacAddr():
        dirPath = "/sys/class/net"

        try:
            devices = os.listdir(dirPath)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenErr(dirPath)
            return

        # return main IP and device #
        try:
            ip = NetworkMgr.getPublicIp()
            if ip:
                dev = NetworkMgr.getDevByIp(ip)
                if dev:
                    return (dev, ip)
        except SystemExit:
            sys.exit(0)
        except:
            pass

        for dev in devices:
            # skip virtual device #
            if dev == "lo" or dev.startswith("docker"):
                continue

            target = "%s/%s/address" % (dirPath, dev)
            try:
                with open(target, "r") as fd:
                    addr = fd.readline()[:-1]
                    return (dev, addr)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenErr(target)

        return ("None", "None")

    @staticmethod
    def getUsingIps():
        if not SysMgr.isLinux:
            return

        connPaths = [
            "%s/net/udp" % SysMgr.procPath,
            "%s/net/tcp" % SysMgr.procPath,
        ]

        effectiveList = {}
        cacheList = {}

        for path in connPaths:
            try:
                with open(path, "r") as fd:
                    ipList = fd.read().split("\n")

                # remove title #
                ipList.pop(0)

                for line in ipList:
                    if not line:
                        continue
                    items = line.split(None, 2)
                    addr = items[1].split(":")[0]
                    if addr in cacheList:
                        continue

                    cacheList[addr] = None
                    ip = SysMgr.convCIDR(addr)
                    effectiveList[ip] = None
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenWarn(path)

        return list(effectiveList)

    @staticmethod
    def getGateways():
        gateways = {}

        ips = NetworkMgr.getRoutedIps()

        for item in ips:
            try:
                ip = item[1]
                if (
                    ip == "0.0.0.0"
                    or ip == "127.0.0.1"
                    or not ip.endswith(".1")
                ):
                    continue

                gw = "%s.1" % ip[: ip.rfind(".")]
                gateways[gw] = None
            except SystemExit:
                sys.exit(0)
            except:
                pass

        return list(gateways)

    @staticmethod
    def getMainIp():
        ipList = NetworkMgr.getUsingIps()

        # remove IP for all IPv4 addresses #
        try:
            ipList.remove("0.0.0.0")
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # return main IP #
        if not ipList:
            return None
        elif "127.0.0.1" in ipList:
            return "127.0.0.1"
        else:
            return list(sorted(ipList, reverse=True))[0]

    @staticmethod
    def getRoutedIps():
        effectiveList = []
        routePath = "%s/net/route" % SysMgr.procPath
        try:
            with open(routePath, "r") as fd:
                ipList = fd.readlines()

            # remove title #
            ipList.pop(0)

            for line in ipList:
                items = line.split()
                effectiveList.append([items[0], SysMgr.convCIDR(items[1])])

            return effectiveList
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenWarn(routePath)
            return effectiveList

    @staticmethod
    def getHostName():
        try:
            return SysMgr.getPkg("socket").gethostname()
        except:
            return None

    @staticmethod
    def getPublicIp(force=False):
        if SysMgr.ipAddr and not force:
            return SysMgr.ipAddr

        # get socket object #
        socket = SysMgr.getPkg("socket", False)
        if not socket:
            return

        from socket import socket, AF_INET, SOCK_DGRAM, SOCK_STREAM

        ret = None

        try:
            s = socket(AF_INET, SOCK_STREAM)
            s.settimeout(0.3)

            # connect to google public IP #
            s.connect(("8.8.8.8", 53))

            ret = s.getsockname()[0]
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("failed to get public IP address")

        if not ret:
            ret = NetworkMgr.getMainIp()

        SysMgr.ipAddr = ret

        return ret

    def __del__(self):
        try:
            self.close()
        except:
            pass


class Timeline(object):
    """SVG viewer for timeline segments"""

    class Segment(object):
        def __init__(self, group, time_start, time_end, extra):
            self.group = group
            self.time_start = time_start
            self.time_end = time_end
            self.text = None
            self.id = None
            self.color = None
            self.state = None
            self.info = None
            self._init_extra(extra)

        def _init_extra(self, extra):
            if "text" in extra:
                self.text = extra["text"]

            if "id" in extra:
                self.id = extra["id"]

            if "color" in extra:
                self.color = extra["color"]

            if "state" in extra:
                self.state = extra["state"]

            if "info" in extra:
                self.info = extra["info"]

    class Config(object):
        def _conv_palette(self, palette):
            plist = []
            for palette_entry in palette:
                rgb = [
                    int(rgb_value)
                    for rgb_value in re.findall("\d+", palette_entry)
                ]
                color = "rgb%s" % palette_entry
                plist.append(color)
            return plist

        def __init__(self):
            self.WIDTH = 1500
            self.HEIGHT = 770
            self.TIME_AXIS_HEIGHT = 1
            self.TICKS = 100

            # set item filter #
            if "FILTER" in SysMgr.environList:
                self.FILTER = SysMgr.environList["FILTER"]
                SysMgr.printInfo(
                    "only specific items [ %s ] are drawn"
                    % ", ".join(self.FILTER)
                )
            else:
                self.FILTER = []

            # set label filter #
            if "LABELMIN" in SysMgr.environList:
                self.LABEL_SIZE_MIN = UtilMgr.getEnvironNum(
                    "LABELMIN", isInt=True
                )
                SysMgr.printInfo(
                    "only time segments bigger than %s are printed"
                    % UtilMgr.convNum(self.LABEL_SIZE_MIN)
                )
            else:
                self.LABEL_SIZE_MIN = 0

            # set font size #
            if "FONTSIZE" in SysMgr.environList:
                self.FONT_SIZE = UtilMgr.getEnvironNum("FONTSIZE", isInt=True)
            else:
                self.FONT_SIZE = 3

            # set group font size #
            if "GROUPFONTSIZE" in SysMgr.environList:
                self.GROUP_FONT_SIZE = UtilMgr.getEnvironNum(
                    "GROUPFONTSIZE", isInt=True
                )
            else:
                self.GROUP_FONT_SIZE = 0

            palette = [
                "(0,150,136)",
                "(0,188,212)",
                "(0,0,128)",
                "(0,0,139)",
                "(0,0,205)",
                "(0,0,255)",
                "(0,100,0)",
                "(0,128,0)",
                "(0,128,128)",
                "(0,139,139)",
                "(0,191,255)",
                "(0,206,209)",
                "(0,250,154)",
                "(0,255,0)",
                "(0,255,127)",
                "(0,255,255)",
                "(100,149,237)",
                "(102,205,170)",
                "(103,58,183)",
                "(106,90,205)",
                "(107,142,35)",
                "(121,85,72)",
                "(123,104,238)",
                "(124,252,0)",
                "(127,255,0)",
                "(127,255,212)",
                "(128,0,0)",
                "(128,0,128)",
                "(128,128,0)",
                "(128,128,128)",
                "(135,206,235)",
                "(135,206,250)",
                "(138,43,226)",
                "(139,195,74)",
                "(139,0,0)",
                "(139,0,139)",
                "(139,69,19)",
                "(143,188,143)",
                "(144,238,144)",
                "(147,112,219)",
                "(148,0,211)",
                "(152,251,152)",
                "(153,50,204)",
                "(154,205,50)",
                "(156,39,176)",
                "(158,158,158)",
                "(160,82,45)",
                "(165,42,42)",
                "(173,216,230)",
                "(173,255,47)",
                "(175,238,238)",
                "(176,224,230)",
                "(178,34,34)",
                "(184,134,11)",
                "(186,85,211)",
                "(188,143,143)",
                "(189,183,107)",
                "(192,192,192)",
                "(199,21,133)",
                "(205,133,63)",
                "(205,220,57)",
                "(205,92,92)",
                "(210,105,30)",
                "(210,180,140)",
                "(216,191,216)",
                "(218,112,214)",
                "(218,165,32)",
                "(219,112,147)",
                "(220,20,60)",
                "(221,160,221)",
                "(222,184,135)",
                "(224,255,255)",
                "(233,150,122)",
                "(233,30,99)",
                "(238,130,238)",
                "(238,232,170)",
                "(240,128,128)",
                "(240,230,140)",
                "(244,67,54)",
                "(244,164,96)",
                "(245,222,179)",
                "(245,245,220)",
                "(25,25,112)",
                "(250,128,114)",
                "(250,235,215)",
                "(250,250,210)",
                "(255,0,0)",
                "(255,0,255)",
                "(255,105,180)",
                "(255,127,80)",
                "(255,140,0)",
                "(255,152,0)",
                "(255,160,122)",
                "(255,165,0)",
                "(255,182,193)",
                "(255,192,203)",
                "(255,193,7)",
                "(255,20,147)",
                "(255,215,0)",
                "(255,228,196)",
                "(255,235,205)",
                "(255,235,59)",
                "(255,248,220)",
                "(255,250,205)",
                "(255,255,0)",
                "(255,255,224)",
                "(255,69,0)",
                "(255,87,34)",
                "(255,99,71)",
                "(3,169,244)",
                "(30,144,255)",
                "(32,178,170)",
                "(33,150,243)",
                "(34,139,34)",
                "(46,139,87)",
                "(47,79,79)",
                "(50,205,50)",
                "(60,179,113)",
                "(63,81,181)",
                "(64,224,208)",
                "(65,105,225)",
                "(70,130,180)",
                "(72,209,204)",
                "(72,61,139)",
                "(75,0,130)",
                "(76,175,80)",
                "(85,107,47)",
                "(95,158,160)",
                "(96,125,139)",
            ]

            self.PALETTE = self._conv_palette(palette)

            # shuffle list #
            random = SysMgr.getPkg("random", False)
            if random:
                random.shuffle(self.PALETTE)

        @staticmethod
        def _load(fileName=None, data=None):
            if fileName:
                with open(fileName) as fd:
                    data = fd.read()
                    data = UtilMgr.convStr2Dict(data)
            elif not data:
                SysMgr.printErr("no path or data for timeline config")
                sys.exit(-1)

            config = Timeline.Config()
            config.WIDTH = data.get("width", 20000)
            config.HEIGHT = data.get("height", 4000)
            config.FONT_SIZE = data.get("font_size", 3)
            config.TICKS = data.get("time_ticks", 5)
            config.TIME_AXIS_HEIGHT = data.get("time_axis_height", 5)
            config.PALETTE = config._conv_palette(data.get("palette", []))
            config.TIMEUNIT = data.get("time_unit", None)
            config.TIMEFACTOR = data.get("time_factor", 1)
            if config.LABEL_SIZE_MIN == 0:
                config.LABEL_SIZE_MIN = data.get("label_size_min", 5)

            return config

    def __init__(self, title, segments, time_unit, fontsize, config, tasks=[]):

        self.title = title
        self.segments = segments
        self.time_unit = time_unit
        self.config = config

        self.time_start = min(
            segments, key=lambda segment: segment.time_start
        ).time_start
        self.time_end = max(
            segments, key=lambda segment: segment.time_end
        ).time_end
        self.segment_groups = sorted(
            list(map(long, set(s.group for s in self.segments)))
        )
        self.segment_groups = list(map(str, self.segment_groups))
        self.groups = len(self.segment_groups)
        self.scaled_height = self.config.HEIGHT / self.groups
        self.group_list = list(self.segment_groups)
        self.group_stat = [
            {
                "cnt": 0,
                "du_min": 0,
                "du_max": 0,
                "du_list": [],
                "inter_min": 0,
                "inter_max": 0,
                "inter_list": [],
                "prev": 0,
            }
            for _ in xrange(len(self.group_list))
        ]

        try:
            self.ratio = self.config.WIDTH / float(
                self.time_end - self.time_start
            )
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to recognize timeline because start and end are same"
            )
            sys.exit(-1)

        self.last_group_segment = {}
        self.last_group_time = {}
        self.height_group_pos = {}
        self.last_iogroup_segment = {}
        self.last_iogroup_time = {}
        self.height_iogroup_pos = {}

        # apply task converter #
        try:
            self.tasks = {}
            if tasks:
                for task in tasks:
                    if task in Timeline.conv_table:
                        new = Timeline.conv_table[task]
                        self.tasks[new] = tasks[task]
                    elif type(tasks) is dict:
                        self.tasks[task] = tasks[task]
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to change tasks in timeline", True)
            sys.exit(-1)

        # time factor #
        if hasattr(self.config, "TIMEFACTOR"):
            self.time_factor = self.config.TIMEFACTOR
        else:
            self.time_factor = 1

        # task color #
        if self.tasks:
            self.color_map = self._build_task_color_map()
        else:
            self.color_map = self._build_color_map()

        # update font size #
        if fontsize and self.config:
            self.config.FONT_SIZE = fontsize

    def _build_task_color_map(self):
        color_map = {}
        palette = self.config.PALETTE
        for i, group in enumerate(self.tasks):
            color_map[group] = palette[i % len(palette)]
        return color_map

    def _build_color_map(self):
        color_map = {}
        palette = self.config.PALETTE
        segment_groups = self.segment_groups
        for i, group in enumerate(segment_groups):
            color_map[group] = palette[i % len(palette)]
        return color_map

    def _draw_grid(self, dwg):
        for x in xrange(0, self.config.WIDTH, self.config.TICKS):
            dwg.add(
                dwg.line(
                    (x, 0),
                    (x, self.config.HEIGHT),
                    stroke="black",
                    stroke_width=0.1,
                )
            )

    def _draw_group_stat(self, dwg):
        # set group font size #
        if self.config.GROUP_FONT_SIZE > 0:
            fontsize = self.config.GROUP_FONT_SIZE
        else:
            fontsize = self.scaled_height / 4

        idx = 0
        convNum = UtilMgr.convNum
        for y_tick in xrange(self.config.HEIGHT):
            try:
                stats = self.group_stat[idx]
                idx += 1

                # count #
                count = stats["cnt"]
                if count == 0:
                    continue

                # build string #
                statstr = "Cnt: %s" % convNum(count)

                # interval #
                if count > 1:
                    try:
                        inter = stats["inter_list"]
                        inter_avg = long(sum(inter) / (len(inter)))
                    except SystemExit:
                        sys.exit(0)
                    except:
                        inter_avg = 0
                    inter_std = UtilMgr.getStdev(inter)

                    statstr += (
                        ", IntMin: %s, IntMax: %s, IntAvg: %s, IntStd: %s"
                        % (
                            convNum(stats["inter_min"]),
                            convNum(stats["inter_max"]),
                            convNum(inter_avg),
                            convNum(inter_std),
                        )
                    )

                # duration #
                if stats["du_min"] > 0:
                    try:
                        du = stats["du_list"]
                        du_avg = long(sum(du) / (len(du)))
                    except SystemExit:
                        sys.exit(0)
                    except:
                        du_avg = 0
                    du_std = UtilMgr.getStdev(du)

                    statstr += (
                        ", DuMin: %s, DuMax: %s, DuAvg: %s, DuStd: %s"
                        % (
                            convNum(stats["du_min"]),
                            convNum(stats["du_max"]),
                            convNum(du_avg),
                            convNum(du_std),
                        )
                    )
            except SystemExit:
                sys.exit(0)
            except:
                continue

            y_tick *= self.scaled_height
            dwg.add(
                dwg.text(
                    statstr,
                    (2, y_tick + self.scaled_height / 2),
                    font_size=fontsize / 2,
                    fill="rgb(200,200,200)",
                )
            )

    def _draw_group_axis(self, dwg, yval):
        dwg.add(
            dwg.rect(
                (0, 0),
                (self.config.TIME_AXIS_HEIGHT, self.config.HEIGHT),
                fill="black",
            )
        )

        # set group font size #
        if self.config.GROUP_FONT_SIZE > 0:
            fontsize = self.config.GROUP_FONT_SIZE
        else:
            fontsize = self.scaled_height / 2

        idx = 0
        groupList = list(self.segment_groups)
        for y_tick in xrange(self.config.HEIGHT):
            try:
                name = groupList[idx]
                idx += 1
            except:
                continue

            y_tick *= self.scaled_height

            dwg.add(
                dwg.line(
                    (0, y_tick),
                    (self.config.WIDTH, y_tick),
                    stroke="black",
                    stroke_width=2,
                )
            )

            dwg.add(
                dwg.text(
                    name,
                    (2, y_tick + self.scaled_height),
                    font_size=fontsize,
                    fill="rgb(200,200,200)",
                )
            )

            # add info #
            addinfo = yval[name] if yval and name in yval else ""
            name = str(name)
            if not addinfo and self.tasks and name in self.tasks:
                addinfo = self.tasks[name]
            if addinfo:
                x = 2 * self.scaled_height * len(name) / 5
                dwg.add(
                    dwg.text(
                        addinfo,
                        (x, y_tick + self.scaled_height),
                        font_size=fontsize / 2,
                        fill="rgb(200,200,200)",
                    )
                )

    def _draw_time_axis(self, dwg, start=0, annotation=None):
        dwg.add(
            dwg.rect(
                (0, self.config.HEIGHT),
                (self.config.WIDTH, self.config.TIME_AXIS_HEIGHT),
                fill="black",
            )
        )

        y_time_tick = self.config.HEIGHT + self.config.TIME_AXIS_HEIGHT / 2
        ratio = 1 / self.ratio

        # set time delta #
        start = float(start) / self.time_factor

        # create the drawing group #
        g = dwg.add(dwg.g())
        if annotation:
            g.set_desc(annotation)

        for x_tick_time in xrange(0, self.config.WIDTH, self.config.TICKS):
            abs_x_tick_time = (x_tick_time * ratio) + start
            tick_time = "{:10}".format(long(abs_x_tick_time))
            g.add(
                dwg.text(
                    "%s %s" % (UtilMgr.convNum(tick_time), self.time_unit),
                    (x_tick_time, y_time_tick + self.config.FONT_SIZE * 5),
                    font_size=self.config.FONT_SIZE * 5,
                    color="rgb(255,255,255)",
                )
            )

    def _draw_background(self, dwg):
        dwg.add(
            dwg.rect(
                (0, 0),
                (self.config.WIDTH, self.config.HEIGHT),
                fill="rgb(245,245,245)",
            )
        )

        # set title #
        if self.title:
            title = self.title
        else:
            title = "Guider Timeline"

        # set font size for title #
        fontsize = self.config.FONT_SIZE * 10

        dwg.add(
            dwg.text(
                title,
                (
                    (self.config.WIDTH / 2) - (len(title) * fontsize / 4),
                    fontsize,
                ),
                font_size=fontsize,
                font_weight="bolder",
                fill="rgb(200,200,200)",
            )
        )

    def _draw_segments(self, dwg, start=0):
        # set time delta #
        start = float(start) / self.time_factor

        for idx, segment in enumerate(
            sorted(self.segments, key=lambda e: len(e.state))
        ):
            UtilMgr.printProgress(idx, len(self.segments))
            self._draw_segment(segment, dwg, start)

        if self.segments:
            UtilMgr.deleteProgress()

    def _draw_segment(self, segment, dwg, start=0):
        x0 = float(segment.time_start - self.time_start) * self.ratio
        x1 = float(segment.time_end - self.time_start) * self.ratio
        group_idx = self.group_list.index(segment.group)
        y0 = self.scaled_height * float(group_idx % self.groups)
        y1 = self.scaled_height * float((group_idx % self.groups) + 1)
        scaled_width = x1 - x0
        scaled_top_height = y0 + (self.scaled_height / 7)
        scaled_bottom_height = y1 - (self.scaled_height * 0.25)
        duration = segment.time_end - segment.time_start
        time_end = segment.time_end + start - self.time_start
        strokeSize = 3.5

        # check filter #
        if self.config.FILTER and not UtilMgr.isValidStr(
            segment.text, self.config.FILTER
        ):
            return

        # get color ID #
        if segment.color:
            color = segment.color
        else:
            if segment.id:
                colorid = segment.id
            else:
                colorid = group_idx

            # get real color via ID #
            try:
                color = self.color_map[str(colorid)]
            except SystemExit:
                sys.exit(0)
            except:
                try:
                    cidx = long(colorid) % len(self.color_map)
                    color = self.color_map[list(self.color_map)[cidx]]
                    self.color_map[str(colorid)] = color
                except SystemExit:
                    sys.exit(0)
                except:
                    color = self.color_map[list(self.color_map)[0]]

        # check stroke option #
        if self.stroke_text and UtilMgr.isValidStr(
            segment.text, self.stroke_text
        ):
            stroke = "rgb(255,0,0)"
            stroke_width = 1
        else:
            stroke = "none"
            stroke_width = 0

        # update count stat #
        stats = self.group_stat[group_idx]
        stats["cnt"] += 1

        # update interval stats #
        if stats["prev"] > 0:
            interval = segment.time_start - stats["prev"]
        else:
            interval = 0
        stats["prev"] = segment.time_start
        if stats["inter_min"] == 0 or stats["inter_min"] > interval:
            stats["inter_min"] = interval
        if stats["inter_max"] == 0 or stats["inter_max"] < interval:
            stats["inter_max"] = interval
        stats["inter_list"].append(interval)

        # apply stroke by interval #
        if self.stroke_interval > 0 and self.stroke_interval <= interval:
            stroke = "rgb(255,0,0)"
            stroke_width = 1

        # update duration stats #
        if stats["du_min"] == 0 or stats["du_min"] > duration:
            stats["du_min"] = duration
        if stats["du_max"] == 0 or stats["du_max"] < duration:
            stats["du_max"] = duration
        stats["du_list"].append(duration)

        # apply stroke by duration #
        if self.stroke_duration > 0 and self.stroke_duration <= duration:
            stroke = "rgb(255,0,0)"
            stroke_width = 1

        # draw bold line for core off #
        if segment.state == "OFF":
            dwg.add(
                dwg.line(
                    (x0, y0), (x1, y0), stroke="gray", stroke_width=strokeSize
                )
            )
            return

        # draw circle and text for event #
        if segment.state and segment.state.startswith("EVENT"):
            if segment.state == "EVENT_MARK":
                font_size = self.config.FONT_SIZE
            elif segment.state == "EVENT_USER":
                font_size = self.config.FONT_SIZE * 3
            else:
                font_size = self.config.FONT_SIZE

            dwg.add(
                dwg.circle(
                    center=(x0, y0),
                    r=font_size / 2,
                    stroke="darkgreen",
                    fill="darkgreen",
                )
            )

            # draw text #
            dwg.add(
                dwg.text(
                    segment.text,
                    (x0 + font_size, y0),
                    fill="darkgreen",
                    stroke="none",
                    font_size=font_size,
                    font_weight="bolder",
                )
            )

            return

        # define shortcut and duration string #
        convNum = UtilMgr.convNum
        durationstr = convNum(duration)

        if hasattr(segment, "info") and segment.info:
            info = "\n%s" % segment.info
        else:
            info = ""

        # create the drawing group #
        g = dwg.add(dwg.g())
        g.set_desc(
            "%s %s / ~%s (%s)%s"
            % (
                segment.text,
                durationstr,
                convNum(time_end),
                self.time_unit,
                info,
            )
        )

        # draw line for block_read status #
        if segment.state == "RD":
            g.add(
                dwg.rect(
                    (x0, scaled_bottom_height),
                    (scaled_width, self.scaled_height * 0.25),
                    rx=1,
                    ry=1,
                    fill="purple",
                    fill_opacity=0.5,
                    stroke=stroke,
                    stroke_width=stroke_width,
                )
            )
        # draw line for block_write status #
        elif segment.state == "WR":
            g.add(
                dwg.rect(
                    (x0, scaled_bottom_height),
                    (scaled_width, self.scaled_height * 0.25),
                    rx=1,
                    ry=1,
                    fill="darkcyan",
                    fill_opacity=0.5,
                    stroke=stroke,
                    stroke_width=stroke_width,
                )
            )
        # draw line for syscall status #
        elif segment.state == "SYSCALL":
            g.add(
                dwg.rect(
                    (x0, y0),
                    (scaled_width, self.scaled_height * 0.5),
                    rx=1,
                    ry=1,
                    fill=color,
                    fill_opacity=0.5,
                    stroke=stroke,
                    stroke_width=stroke_width,
                )
            )
        # draw line for sched status #
        else:
            # draw CPU timeslice #
            g.add(
                dwg.rect(
                    (x0, y0),
                    (scaled_width, self.scaled_height),
                    rx=1,
                    ry=1,
                    fill=color,
                    fill_opacity=0.5,
                    stroke=stroke,
                    stroke_width=stroke_width,
                )
            )

            # draw preempted status #
            if segment.state == "R":
                g.add(
                    dwg.line(
                        (x1, y0),
                        (x1, scaled_top_height),
                        stroke="red",
                        stroke_width=strokeSize,
                    )
                )
            # draw wait status #
            elif segment.state == "D":
                g.add(
                    dwg.line(
                        (x1, y0),
                        (x1, scaled_top_height),
                        stroke="black",
                        stroke_width=strokeSize,
                    )
                )

        # check label flag #
        if (
            not SysMgr.showAll
            and not "LABEL" in SysMgr.environList
            and not "LABELMIN" in SysMgr.environList
        ):
            return
        # check duration #
        elif not duration or duration < self.config.LABEL_SIZE_MIN:
            return

        # convert duration to text #
        duration = "~%s" % convNum(durationstr)

        # I/O #
        if segment.state == "RD" or segment.state == "WR":
            # initialize group data #
            self.last_iogroup_segment.setdefault(group_idx, None)
            self.last_iogroup_time.setdefault(group_idx, x0)

            # define data #
            last_iogroup_segment = self.last_iogroup_segment[group_idx]
            last_iogroup_time = self.last_iogroup_time[group_idx]

            # set text attributes for block_read #
            if segment.state == "RD":
                if (
                    last_iogroup_segment == segment.text
                    and x0 - last_iogroup_time < self.config.TICKS
                ):
                    segment_label = durationstr
                    font_size = self.config.FONT_SIZE - 1
                else:
                    segment_label = "[R] %s %s" % (segment.text, durationstr)
                    font_size = self.config.FONT_SIZE - 0.7
                color = "rgb(128,0,128)"
            # set text attributes for block_write #
            elif segment.state == "WR":
                if (
                    last_iogroup_segment == segment.text
                    and x0 - last_iogroup_time < self.config.TICKS
                ):
                    segment_label = durationstr
                    font_size = self.config.FONT_SIZE - 1
                else:
                    segment_label = "[W] %s %s" % (segment.text, durationstr)
                    font_size = self.config.FONT_SIZE - 0.7
                color = "rgb(0,139,139)"

            # update group info #
            self.last_iogroup_segment[group_idx] = segment.text
            self.last_iogroup_time[group_idx] = x0
            self.height_iogroup_pos.setdefault(group_idx, 0)

            # set text position #
            scaled_pos = self.scaled_height * 0.75
            self.height_iogroup_pos[group_idx] += self.config.FONT_SIZE
            height_pos = self.height_iogroup_pos[group_idx]
            if height_pos + scaled_pos >= self.scaled_height:
                height_pos = self.height_iogroup_pos[
                    group_idx
                ] = self.config.FONT_SIZE
        # CPU & SYSCALL #
        else:
            # SYSCALL #
            if segment.state == "SYSCALL":
                prefix = "[S] "
            else:
                prefix = ""

            # initialize group data #
            self.last_group_segment.setdefault(group_idx, None)
            self.last_group_time.setdefault(group_idx, x0)

            # set text attributes for same task #
            if (
                self.last_group_segment[group_idx] == segment.text
                and x0 - self.last_group_time[group_idx] < self.config.TICKS
            ):
                segment_label = durationstr
                color = "rgb(50,50,50)"
                font_size = self.config.FONT_SIZE - 1
            # set text attributes for new task #
            else:
                segment_label = "%s%s %s" % (prefix, segment.text, durationstr)
                color = "rgb(255,0,0)"
                font_size = self.config.FONT_SIZE - 0.5

            # update group info #
            self.last_group_segment[group_idx] = segment.text
            self.last_group_time[group_idx] = x0
            self.height_group_pos.setdefault(group_idx, 0)

            # set text position #
            scaled_pos = self.scaled_height * 0.15
            self.height_group_pos[group_idx] += self.config.FONT_SIZE
            height_pos = self.height_group_pos[group_idx]
            if height_pos + scaled_pos * 2.5 >= self.scaled_height:
                height_pos = self.height_group_pos[group_idx] = 0

        # set text position #
        xpos = x0
        ypos = y0 + scaled_pos + height_pos

        # draw text #
        dwg.add(
            dwg.text(
                segment_label,
                (xpos, ypos),
                fill=color,
                stroke="none",
                font_size=font_size,
                font_weight="normal",
                transform="rotate(0,%s,%s)" % (xpos, ypos),
            )
        )

    def draw(self, dwg, start=0, annotation=None, yval=None):
        self._draw_background(dwg)
        self._draw_grid(dwg)
        self._draw_group_axis(dwg, yval)
        self._draw_time_axis(dwg, start, annotation=annotation)
        self._draw_segments(dwg, start)
        self._draw_group_stat(dwg)

    @staticmethod
    def load(
        fileName=None,
        data=None,
        config=None,
        tasks=None,
        begin=0,
        end=0,
        duration=0,
        durationMin=0,
    ):

        if fileName:
            with open(fileName) as json_file:
                # get json object #
                json = SysMgr.getPkg("json")

                data = json.load(json_file)
        elif not data:
            SysMgr.printErr("no path or data for timeline input")
            sys.exit(-1)

        # get default timeunit #
        time_unit = ""
        if "time_unit" in data:
            time_unit = data["time_unit"]
            time_unit = time_unit.lower()

        # get title #
        if "title" in data:
            title = data["title"]
        else:
            title = ""

        # get font size #
        if "names" in data and data["names"]:
            if tasks:
                tasks.update(data["names"])
            else:
                tasks = data["names"]

        # get font size #
        if "font_size" in data:
            fontsize = data["font_size"]
        else:
            fontsize = None

        # get configured timeunit #
        time_factor = 1.0
        if hasattr(config, "TIMEUNIT") and config.TIMEUNIT:
            new_time_unit = config.TIMEUNIT.lower()

            if time_unit == new_time_unit:
                pass
            elif time_unit == "us":
                if new_time_unit == "ms":
                    time_factor = 1 / 1000.0
                elif new_time_unit == "sec":
                    time_factor = 1 / 1000000.0
                else:
                    SysMgr.printErr(
                        "no support '%s' unit for timeline" % new_time_unit
                    )
            elif time_unit == "ms":
                if new_time_unit == "us":
                    time_factor = 1000.0
                elif new_time_unit == "sec":
                    time_factor = 1 / 1000.0
                else:
                    SysMgr.printErr(
                        "no support '%s' unit for timeline" % new_time_unit
                    )
            else:
                SysMgr.printErr(
                    "no support '%s' unit for timeline" % new_time_unit
                )

            time_unit = new_time_unit
            config.TIMEFACTOR = time_factor

        # print time unit #
        if time_unit:
            SysMgr.printInfo("apply '%s' in time unit" % time_unit)

        # load segments #
        segments = Timeline._load_segments(
            data, time_factor, begin, end, duration, durationMin
        )
        if not segments:
            return None

        return Timeline(title, segments, time_unit, fontsize, config, tasks)

    @staticmethod
    def _load_segments(
        data, time_factor=1, begin=0, end=0, duration=0, durationMin=0
    ):

        segments = []
        for segment_data in sorted(
            data["segments"], key=lambda e: e["time_start"]
        ):
            # convert group #
            group = str(segment_data["group"])
            group_num = long(group)
            if group in Timeline.conv_table:
                group = Timeline.conv_table[group]

            # apply core filter ;) #
            if SysMgr.perCoreDrawList:
                if not group_num in SysMgr.perCoreDrawList:
                    continue

            # verify time #
            if segment_data["time_start"] > segment_data["time_end"]:
                SysMgr.printWarn(
                    "time_start is bigger than time_end for %s" % segment_data
                )
                continue

            # apply common duration #
            time_start = long(segment_data["time_start"] * time_factor)
            if duration > 0:
                time_end = time_start + duration
            else:
                time_end = long(segment_data["time_end"] * time_factor)

            # apply minimum duration #
            if durationMin > 0:
                diff = time_end - time_start
                if durationMin > diff:
                    time_end = time_start + durationMin

            # check time #
            if end > 0 and time_end > end:
                time_end = end
                if time_start > end:
                    continue
            if begin > 0 and time_start < begin:
                if time_end < begin:
                    continue
                time_start = begin

            # add segment #
            segments.append(
                Timeline.Segment(group, time_start, time_end, segment_data)
            )

        return segments


class Ext4Analyzer(object):
    """Analyzer for ext4"""

    FILE_TYPE = {
        0: "unkn",
        1: "file",
        2: "dir",
        3: "chr",
        4: "blk",
        5: "fifo",
        6: "sock",
        7: "sym",
    }

    def __init__(self, path, verb=False):
        # get ctypes object #
        SysMgr.importPkgItems("ctypes")

        # init variables #
        self.volume = None
        self.inodeList = {}
        self.failDirList = {}

        # start loading classes #
        # refer to https://github.com/cubinator/ext4 #
        class Ext4Error(Exception):
            """
            Base class for all custom errors
            """

            pass

        class BlockMapError(Ext4Error):
            # a requested file_block is not mapped to disk
            pass

        class EndOfStreamError(Ext4Error):
            # BlockReader reads beyond the end of the volume's underlying stream
            pass

        class MagicError(Ext4Error):
            # a structures magic value is wrong and ignoreMagic is False
            pass

        class ext4_struct(LittleEndianStructure):
            """
            Simplifies access to *_lo and *_hi fields
            """

            def __getattr__(self, name):
                """
                Enables reading *_lo and *_hi fields together.
                """
                try:
                    # Combining *_lo and *_hi fields
                    lo_field = LittleEndianStructure.__getattribute__(
                        type(self), name + "_lo"
                    )
                    size = lo_field.size

                    lo = lo_field.__get__(self)
                    hi = LittleEndianStructure.__getattribute__(
                        self, name + "_hi"
                    )

                    return (hi << (8 * size)) | lo
                except AttributeError:
                    return LittleEndianStructure.__getattribute__(self, name)

            def __setattr__(self, name, value):
                """
                Enables setting *_lo and *_hi fields together.
                """
                try:
                    # Combining *_lo and *_hi fields
                    lo_field = (
                        lo_field
                    ) = LittleEndianStructure.__getattribute__(
                        type(self), name + "_lo"
                    )
                    size = lo_field.size

                    lo_field.__set__(self, value & ((1 << (8 * size)) - 1))
                    LittleEndianStructure.__setattr__(
                        self, name + "_hi", value >> (8 * size)
                    )
                except AttributeError:
                    LittleEndianStructure.__setattr__(self, name, value)

        class ext4_dir_entry_2(ext4_struct):
            _fields_ = [
                ("inode", c_uint),  # 0x0
                ("rec_len", c_ushort),  # 0x4
                ("name_len", c_ubyte),  # 0x6
                ("file_type", c_ubyte)  # 0x7
                # Variable length field "name" missing at 0x8
            ]

            @classmethod
            def _from_buffer_copy(cls, raw, offset=0, platform64=True):
                # pylint: disable=no-self-argument
                struct = ext4_dir_entry_2.from_buffer_copy(raw, offset)
                struct.name = raw[
                    offset + 0x8 : offset + 0x8 + struct.name_len
                ]
                return struct

        class ext4_extent(ext4_struct):
            _fields_ = [
                ("ee_block", c_uint),  # 0x0000
                ("ee_len", c_ushort),  # 0x0004
                ("ee_start_hi", c_ushort),  # 0x0006
                ("ee_start_lo", c_uint),  # 0x0008
            ]

        class ext4_extent_header(ext4_struct):
            _fields_ = [
                ("eh_magic", c_ushort),  # 0x0000, Must be 0xF30A
                ("eh_entries", c_ushort),  # 0x0002
                ("eh_max", c_ushort),  # 0x0004
                ("eh_depth", c_ushort),  # 0x0006
                ("eh_generation", c_uint),  # 0x0008
            ]

        class ext4_extent_idx(ext4_struct):
            _fields_ = [
                ("ei_block", c_uint),  # 0x0000
                ("ei_leaf_lo", c_uint),  # 0x0004
                ("ei_leaf_hi", c_ushort),  # 0x0008
                ("ei_unused", c_ushort),  # 0x000A
            ]

        class ext4_group_descriptor(ext4_struct):
            _fields_ = [
                ("bg_block_bitmap_lo", c_uint),  # 0x0000
                ("bg_inode_bitmap_lo", c_uint),  # 0x0004
                ("bg_inode_table_lo", c_uint),  # 0x0008
                ("bg_free_blocks_count_lo", c_ushort),  # 0x000C
                ("bg_free_inodes_count_lo", c_ushort),  # 0x000E
                ("bg_used_dirs_count_lo", c_ushort),  # 0x0010
                ("bg_flags", c_ushort),  # 0x0012
                ("bg_exclude_bitmap_lo", c_uint),  # 0x0014
                ("bg_block_bitmap_csum_lo", c_ushort),  # 0x0018
                ("bg_inode_bitmap_csum_lo", c_ushort),  # 0x001A
                ("bg_itable_unused_lo", c_ushort),  # 0x001C
                ("bg_checksum", c_ushort),  # 0x001E
                # 64-bit fields
                ("bg_block_bitmap_hi", c_uint),  # 0x0020
                ("bg_inode_bitmap_hi", c_uint),  # 0x0024
                ("bg_inode_table_hi", c_uint),  # 0x0028
                ("bg_free_blocks_count_hi", c_ushort),  # 0x002C
                ("bg_free_inodes_count_hi", c_ushort),  # 0x002E
                ("bg_used_dirs_count_hi", c_ushort),  # 0x0030
                ("bg_itable_unused_hi", c_ushort),  # 0x0032
                ("bg_exclude_bitmap_hi", c_uint),  # 0x0034
                ("bg_block_bitmap_csum_hi", c_ushort),  # 0x0038
                ("bg_inode_bitmap_csum_hi", c_ushort),  # 0x003A
                ("bg_reserved", c_uint),  # 0x003C
            ]

            @classmethod
            def _from_buffer_copy(cls, raw, offset=0, platform64=True):
                # pylint: disable=no-self-argument
                struct = ext4_group_descriptor.from_buffer_copy(raw, offset)

                if not platform64:
                    struct.bg_block_bitmap_hi = 0
                    struct.bg_inode_bitmap_hi = 0
                    struct.bg_inode_table_hi = 0
                    struct.bg_free_blocks_count_hi = 0
                    struct.bg_free_inodes_count_hi = 0
                    struct.bg_used_dirs_count_hi = 0
                    struct.bg_itable_unused_hi = 0
                    struct.bg_exclude_bitmap_hi = 0
                    struct.bg_block_bitmap_csum_hi = 0
                    struct.bg_inode_bitmap_csum_hi = 0
                    struct.bg_reserved = 0

                return struct

        class ext4_inode(ext4_struct):
            """
            Every field passing 128 bytes is "additional data",
            whose size is specified by i_extra_isize.
            """

            EXT2_GOOD_OLD_INODE_SIZE = 128

            # i_mode
            S_IXOTH = 0x1  # Others can execute
            S_IWOTH = 0x2  # Others can write
            S_IROTH = 0x4  # Others can read
            S_IXGRP = 0x8  # Group can execute
            S_IWGRP = 0x10  # Group can write
            S_IRGRP = 0x20  # Group can read
            S_IXUSR = 0x40  # Owner can execute
            S_IWUSR = 0x80  # Owner can write
            S_IRUSR = 0x100  # Owner can read
            S_ISVTX = 0x200  # Sticky bit (only owner can delete)
            S_ISGID = 0x400  # Set GID
            S_ISUID = 0x800  # Set UID
            S_IFIFO = 0x1000  # FIFO device (named pipe)
            S_IFCHR = 0x2000  # Character device
            S_IFDIR = 0x4000  # Directory
            S_IFBLK = 0x6000  # Block device
            S_IFREG = 0x8000  # Regular file
            S_IFLNK = 0xA000  # Symbolic link
            S_IFSOCK = 0xC000  # Socket

            # i_flags
            EXT4_INDEX_FL = 0x1000  # Uses hash trees
            EXT4_EXTENTS_FL = 0x80000  # Uses extents
            EXT4_EA_INODE_FL = 0x200000  # Inode stores large xattr
            EXT4_INLINE_DATA_FL = 0x10000000  # Has inline data

            _fields_ = [
                ("i_mode", c_ushort),  # 0x0000
                ("i_uid_lo", c_ushort),  # 0x0002
                ("i_size_lo", c_uint),  # 0x0004
                ("i_atime", c_uint),  # 0x0008
                ("i_ctime", c_uint),  # 0x000C
                ("i_mtime", c_uint),  # 0x0010
                ("i_dtime", c_uint),  # 0x0014
                ("i_gid_lo", c_ushort),  # 0x0018
                ("i_links_count", c_ushort),  # 0x001A
                ("i_blocks_lo", c_uint),  # 0x001C
                ("i_flags", c_uint),  # 0x0020
                ("osd1", c_uint),  # 0x0024
                ("i_block", c_uint * 15),  # 0x0028
                ("i_generation", c_uint),  # 0x0064
                ("i_file_acl_lo", c_uint),  # 0x0068
                ("i_size_hi", c_uint),  # 0x006C
                ("i_obso_faddr", c_uint),  # 0x0070
                ("i_osd2_blocks_high", c_ushort),  # 0x0074
                ("i_file_acl_hi", c_ushort),  # 0x0076
                ("i_uid_hi", c_ushort),  # 0x0078
                ("i_gid_hi", c_ushort),  # 0x007A
                ("i_osd2_checksum_lo", c_ushort),  # 0x007C
                ("i_osd2_reserved", c_ushort),  # 0x007E
                ("i_extra_isize", c_ushort),  # 0x0080
                ("i_checksum_hi", c_ushort),  # 0x0082
                ("i_ctime_extra", c_uint),  # 0x0084
                ("i_mtime_extra", c_uint),  # 0x0088
                ("i_atime_extra", c_uint),  # 0x008C
                ("i_crtime", c_uint),  # 0x0090
                ("i_crtime_extra", c_uint),  # 0x0094
                ("i_version_hi", c_uint),  # 0x0098
                ("i_projid", c_uint),  # 0x009C
            ]

        class ext4_superblock(ext4_struct):
            # Default value for s_desc_size, if INCOMPAT_64BIT is not set
            EXT2_MIN_DESC_SIZE = 0x20
            # Default value for s_desc_size, if INCOMPAT_64BIT is set
            EXT2_MIN_DESC_SIZE_64BIT = 0x40

            # s_feature_incompat
            # Uses 64-bit features
            INCOMPAT_64BIT = 0x80
            # Directory entries record file type (instead of inode flags)
            INCOMPAT_FILETYPE = 0x2

            _fields_ = [
                ("s_inodes_count", c_uint),  # 0x0000
                ("s_blocks_count_lo", c_uint),  # 0x0004
                ("s_r_blocks_count_lo", c_uint),  # 0x0008
                ("s_free_blocks_count_lo", c_uint),  # 0x000C
                ("s_free_inodes_count", c_uint),  # 0x0010
                ("s_first_data_block", c_uint),  # 0x0014
                ("s_log_block_size", c_uint),  # 0x0018
                ("s_log_cluster_size", c_uint),  # 0x001C
                ("s_blocks_per_group", c_uint),  # 0x0020
                ("s_clusters_per_group", c_uint),  # 0x0024
                ("s_inodes_per_group", c_uint),  # 0x0028
                ("s_mtime", c_uint),  # 0x002C
                ("s_wtime", c_uint),  # 0x0030
                ("s_mnt_count", c_ushort),  # 0x0034
                ("s_max_mnt_count", c_ushort),  # 0x0036
                ("s_magic", c_ushort),  # 0x0038
                ("s_state", c_ushort),  # 0x003A
                ("s_errors", c_ushort),  # 0x003C
                ("s_minor_rev_level", c_ushort),  # 0x003E
                ("s_lastcheck", c_uint),  # 0x0040
                ("s_checkinterval", c_uint),  # 0x0044
                ("s_creator_os", c_uint),  # 0x0048
                ("s_rev_level", c_uint),  # 0x004C
                ("s_def_resuid", c_ushort),  # 0x0050
                ("s_def_resgid", c_ushort),  # 0x0052
                ("s_first_ino", c_uint),  # 0x0054
                ("s_inode_size", c_ushort),  # 0x0058
                ("s_block_group_nr", c_ushort),  # 0x005A
                ("s_feature_compat", c_uint),  # 0x005C
                ("s_feature_incompat", c_uint),  # 0x0060
                ("s_feature_ro_compat", c_uint),  # 0x0064
                ("s_uuid", c_ubyte * 16),  # 0x0068
                ("s_volume_name", c_char * 16),  # 0x0078
                ("s_last_mounted", c_char * 64),  # 0x0088
                ("s_algorithm_usage_bitmap", c_uint),  # 0x00C8
                ("s_prealloc_blocks", c_ubyte),  # 0x00CC
                ("s_prealloc_dir_blocks", c_ubyte),  # 0x00CD
                ("s_reserved_gdt_blocks", c_ushort),  # 0x00CE
                ("s_journal_uuid", c_ubyte * 16),  # 0x00D0
                ("s_journal_inum", c_uint),  # 0x00E0
                ("s_journal_dev", c_uint),  # 0x00E4
                ("s_last_orphan", c_uint),  # 0x00E8
                ("s_hash_seed", c_uint * 4),  # 0x00EC
                ("s_def_hash_version", c_ubyte),  # 0x00FC
                ("s_jnl_backup_type", c_ubyte),  # 0x00FD
                ("s_desc_size", c_ushort),  # 0x00FE
                ("s_default_mount_opts", c_uint),  # 0x0100
                ("s_first_meta_bg", c_uint),  # 0x0104
                ("s_mkfs_time", c_uint),  # 0x0108
                ("s_jnl_blocks", c_uint * 17),  # 0x010C
                # 64-bit fields
                ("s_blocks_count_hi", c_uint),  # 0x0150
                ("s_r_blocks_count_hi", c_uint),  # 0x0154
                ("s_free_blocks_count_hi", c_uint),  # 0x0158
                ("s_min_extra_isize", c_ushort),  # 0x015C
                ("s_want_extra_isize", c_ushort),  # 0x015E
                ("s_flags", c_uint),  # 0x0160
                ("s_raid_stride", c_ushort),  # 0x0164
                ("s_mmp_interval", c_ushort),  # 0x0166
                ("s_mmp_block", c_ulonglong),  # 0x0168
                ("s_raid_stripe_width", c_uint),  # 0x0170
                ("s_log_groups_per_flex", c_ubyte),  # 0x0174
                ("s_checksum_type", c_ubyte),  # 0x0175
                ("s_reserved_pad", c_ushort),  # 0x0176
                ("s_kbytes_written", c_ulonglong),  # 0x0178
                ("s_snapshot_inum", c_uint),  # 0x0180
                ("s_snapshot_id", c_uint),  # 0x0184
                ("s_snapshot_r_blocks_count", c_ulonglong),  # 0x0188
                ("s_snapshot_list", c_uint),  # 0x0190
                ("s_error_count", c_uint),  # 0x0194
                ("s_first_error_time", c_uint),  # 0x0198
                ("s_first_error_ino", c_uint),  # 0x019C
                ("s_first_error_block", c_ulonglong),  # 0x01A0
                ("s_first_error_func", c_ubyte * 32),  # 0x01A8
                ("s_first_error_line", c_uint),  # 0x01C8
                ("s_last_error_time", c_uint),  # 0x01CC
                ("s_last_error_ino", c_uint),  # 0x01D0
                ("s_last_error_line", c_uint),  # 0x01D4
                ("s_last_error_block", c_ulonglong),  # 0x01D8
                ("s_last_error_func", c_ubyte * 32),  # 0x01E0
                ("s_mount_opts", c_ubyte * 64),  # 0x0200
                ("s_usr_quota_inum", c_uint),  # 0x0240
                ("s_grp_quota_inum", c_uint),  # 0x0244
                ("s_overhead_blocks", c_uint),  # 0x0248
                ("s_backup_bgs", c_uint * 2),  # 0x024C
                ("s_encrypt_algos", c_ubyte * 4),  # 0x0254
                ("s_encrypt_pw_salt", c_ubyte * 16),  # 0x0258
                ("s_lpf_ino", c_uint),  # 0x0268
                ("s_prj_quota_inum", c_uint),  # 0x026C
                ("s_checksum_seed", c_uint),  # 0x0270
                ("s_reserved", c_uint * 98),  # 0x0274
                ("s_checksum", c_uint),  # 0x03FC
            ]

            @classmethod
            def _from_buffer_copy(cls, raw, platform64=True):
                # pylint: disable=no-self-argument
                struct = ext4_superblock.from_buffer_copy(raw)

                if not platform64:
                    struct.s_blocks_count_hi = 0
                    struct.s_r_blocks_count_hi = 0
                    struct.s_free_blocks_count_hi = 0
                    struct.s_min_extra_isize = 0
                    struct.s_want_extra_isize = 0
                    struct.s_flags = 0
                    struct.s_raid_stride = 0
                    struct.s_mmp_interval = 0
                    struct.s_mmp_block = 0
                    struct.s_raid_stripe_width = 0
                    struct.s_log_groups_per_flex = 0
                    struct.s_checksum_type = 0
                    struct.s_reserved_pad = 0
                    struct.s_kbytes_written = 0
                    struct.s_snapshot_inum = 0
                    struct.s_snapshot_id = 0
                    struct.s_snapshot_r_blocks_count = 0
                    struct.s_snapshot_list = 0
                    struct.s_error_count = 0
                    struct.s_first_error_time = 0
                    struct.s_first_error_ino = 0
                    struct.s_first_error_block = 0
                    struct.s_first_error_func = 0
                    struct.s_first_error_line = 0
                    struct.s_last_error_time = 0
                    struct.s_last_error_ino = 0
                    struct.s_last_error_line = 0
                    struct.s_last_error_block = 0
                    struct.s_last_error_func = 0
                    struct.s_mount_opts = 0
                    struct.s_usr_quota_inum = 0
                    struct.s_grp_quota_inum = 0
                    struct.s_overhead_blocks = 0
                    struct.s_backup_bgs = 0
                    struct.s_encrypt_algos = 0
                    struct.s_encrypt_pw_salt = 0
                    struct.s_lpf_ino = 0
                    struct.s_prj_quota_inum = 0
                    struct.s_checksum_seed = 0
                    struct.s_reserved = 0
                    struct.s_checksum = 0

                if struct.s_desc_size != 0:
                    return struct

                if (
                    struct.s_feature_incompat & ext4_superblock.INCOMPAT_64BIT
                ) == 0:
                    struct.s_desc_size = ext4_superblock.EXT2_MIN_DESC_SIZE
                else:
                    struct.s_desc_size = (
                        ext4_superblock.EXT2_MIN_DESC_SIZE_64BIT
                    )

                return struct

        class ext4_xattr_entry(ext4_struct):
            _fields_ = [
                ("e_name_len", c_ubyte),  # 0x00
                ("e_name_index", c_ubyte),  # 0x01
                ("e_value_offs", c_ushort),  # 0x02
                ("e_value_inum", c_uint),  # 0x04
                ("e_value_size", c_uint),  # 0x08
                ("e_hash", c_uint)  # 0x0C
                # Variable length field "e_name" missing at 0x10
            ]

            @classmethod
            def _from_buffer_copy(cls, raw, offset=0, platform64=True):
                # pylint: disable=no-self-argument
                struct = ext4_xattr_entry.from_buffer_copy(raw, offset)
                struct.e_name = raw[
                    offset + 0x10 : offset + 0x10 + struct.e_name_len
                ]
                return struct

            @property
            def _size(self):
                # 4-byte alignment
                return 4 * ((sizeof(type(self)) + self.e_name_len + 3) // 4)

        class ext4_xattr_header(ext4_struct):
            _fields_ = [
                ("h_magic", c_uint),  # 0x0, Must be 0xEA020000
                ("h_refcount", c_uint),  # 0x4
                ("h_blocks", c_uint),  # 0x8
                ("h_hash", c_uint),  # 0xC
                ("h_checksum", c_uint),  # 0x10
                ("h_reserved", c_uint * 3),  # 0x14
            ]

        class ext4_xattr_ibody_header(ext4_struct):
            _fields_ = [("h_magic", c_uint)]  # 0x0, Must be 0xEA020000

        class InodeType:
            UNKNOWN = 0x0  # Unknown file type
            FILE = 0x1  # Regular file
            DIRECTORY = 0x2  # Directory
            CHARACTER_DEVICE = 0x3  # Character device
            BLOCK_DEVICE = 0x4  # Block device
            FIFO = 0x5  # FIFO
            SOCKET = 0x6  # Socket
            SYMBOLIC_LINK = 0x7  # Symbolic link
            CHECKSUM = 0xDE  # Checksum entry

        class MappingEntry:
            """
            Helper class: This class maps blkCnt file blocks
            indexed by fileBlkIdx to the associated disk blocks indexed
            by diskBlkIdx.
            """

            def __init__(self, fileBlkIdx, diskBlkIdx, blkCnt=1):
                """
                Initialize a MappingEntry instance with given fileBlkIdx,
                diskBlkIdx and blkCnt.
                """
                self.fileBlkIdx = fileBlkIdx
                self.diskBlkIdx = diskBlkIdx
                self.blkCnt = blkCnt

            def __iter__(self):
                """
                Can be used to convert an MappingEntry into a tuple
                (fileBlkIdx, diskBlkIdx, blkCnt).
                """
                yield self.fileBlkIdx
                yield self.diskBlkIdx
                yield self.blkCnt

            def __repr__(self):
                return "%s(%s, %s, %s)" % (
                    type(self).__name__,
                    self.fileBlkIdx,
                    self.diskBlkIdx,
                    self.blkCnt,
                )

            def copy(self):
                return MappingEntry(
                    self.fileBlkIdx, self.diskBlkIdx, self.blkCnt
                )

            def create_mapping(*entries):
                # pylint: disable=no-method-argument
                """
                Converts a list of 2-tuples
                (diskBlkIdx, blkCnt) into a list of MappingEntry instances
                """
                fileBlkIdx = 0
                result = [None] * len(entries)

                for i, entry in enumerate(entries):
                    diskBlkIdx, blkCnt = entry
                    result[i] = MappingEntry(fileBlkIdx, diskBlkIdx, blkCnt)
                    fileBlkIdx += blkCnt

                return result

            @classmethod
            def optimize(cls, entries):
                # pylint: disable=no-self-argument
                """
                Sorts and stiches together a list of MappingEntry instances
                """
                entries = list(entries)
                entries.sort(key=lambda entry: entry.fileBlkIdx)

                idx = 0
                while idx < len(entries):
                    while (
                        (idx + 1 < len(entries))
                        and (
                            entries[idx].fileBlkIdx + entries[idx].blkCnt
                            == entries[idx + 1].fileBlkIdx
                        )
                        and (
                            entries[idx].diskBlkIdx + entries[idx].blkCnt
                            == entries[idx + 1].diskBlkIdx
                        )
                    ):
                        tmp = entries.pop(idx + 1)
                        entries[idx].blkCnt += tmp.blkCnt

                    idx += 1

        class Volume:
            """
            Provides functionality for reading ext4 volumes
            """

            ROOT_INODE = 2

            def __init__(
                self, stream, offset=0, ignoreFlag=False, ignoreMagic=False
            ):
                """
                Initializes a new ext4 reader at a given offset in stream.
                If ignoreMagic is True, no exception will be thrown,
                when a structure with wrong magic number is found.
                Analogously passing True to ignoreFlag suppresses Exception
                caused by wrong flags.
                """
                self.ignoreFlag = ignoreFlag
                self.ignoreMagic = ignoreMagic
                self.offset = offset
                # Initial value needed for Volume.read_struct
                self.platform64 = True
                self.stream = stream

                # Superblock
                self.superblock = self.read_struct(ext4_superblock, 0x400)
                self.platform64 = (
                    self.superblock.s_feature_incompat
                    & ext4_superblock.INCOMPAT_64BIT
                ) != 0

                if not ignoreMagic and self.superblock.s_magic != 0xEF53:
                    raise MagicError(
                        (
                            "Invalid magic value in superblock: "
                            "0x%04X (expected 0xEF53)"
                        )
                        % self.superblock.s_magic
                    )

                # Group descriptors
                self.group_descriptors = [None] * (
                    self.superblock.s_inodes_count
                    // self.superblock.s_inodes_per_group
                )

                # First block after superblock
                group_desc_table_offset = (
                    0x400 // self.block_size + 1
                ) * self.block_size
                for group_desc_idx in xrange(len(self.group_descriptors)):
                    group_desc_offset = (
                        group_desc_table_offset
                        + group_desc_idx * self.superblock.s_desc_size
                    )
                    self.group_descriptors[group_desc_idx] = self.read_struct(
                        ext4_group_descriptor, group_desc_offset
                    )

            def __repr__(self):
                return "%s(volume_name = %s, uuid = %s, last_mounted = %s)" % (
                    type(self).__name__,
                    self.superblock.s_volume_name,
                    self.uuid,
                    self.superblock.s_last_mounted,
                )

            @property
            def block_size(self):
                """
                Returns the volume's block size in bytes.
                """
                return 1 << (10 + self.superblock.s_log_block_size)

            def get_inode(self, inode_idx):
                """
                Returns an Inode instance representing the inode specified
                by its index inode_idx.
                """
                group_idx, inode_table_entry_idx = self.get_inode_group(
                    inode_idx
                )

                inode_table_offset = (
                    self.group_descriptors[group_idx].bg_inode_table
                    * self.block_size
                )
                inode_offset = (
                    inode_table_offset
                    + inode_table_entry_idx * self.superblock.s_inode_size
                )

                return Inode(self, inode_offset, inode_idx)

            def get_inode_group(self, inode_idx):
                """
                Returns a tuple (group_idx, inode_table_entry_idx)
                """
                group_idx = (
                    inode_idx - 1
                ) // self.superblock.s_inodes_per_group
                inode_table_entry_idx = (
                    inode_idx - 1
                ) % self.superblock.s_inodes_per_group
                return (group_idx, inode_table_entry_idx)

            def read(self, offset, byte_len):
                """
                Returns byte_len bytes at offset within this volume.
                """
                if self.offset + offset != self.stream.tell():
                    self.stream.seek(self.offset + offset, os.SEEK_SET)

                return self.stream.read(byte_len)

            def read_struct(self, structure, offset, platform64=None):
                """
                Interprets the bytes at offset as structure and returns
                the interpretd instance
                """
                raw = self.read(offset, sizeof(structure))

                if hasattr(structure, "_from_buffer_copy"):
                    return structure._from_buffer_copy(
                        raw,
                        platform64=platform64
                        if platform64 != None
                        else self.platform64,
                    )
                else:
                    return structure.from_buffer_copy(raw)

            @property
            def root(self):
                """
                Returns the volume's root inode
                """
                return self.get_inode(Volume.ROOT_INODE)

            @property
            def uuid(self):
                """
                Returns the volume's UUID in the format
                XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX.
                """
                uuid = self.superblock.s_uuid
                uuid = [uuid[:4], uuid[4:6], uuid[6:8], uuid[8:10], uuid[10:]]
                return "-".join(
                    "".join("%02X" % c for c in part) for part in uuid
                )

        class Inode:
            """
            Provides functionality for parsing inodes and accessing raw data
            """

            def __init__(self, volume, offset, inode_idx):
                """
                Initializes a new inode parser at the specified offset
                within the specified volume. file_type is the file type
                of the inode as given by the directory entry
                referring to this inode.
                """
                self.inode_idx = inode_idx
                self.offset = offset
                self.volume = volume
                self.inode = volume.read_struct(ext4_inode, offset)

            def __len__(self):
                """
                Returns the length in bytes of the content
                referenced by this inode.
                """
                return int(self.inode.i_size)

            def __repr__(self):
                if self.inode_idx != None:
                    return (
                        "%s(inode_idx = %s, offset = 0x%X, volume_uuid = %s"
                    ) % (
                        type(self).__name__,
                        self.inode_idx,
                        self.offset,
                        self.volume.uuid,
                    )
                else:
                    return "%s(offset = 0x%X, volume_uuid = %s)" % (
                        type(self).__name__,
                        self.offset,
                        self.volume.uuid,
                    )

            def _parse_xattrs(self, raw_data, offset, prefix_override={}):
                """
                Generator: Parses raw_data (bytes) as ext4_xattr_entry
                structures and their referenced xattr values and yields
                tuples (xattr_name, xattr_value) where xattr_name (str)
                is the attribute name including its prefix and
                xattr_value (bytes) is the raw attribute value.
                raw_data must start with the first ext4_xattr_entry
                structure and offset specifies the offset to the "block start"
                for ext4_xattr_entry.e_value_offs.
                prefix_overrides allows specifying attributes apart from
                the default prefixes. The default prefix dictionary is
                updated with prefix_overrides.
                """
                prefixes = {
                    0: "",
                    1: "user.",
                    2: "system.posix_acl_access",
                    3: "system.posix_acl_default",
                    4: "trusted.",
                    6: "security.",
                    7: "system.",
                    8: "system.richacl",
                }
                prefixes.update(prefixes)

                # Iterator over ext4_xattr_entry structures
                i = 0
                while i < len(raw_data):
                    xattr_entry = ext4_xattr_entry._from_buffer_copy(
                        raw_data, i, platform64=self.volume.platform64
                    )

                    if (
                        xattr_entry.e_name_len
                        | xattr_entry.e_name_index
                        | xattr_entry.e_value_offs
                        | xattr_entry.e_value_inum
                    ) == 0:
                        # End of ext4_xattr_entry list
                        break

                    if not xattr_entry.e_name_index in prefixes:
                        raise Ext4Error(
                            "Unknown attribute prefix %d in inode %d"
                            % (xattr_entry.e_name_idx, self.inode_idx)
                        )

                    xattr_name = prefixes[
                        xattr_entry.e_name_index
                    ] + xattr_entry.e_name.decode("iso-8859-2")

                    if xattr_entry.e_value_inum != 0:
                        # external xattr
                        xattr_inode = self.volume.get_inode(
                            xattr_entry.e_value_inum
                        )

                        if (
                            not self.volume.ignoreFlag
                            and (
                                xattr_inode.inode.i_flags
                                & ext4_inode.EXT4_EA_INODE_FL
                            )
                            != 0
                        ):
                            raise Ext4Error(
                                (
                                    "Inode %d associated with the extended "
                                    "attribute %s of inode %d is not marked as "
                                    "large extended attribute value."
                                )
                                % (
                                    xattr_inode.inode_idx,
                                    xattr_name,
                                    self.inode_idx,
                                )
                            )

                        # TODO Use xattr_entry.e_value_size or xattr_inode.inode.i_size?
                        xattr_value = xattr_inode.open_read().read()
                    else:
                        # internal xattr
                        start = xattr_entry.e_value_offs + offset
                        end = (
                            xattr_entry.e_value_offs
                            + offset
                            + xattr_entry.e_value_size
                        )
                        xattr_value = raw_data[start:end]

                    yield (xattr_name, xattr_value)

                    i += xattr_entry._size

            def get_inode(self, *relative_path):
                """
                Returns the inode specified by the path relative_path
                (list of entry names) relative to this inode. "." and ".."
                usually are supported too, however in special cases
                (e.g. manually crafted volumes) they might not be supported
                due to them being real on-disk directory entries that
                might be missing or pointing somewhere else.
                decode_name is directly passed to open_dir.
                NOTE: Whitespaces will not be trimmed off the path's parts
                and "\\0" and "\\0\\0" as well as b"\\0" and b"\\0\\0" are
                seen as different names
                (unless decode_name actually trims the name).
                NOTE: Along the path file_type != FILETYPE_DIR will be
                ignored, however i_flags will not be ignored.
                """
                if not self.is_dir:
                    raise Ext4Error(
                        "Inode %d is not a directory" % self.inode_idx
                    )

                current_inode = self
                decode_name = None

                for i, part in enumerate(relative_path):
                    if not self.volume.ignoreFlag and not current_inode.is_dir:
                        current_path = "/".join(relative_path[:i])
                        raise Ext4Error(
                            "%s (Inode %d) is not a directory."
                            % (current_path, inode_idx)
                        )

                    file_name, inode_idx, file_type = next(
                        filter(
                            lambda entry: entry[0] == part,
                            current_inode.open_dir(decode_name),
                        ),
                        (None, None, None),
                    )

                    if inode_idx == None:
                        current_path = "/".join(relative_path[:i])
                        raise FileNotFoundError(
                            "%s not found in %s (Inode %d)"
                            % (part, current_path, current_inode.inode_idx)
                        )

                    current_inode = current_inode.volume.get_inode(inode_idx)

                return current_inode

            @property
            def is_dir(self):
                """
                Indicates whether the inode is marked as a directory.
                """
                return (self.inode.i_mode & ext4_inode.S_IFDIR) != 0

            @property
            def is_file(self):
                """
                Indicates whether the inode is marker as a regular file.
                """
                return (self.inode.i_mode & ext4_inode.S_IFREG) != 0

            @property
            def is_in_use(self):
                """
                Indicates whether the inode's associated bit
                in the inode bitmap is set.
                """
                group_idx, bitmap_bit = self.volume.get_inode_group(
                    self.inode_idx
                )

                inode_usage_bitmap_offset = (
                    self.volume.group_descriptors[group_idx].bg_inode_bitmap
                    * self.volume.block_size
                )
                inode_usage_byte = self.volume.read(
                    inode_usage_bitmap_offset + bitmap_bit // 8, 1
                )[0]

                return ((inode_usage_byte >> (7 - bitmap_bit % 8)) & 1) != 0

            @property
            def mode_str(self):
                """
                Returns the inode's permissions in form of a unix string
                (e.g. "-rwxrw-rw" or "drwxr-xr--").
                """
                special_flag = lambda letter, execute, special: {
                    (False, False): "-",
                    (False, True): letter.upper(),
                    (True, False): "x",
                    (True, True): letter.lower(),
                }[(execute, special)]

                try:
                    device_type = {
                        ext4_inode.S_IFIFO: "p",
                        ext4_inode.S_IFCHR: "c",
                        ext4_inode.S_IFDIR: "d",
                        ext4_inode.S_IFBLK: "b",
                        ext4_inode.S_IFREG: "-",
                        ext4_inode.S_IFLNK: "l",
                        ext4_inode.S_IFSOCK: "s",
                    }[self.inode.i_mode & 0xF000]
                except KeyError:
                    device_type = "?"

                return "".join(
                    [
                        device_type,
                        "r"
                        if (self.inode.i_mode & ext4_inode.S_IRUSR) != 0
                        else "-",
                        "w"
                        if (self.inode.i_mode & ext4_inode.S_IWUSR) != 0
                        else "-",
                        special_flag(
                            "s",
                            (self.inode.i_mode & ext4_inode.S_IXUSR) != 0,
                            (self.inode.i_mode & ext4_inode.S_ISUID) != 0,
                        ),
                        "r"
                        if (self.inode.i_mode & ext4_inode.S_IRGRP) != 0
                        else "-",
                        "w"
                        if (self.inode.i_mode & ext4_inode.S_IWGRP) != 0
                        else "-",
                        special_flag(
                            "s",
                            (self.inode.i_mode & ext4_inode.S_IXGRP) != 0,
                            (self.inode.i_mode & ext4_inode.S_ISGID) != 0,
                        ),
                        "r"
                        if (self.inode.i_mode & ext4_inode.S_IROTH) != 0
                        else "-",
                        "w"
                        if (self.inode.i_mode & ext4_inode.S_IWOTH) != 0
                        else "-",
                        special_flag(
                            "t",
                            (self.inode.i_mode & ext4_inode.S_IXOTH) != 0,
                            (self.inode.i_mode & ext4_inode.S_ISVTX) != 0,
                        ),
                    ]
                )

            def open_dir(self, decode_name=None, path=None):
                """
                Generator: Yields the directory entries as tuples
                (decode_name(name), inode, file_type) in their on-disk order,
                where name is the raw on-disk directory entry name (bytes).
                file_type is one of the Inode.IT_* constants. For
                special cases (e.g. invalid utf8 characters in entry names)
                you can try a different decoder
                (e.g. decode_name = lambda raw: raw).
                Default of decode_name = lambda raw: raw.decode("utf8")
                """
                # Parse args
                if decode_name == None:
                    # decode_name = lambda raw: raw.decode("utf8")
                    decode_name = lambda raw: raw.decode("latin-1")

                if not self.volume.ignoreFlag and not self.is_dir:
                    raise Ext4Error(
                        "Inode (%d) is not a directory (%s)"
                        % (self.inode_idx, path)
                    )

                # Hash trees are compatible with linear arrays
                if (self.inode.i_flags & ext4_inode.EXT4_INDEX_FL) != 0:
                    SysMgr.printWarn(
                        "hash trees are not implemented yet for %s" % path
                    )
                    return
                    # TODO: implement hash tree parser #
                    raise NotImplementedError(
                        "Hash trees are not implemented yet for %s" % path
                    )

                # Read raw directory content
                raw_data = self.open_read().read()
                offset = 0

                while offset < len(raw_data):
                    dirent = ext4_dir_entry_2._from_buffer_copy(
                        raw_data, offset, platform64=self.volume.platform64
                    )

                    if dirent.file_type != InodeType.CHECKSUM:
                        yield (
                            decode_name(dirent.name),
                            dirent.inode,
                            dirent.file_type,
                        )

                    offset += dirent.rec_len

            def open_read(self):
                """
                Returns an BlockReader instance for reading this inode's
                raw content.
                """
                if (self.inode.i_flags & ext4_inode.EXT4_EXTENTS_FL) != 0:
                    # Obtain mapping from extents
                    mapping = []  # List of MappingEntry instances

                    nodes = []
                    nodes.append(self.offset + ext4_inode.i_block.offset)

                    while nodes:
                        header_offset = nodes.pop(0)
                        header = self.volume.read_struct(
                            ext4_extent_header, header_offset
                        )

                        if (
                            not self.volume.ignoreMagic
                            and header.eh_magic != 0xF30A
                        ):
                            raise MagicError(
                                (
                                    "Invalid magic value in extent header at "
                                    "offset 0x%X of inode %d: 0x%04X "
                                    "(expected 0xF30A)"
                                )
                                % (
                                    header_offset,
                                    self.inode_idx,
                                    header.eh_magic,
                                )
                            )

                        if header.eh_depth != 0:
                            indices = self.volume.read_struct(
                                ext4_extent_idx * header.eh_entries,
                                header_offset + sizeof(ext4_extent_header),
                            )
                            for idx in indices:
                                nodes.append(
                                    idx.ei_leaf * self.volume.block_size
                                )
                        else:
                            extents = self.volume.read_struct(
                                ext4_extent * header.eh_entries,
                                header_offset + sizeof(ext4_extent_header),
                            )
                            for extent in extents:
                                mapping.append(
                                    MappingEntry(
                                        extent.ee_block,
                                        extent.ee_start,
                                        extent.ee_len,
                                    )
                                )

                    MappingEntry.optimize(mapping)
                    return BlockReader(self.volume, len(self), mapping)
                else:
                    # Inode uses inline data
                    i_block = self.volume.read(
                        self.offset + ext4_inode.i_block.offset,
                        ext4_inode.i_block.size,
                    )
                    return SysMgr.getPkg("io").BytesIO(
                        i_block[: self.inode.i_size]
                    )

            def xattrs(
                self,
                check_inline=True,
                check_block=True,
                force_inline=False,
                prefix_override={},
            ):
                """
                Generator: Yields the inode's extended attributes as tuples
                (name, value) in their on-disk order, where name (str)
                is the on-disk attribute name including its resolved name
                prefix and value (bytes) is the raw attribute value.
                check_inline and check_block control where to read attributes
                (the inode's inline data and/or the external data block
                pointed to by i_file_acl) and if check_inline as well as
                force_inline are set to True, the inode's inline data
                will not be verified to contain actual extended attributes
                and instead is just interpretd as such. prefix_overrides
                is directly passed to Inode._parse_xattrs.
                """
                # Inline xattrs
                inline_data_offset = (
                    self.offset
                    + ext4_inode.EXT2_GOOD_OLD_INODE_SIZE
                    + self.inode.i_extra_isize
                )
                inline_data_length = (
                    self.offset
                    + self.volume.superblock.s_inode_size
                    - inline_data_offset
                )

                if check_inline and inline_data_length > sizeof(
                    ext4_xattr_ibody_header
                ):
                    inline_data = self.volume.read(
                        inline_data_offset, inline_data_length
                    )
                    xattrs_header = ext4_xattr_ibody_header.from_buffer_copy(
                        inline_data
                    )

                    """
                    TODO: Find way to detect inline xattrs without checking
                    the h_magic field to enable error detection with
                    the h_magic field.
                    """
                    if force_inline or xattrs_header.h_magic == 0xEA020000:
                        # The ext4_xattr_entry following the header is aligned on a 4-byte boundary
                        offset = 4 * (
                            (sizeof(ext4_xattr_ibody_header) + 3) // 4
                        )
                        for xattr_name, xattr_value in self._parse_xattrs(
                            inline_data[offset:],
                            0,
                            prefix_override=prefix_override,
                        ):
                            yield (xattr_name, xattr_value)

                # xattr block(s)
                if check_block and self.inode.i_file_acl != 0:
                    xattrs_block_start = (
                        self.inode.i_file_acl * self.volume.block_size
                    )
                    xattrs_block = self.volume.read(
                        xattrs_block_start, self.volume.block_size
                    )

                    xattrs_header = ext4_xattr_header.from_buffer_copy(
                        xattrs_block
                    )
                    if (
                        not self.volume.ignoreMagic
                        and xattrs_header.h_magic != 0xEA020000
                    ):
                        raise MagicError(
                            (
                                "Invalid magic value in xattrs block header at "
                                "offset 0x%X of inode %d: 0x%X "
                                "(expected 0xEA020000)"
                            )
                            % (
                                xattrs_block_start,
                                self.inode_idx,
                                xattrs_header.h_magic,
                            )
                        )

                    if xattrs_header.h_blocks != 1:
                        raise Ext4Error(
                            "Invalid number of xattr blocks at offset "
                            "0x%X of inode %d: %d (expected 1)"
                            % (
                                xattrs_block_start,
                                self.inode_idx,
                                xattrs_header.h_blocks,
                            )
                        )

                    # The ext4_xattr_entry following the header is aligned on a 4-byte boundary
                    offset = 4 * ((sizeof(ext4_xattr_header) + 3) // 4)
                    for xattr_name, xattr_value in self._parse_xattrs(
                        xattrs_block[offset:],
                        -offset,
                        prefix_override=prefix_override,
                    ):
                        yield (xattr_name, xattr_value)

        class BlockReader:
            """
            Maps disk blocks into a linear byte stream.
            NOTE: This class does not implement buffering or caching.
            """

            # OSError
            EINVAL = 22

            def __init__(self, volume, byte_size, block_map):
                """
                Initializes a new block reader on the specified volume.
                mapping must be a list of MappingEntry instances. If
                you prefer a way to use 2-tuples (diskBlkIdx, blkCnt)
                with inferred file_block_index entries, see
                MappingEntry.create_mapping.
                """
                self.byte_size = byte_size
                self.volume = volume
                self.cursor = 0
                block_map = list(map(MappingEntry.copy, block_map))

                # Optimize mapping (stich together)
                MappingEntry.optimize(block_map)
                self.block_map = block_map

            def __repr__(self):
                return (
                    "%s(byte_size = %s, block_map = %s, "
                    "volume_uuid = %s)"
                    % (
                        type(self).__name__,
                        self.byte_size,
                        self.block_map,
                        self.volume.uuid,
                    )
                )

            def get_block_mapping(self, fileBlkIdx):
                """
                Returns the disk block index of the file block specified
                by fileBlkIdx.
                """
                diskBlkIdx = None

                # Find disk block
                for entry in self.block_map:
                    if (
                        entry.fileBlkIdx
                        <= fileBlkIdx
                        < entry.fileBlkIdx + entry.blkCnt
                    ):
                        block_diff = fileBlkIdx - entry.fileBlkIdx
                        diskBlkIdx = entry.diskBlkIdx + block_diff
                        break

                return diskBlkIdx

            def read(self, byte_len=-1):
                """
                Reades up to byte_len bytes from the block device beginning
                at the cursor's current position. This operation will
                not exceed the inode's size. If -1 is passed for byte_len,
                the inode is read to the end.
                """
                # Parse args
                if byte_len < -1:
                    raise ValueError("byte_len must be non-negative or -1")

                bytes_remaining = self.byte_size - self.cursor
                byte_len = (
                    bytes_remaining
                    if byte_len == -1
                    else max(0, min(byte_len, bytes_remaining))
                )

                if byte_len == 0:
                    return b""

                # Reading blocks
                start_block_idx = self.cursor // self.volume.block_size
                end_block_idx = (
                    self.cursor + byte_len - 1
                ) // self.volume.block_size
                end_of_stream_check = byte_len

                blocks = [
                    self.read_block(i)
                    for i in xrange(
                        start_block_idx, end_block_idx - start_block_idx + 1
                    )
                ]

                startOffset = self.cursor % self.volume.block_size
                if startOffset != 0:
                    blocks[0] = blocks[0][startOffset:]
                byte_len = (
                    byte_len + startOffset - self.volume.block_size - 1
                ) % self.volume.block_size + 1
                blocks[-1] = blocks[-1][:byte_len]

                result = b"".join(blocks)

                # Check read
                if len(result) != end_of_stream_check:
                    raise EndOfStreamError(
                        (
                            "The volume's underlying stream ended "
                            "%s bytes before EOF."
                        )
                        % (UtilMgr.convNum(byte_len - len(result)))
                    )

                self.cursor += len(result)
                return result

            def read_block(self, fileBlkIdx):
                """
                Reads one block from disk
                (return a zero-block if the file block is not mapped)
                """
                diskBlkIdx = self.get_block_mapping(fileBlkIdx)

                if diskBlkIdx != None:
                    return self.volume.read(
                        diskBlkIdx * self.volume.block_size,
                        self.volume.block_size,
                    )
                else:
                    return bytes([0] * self.volume.block_size)

            def seek(self, seek, seek_mode=os.SEEK_SET):
                """
                Moves the internal cursor along the file
                (not the disk) and behaves like BufferedReader.seek
                """
                if seek_mode == os.SEEK_CUR:
                    seek += self.cursor
                elif seek_mode == os.SEEK_END:
                    seek += self.byte_size
                elif seek_mode == os.SEEK_SET:
                    seek += 0

                if seek < 0:
                    # Exception behavior copied from IOBase.seek
                    raise OSError(BlockReader.EINVAL, "Invalid argument")

                self.cursor = seek
                return seek

            def tell(self):
                """
                Returns the internal cursor's current file offset.
                """
                return self.cursor

        # open target file #
        try:
            self.fd = open(path, "rb")
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("failed to open %s" % path, reason=True)
            raise Exception("open failure")

        # init volume object #
        try:
            self.volume = Volume(self.fd)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn(
                "failed to init EXT4 object for %s'" % path, reason=True
            )

        # check volume object #
        if not self.volume:
            raise Exception("volume failure")

    def getInodeInfo(self, inode=None, path=None):
        if not inode and not path:
            SysMgr.printErr("no input for inode or path to get file meta info")
            return None

        if inode:
            inode = long(inode)
            inodeObj = self.volume.get_inode(inode)
            return inodeObj

        if path:
            parent = self.volume.root
            for item in path.split("/"):
                if not item:
                    continue
                parent = parent.get_inode(item)
            return parent

    def getInodeList(self, start=None, path=None, filters=[], verb=False):
        # define traverse function #
        def _traverseItems(self, start, path, filters, verb):
            if start:
                if type(start) is str:
                    path = start.strip()
                    parent = self.volume.root
                    for item in start.split("/"):
                        if not item:
                            continue
                        parent = parent.get_inode(item)
                    start = parent
            else:
                start = self.volume.root
                path = "/"

            # print progress #
            UtilMgr.printProgress()

            # open directory #
            FILE_TYPE = Ext4Analyzer.FILE_TYPE
            try:
                dirnode = start.open_dir(path=path)
                if not dirnode:
                    self.failDirList.setdefault(path, None)
            except SystemExit:
                sys.exit(0)
            except:
                self.failDirList.setdefault(path, None)
                SysMgr.printWarn("failed to open '%s' directory" % None, True)
                return

            # traverse all items #
            for fname, inode, ftype in dirnode:
                if fname == "." or fname == "..":
                    continue
                elif inode in self.inodeList:
                    continue

                # define attribute #
                ftype = FILE_TYPE[ftype] if ftype in FILE_TYPE else "?"
                inodeObj = self.volume.get_inode(inode)
                fpath = os.path.join(path, fname)

                # check condition #
                if not UtilMgr.isValidStr(
                    str(inode), filters
                ) and not UtilMgr.isValidStr(fpath, filters):
                    pass
                else:
                    self.inodeList[inode] = {
                        "name": fname,
                        "type": ftype,
                        "size": len(inodeObj),
                        "path": path,
                    }

                    if verb:
                        SysMgr.printWarn(
                            "%s [inode: %s] [type: %s] [size: %s]"
                            % (
                                fpath,
                                inode,
                                ftype,
                                UtilMgr.convSize2Unit(len(inodeObj)),
                            ),
                            always=True,
                            newline=False,
                        )

                if ftype == "dir":
                    _traverseItems(self, inodeObj, fpath, filters, verb)
                    continue

        # start traversing all items #
        _traverseItems(self, start, path, filters, verb)

        # return inode list #
        return self.inodeList


'''
class GlMgr(object):
    """Manager for GL"""

    instance = None

    @staticmethod
    def init():
        SysMgr.importPkgItems("ctypes")

        try:
            # load libglesobj library #
            if not SysMgr.libglesObj:
                SysMgr.libglesObj = SysMgr.loadLib(SysMgr.libglesPath)
        except:
            SysMgr.printErr("failed to load GLES object")
            sys.exit(-1)

        gl = GlMgr.instance = SysMgr.libglesObj
        gl.glActiveShaderProgram.argtypes = [c_uint32, c_uint32]
        gl.glActiveShaderProgram.restype = None
        gl.glActiveTexture.argtypes = [c_uint]
        gl.glActiveTexture.restype = None
        gl.glAttachShader.argtypes = [c_uint32, c_uint32]
        gl.glAttachShader.restype = None
        gl.glBeginQuery.argtypes = [c_uint, c_uint32]
        gl.glBeginQuery.restype = None
        gl.glBeginTransformFeedback.argtypes = [c_uint]
        gl.glBeginTransformFeedback.restype = None
        gl.glBindAttribLocation.argtypes = [
            c_uint32,
            c_uint32,
            POINTER(c_char),
        ]
        gl.glBindAttribLocation.restype = None
        gl.glBindBuffer.argtypes = [c_uint, c_uint32]
        gl.glBindBuffer.restype = None
        gl.glBindBufferBase.argtypes = [c_uint, c_uint32, c_uint32]
        gl.glBindBufferBase.restype = None
        gl.glBindBufferRange.argtypes = [
            c_uint,
            c_uint32,
            c_uint32,
            c_size_t,
            c_ssize_t,
        ]
        gl.glBindBufferRange.restype = None
        gl.glBindFramebuffer.argtypes = [c_uint, c_uint32]
        gl.glBindFramebuffer.restype = None
        gl.glBindImageTexture.argtypes = [
            c_uint32,
            c_uint32,
            c_int32,
            c_ubyte,
            c_int32,
            c_uint,
            c_uint,
        ]
        gl.glBindImageTexture.restype = None
        gl.glBindProgramPipeline.argtypes = [c_uint32]
        gl.glBindProgramPipeline.restype = None
        gl.glBindRenderbuffer.argtypes = [c_uint, c_uint32]
        gl.glBindRenderbuffer.restype = None
        gl.glBindSampler.argtypes = [c_uint32, c_uint32]
        gl.glBindSampler.restype = None
        gl.glBindTexture.argtypes = [c_uint, c_uint]
        gl.glBindTexture.restype = None
        gl.glBindTransformFeedback.argtypes = [c_uint, c_uint32]
        gl.glBindTransformFeedback.restype = None
        gl.glBindVertexArray.argtypes = [c_uint32]
        gl.glBindVertexArray.restype = None
        gl.glBindVertexBuffer.argtypes = [
            c_uint32,
            c_uint32,
            c_size_t,
            c_size_t,
        ]
        gl.glBindVertexBuffer.restype = None
        gl.glBlendColor.argtypes = [c_float, c_float, c_float, c_float]
        gl.glBlendColor.restype = None
        gl.glBlendEquation.argtypes = [c_uint]
        gl.glBlendEquation.restype = None
        gl.glBlendEquationSeparate.argtypes = [c_uint, c_uint]
        gl.glBlendEquationSeparate.restype = None
        gl.glBlendEquationSeparatei.argtypes = [c_uint32, c_uint, c_uint]
        gl.glBlendEquationSeparatei.restype = None
        gl.glBlendEquationi.argtypes = [c_uint32, c_uint]
        gl.glBlendEquationi.restype = None
        gl.glBlendFunc.argtypes = [c_uint, c_uint]
        gl.glBlendFunc.restype = None
        gl.glBlendFuncSeparate.argtypes = [c_uint, c_uint, c_uint, c_uint]
        gl.glBlendFuncSeparate.restype = None
        gl.glBlendFuncSeparatei.argtypes = [
            c_uint32,
            c_uint,
            c_uint,
            c_uint,
            c_uint,
        ]
        gl.glBlendFuncSeparatei.restype = None
        gl.glBlendFunci.argtypes = [c_uint32, c_uint, c_uint]
        gl.glBlendFunci.restype = None
        gl.glBlitFramebuffer.argtypes = [
            c_int32,
            c_int32,
            c_int32,
            c_int32,
            c_int32,
            c_int32,
            c_int32,
            c_int32,
            c_uint,
            c_uint,
        ]
        gl.glBlitFramebuffer.restype = None
        gl.glBufferData.argtypes = [c_uint, c_ssize_t, c_void_p, c_uint]
        gl.glBufferData.restype = None
        gl.glBufferSubData.argtypes = [c_uint, c_size_t, c_ssize_t, c_void_p]
        gl.glBufferSubData.restype = None
        gl.glCheckFramebufferStatus.argtypes = [c_uint]
        gl.glCheckFramebufferStatus.restype = c_uint
        gl.glClear.argtypes = [c_uint]
        gl.glClear.restype = None
        gl.glClearBufferfi.argtypes = [c_uint, c_int, c_float, c_int32]
        gl.glClearBufferfi.restype = None
        gl.glClearBufferfv.argtypes = [c_uint, c_int, POINTER(c_float)]
        gl.glClearBufferfv.restype = None
        gl.glClearBufferiv.argtypes = [c_uint, c_int, POINTER(c_int32)]
        gl.glClearBufferiv.restype = None
        gl.glClearBufferuiv.argtypes = [c_uint, c_int, POINTER(c_uint32)]
        gl.glClearBufferuiv.restype = None
        gl.glClearColor.argtypes = [c_float, c_float, c_float, c_float]
        gl.glClearColor.restype = None
        gl.glClearDepthf.argtypes = [c_float]
        gl.glClearDepthf.restype = None
        gl.glClearStencil.argtypes = [c_int]
        gl.glClearStencil.restype = None
        gl.glColorMask.argtypes = [c_ubyte, c_ubyte, c_ubyte, c_ubyte]
        gl.glColorMask.restype = None
        gl.glColorMaski.argtypes = [
            c_uint32,
            c_ubyte,
            c_ubyte,
            c_ubyte,
            c_ubyte,
        ]
        gl.glColorMaski.restype = None
        gl.glCompileShader.argtypes = [c_uint32]
        gl.glCompileShader.restype = None
        gl.glCompressedTexImage2D.argtypes = [
            c_uint,
            c_long,
            c_uint,
            c_size_t,
            c_size_t,
            c_long,
            c_size_t,
            c_void_p,
        ]
        gl.glCompressedTexImage2D.restype = None
        gl.glCompressedTexImage3D.argtypes = [
            c_uint,
            c_long,
            c_uint,
            c_size_t,
            c_size_t,
            c_size_t,
            c_long,
            c_size_t,
            c_void_p,
        ]
        gl.glCompressedTexImage3D.restype = None
        gl.glCompressedTexSubImage2D.argtypes = [
            c_uint,
            c_long,
            c_long,
            c_long,
            c_size_t,
            c_size_t,
            c_uint,
            c_size_t,
            c_void_p,
        ]
        gl.glCompressedTexSubImage2D.restype = None
        gl.glCompressedTexSubImage3D.argtypes = [
            c_uint,
            c_long,
            c_long,
            c_long,
            c_long,
            c_size_t,
            c_size_t,
            c_size_t,
            c_uint,
            c_size_t,
            c_void_p,
        ]
        gl.glCompressedTexSubImage3D.restype = None
        gl.glCopyBufferSubData.argtypes = [
            c_uint,
            c_uint,
            c_size_t,
            c_size_t,
            c_ssize_t,
        ]
        gl.glCopyBufferSubData.restype = None
        gl.glCopyImageSubData.argtypes = [
            c_uint32,
            c_uint,
            c_int32,
            c_int32,
            c_int32,
            c_int32,
            c_uint32,
            c_uint,
            c_int32,
            c_int32,
            c_int32,
            c_int32,
            c_size_t,
            c_size_t,
            c_size_t,
        ]
        gl.glCopyImageSubData.restype = None
        gl.glCopyTexImage2D.argtypes = [
            c_uint,
            c_long,
            c_uint,
            c_int,
            c_int,
            c_size_t,
            c_size_t,
            c_long,
        ]
        gl.glCopyTexImage2D.restype = None
        gl.glCopyTexSubImage2D.argtypes = [
            c_uint,
            c_long,
            c_long,
            c_long,
            c_int,
            c_int,
            c_size_t,
            c_size_t,
        ]
        gl.glCopyTexSubImage2D.restype = None
        gl.glCopyTexSubImage3D.argtypes = [
            c_uint,
            c_long,
            c_long,
            c_long,
            c_long,
            c_int,
            c_int,
            c_size_t,
            c_size_t,
        ]
        gl.glCopyTexSubImage3D.restype = None
        gl.glCreateProgram.argtypes = None
        gl.glCreateProgram.restype = c_uint32
        gl.glCreateShader.argtypes = [c_uint]
        gl.glCreateShader.restype = c_uint32
        gl.glCreateShaderProgramv.argtypes = [
            c_uint,
            c_size_t,
            POINTER(c_char_p),
        ]
        gl.glCreateShaderProgramv.restype = c_uint32
        gl.glCullFace.argtypes = [c_uint]
        gl.glCullFace.restype = None
        gl.glDebugMessageControl.argtypes = [
            c_uint,
            c_uint,
            c_uint,
            c_size_t,
            POINTER(c_uint32),
            c_ubyte,
        ]
        gl.glDebugMessageControl.restype = None
        gl.glDebugMessageInsert.argtypes = [
            c_uint,
            c_uint,
            c_uint32,
            c_uint,
            c_size_t,
            POINTER(c_char),
        ]
        gl.glDebugMessageInsert.restype = None
        gl.glDeleteBuffers.argtypes = [c_size_t, POINTER(c_ulong)]
        gl.glDeleteBuffers.restype = None
        gl.glDeleteFramebuffers.argtypes = [c_size_t, POINTER(c_uint32)]
        gl.glDeleteFramebuffers.restype = None
        gl.glDeleteProgram.argtypes = [c_uint32]
        gl.glDeleteProgram.restype = None
        gl.glDeleteProgramPipelines.argtypes = [c_size_t, POINTER(c_uint32)]
        gl.glDeleteProgramPipelines.restype = None
        gl.glDeleteQueries.argtypes = [c_size_t, POINTER(c_uint32)]
        gl.glDeleteQueries.restype = None
        gl.glDeleteRenderbuffers.argtypes = [c_size_t, POINTER(c_uint32)]
        gl.glDeleteRenderbuffers.restype = None
        gl.glDeleteSamplers.argtypes = [c_size_t, POINTER(c_uint32)]
        gl.glDeleteSamplers.restype = None
        gl.glDeleteShader.argtypes = [c_uint32]
        gl.glDeleteShader.restype = None
        gl.glDeleteTextures.argtypes = [c_size_t, POINTER(c_uint)]
        gl.glDeleteTextures.restype = None
        gl.glDeleteTransformFeedbacks.argtypes = [c_size_t, POINTER(c_uint32)]
        gl.glDeleteTransformFeedbacks.restype = None
        gl.glDeleteVertexArrays.argtypes = [c_size_t, POINTER(c_uint32)]
        gl.glDeleteVertexArrays.restype = None
        gl.glDepthFunc.argtypes = [c_uint]
        gl.glDepthFunc.restype = None
        gl.glDepthMask.argtypes = [c_ubyte]
        gl.glDepthMask.restype = None
        gl.glDepthRangef.argtypes = [c_float, c_float]
        gl.glDepthRangef.restype = None
        gl.glDetachShader.argtypes = [c_uint32, c_uint32]
        gl.glDetachShader.restype = None
        gl.glDisable.argtypes = [c_uint]
        gl.glDisable.restype = None
        gl.glDisableVertexAttribArray.argtypes = [c_uint32]
        gl.glDisableVertexAttribArray.restype = None
        gl.glDisablei.argtypes = [c_uint, c_uint32]
        gl.glDisablei.restype = None
        gl.glDispatchCompute.argtypes = [c_uint32, c_uint32, c_uint32]
        gl.glDispatchCompute.restype = None
        gl.glDispatchComputeIndirect.argtypes = [c_size_t]
        gl.glDispatchComputeIndirect.restype = None
        gl.glDrawArrays.argtypes = [c_uint, c_int32, c_size_t]
        gl.glDrawArrays.restype = None
        gl.glDrawArraysIndirect.argtypes = [c_uint, c_void_p]
        gl.glDrawArraysIndirect.restype = None
        gl.glDrawArraysInstanced.argtypes = [
            c_uint,
            c_int32,
            c_size_t,
            c_size_t,
        ]
        gl.glDrawArraysInstanced.restype = None
        gl.glDrawBuffers.argtypes = [c_size_t, POINTER(c_uint)]
        gl.glDrawBuffers.restype = None
        gl.glDrawElements.argtypes = [c_uint, c_size_t, c_uint, c_void_p]
        gl.glDrawElements.restype = None
        gl.glDrawElementsBaseVertex.argtypes = [
            c_uint,
            c_size_t,
            c_uint,
            c_void_p,
            c_int32,
        ]
        gl.glDrawElementsBaseVertex.restype = None
        gl.glDrawElementsIndirect.argtypes = [c_uint, c_uint, c_void_p]
        gl.glDrawElementsIndirect.restype = None
        gl.glDrawElementsInstanced.argtypes = [
            c_uint,
            c_size_t,
            c_uint,
            c_void_p,
            c_size_t,
        ]
        gl.glDrawElementsInstanced.restype = None
        gl.glDrawElementsInstancedBaseVertex.argtypes = [
            c_uint,
            c_size_t,
            c_uint,
            c_void_p,
            c_size_t,
            c_int32,
        ]
        gl.glDrawElementsInstancedBaseVertex.restype = None
        gl.glDrawRangeElements.argtypes = [
            c_uint,
            c_uint32,
            c_uint32,
            c_size_t,
            c_uint,
            c_void_p,
        ]
        gl.glDrawRangeElements.restype = None
        gl.glDrawRangeElementsBaseVertex.argtypes = [
            c_uint,
            c_uint32,
            c_uint32,
            c_size_t,
            c_uint,
            c_void_p,
            c_int32,
        ]
        gl.glDrawRangeElementsBaseVertex.restype = None
        gl.glEnable.argtypes = [c_uint]
        gl.glEnable.restype = None
        gl.glEnableVertexAttribArray.argtypes = [c_uint32]
        gl.glEnableVertexAttribArray.restype = None
        gl.glEnablei.argtypes = [c_uint, c_uint32]
        gl.glEnablei.restype = None
        gl.glEndQuery.argtypes = [c_uint]
        gl.glEndQuery.restype = None
        gl.glEndTransformFeedback.argtypes = None
        gl.glEndTransformFeedback.restype = None
        gl.glFinish.argtypes = None
        gl.glFinish.restype = None
        gl.glFlush.argtypes = None
        gl.glFlush.restype = None
        gl.glFlushMappedBufferRange.argtypes = [c_uint, c_size_t, c_ssize_t]
        gl.glFlushMappedBufferRange.restype = None
        gl.glFramebufferParameteri.argtypes = [c_uint, c_uint, c_int32]
        gl.glFramebufferParameteri.restype = None
        gl.glFramebufferRenderbuffer.argtypes = [
            c_uint,
            c_uint,
            c_uint,
            c_uint32,
        ]
        gl.glFramebufferRenderbuffer.restype = None
        gl.glFramebufferTexture.argtypes = [c_uint, c_uint, c_uint32, c_int32]
        gl.glFramebufferTexture.restype = None
        gl.glFramebufferTexture2D.argtypes = [
            c_uint,
            c_uint,
            c_uint,
            c_uint32,
            c_int32,
        ]
        gl.glFramebufferTexture2D.restype = None
        gl.glFramebufferTextureLayer.argtypes = [
            c_uint,
            c_uint,
            c_uint,
            c_long,
            c_long,
        ]
        gl.glFramebufferTextureLayer.restype = None
        gl.glFrontFace.argtypes = [c_uint]
        gl.glFrontFace.restype = None
        gl.glGenBuffers.argtypes = [c_size_t, POINTER(c_uint32)]
        gl.glGenBuffers.restype = None
        gl.glGenFramebuffers.argtypes = [c_size_t, POINTER(c_uint32)]
        gl.glGenFramebuffers.restype = None
        gl.glGenProgramPipelines.argtypes = [c_size_t, POINTER(c_uint32)]
        gl.glGenProgramPipelines.restype = None
        gl.glGenQueries.argtypes = [c_size_t, POINTER(c_uint32)]
        gl.glGenQueries.restype = None
        gl.glGenRenderbuffers.argtypes = [c_size_t, POINTER(c_uint32)]
        gl.glGenRenderbuffers.restype = None
        gl.glGenSamplers.argtypes = [c_size_t, POINTER(c_uint32)]
        gl.glGenSamplers.restype = None
        gl.glGenTextures.argtypes = [c_size_t, POINTER(c_uint)]
        gl.glGenTextures.restype = None
        gl.glGenTransformFeedbacks.argtypes = [c_size_t, POINTER(c_uint32)]
        gl.glGenTransformFeedbacks.restype = None
        gl.glGenVertexArrays.argtypes = [c_size_t, POINTER(c_uint32)]
        gl.glGenVertexArrays.restype = None
        gl.glGenerateMipmap.argtypes = [c_uint]
        gl.glGenerateMipmap.restype = None
        gl.glGetActiveAttrib.argtypes = [
            c_uint32,
            c_uint32,
            c_size_t,
            POINTER(c_size_t),
            POINTER(c_int32),
            POINTER(c_uint),
            POINTER(c_char),
        ]
        gl.glGetActiveAttrib.restype = None
        gl.glGetActiveUniform.argtypes = [
            c_uint32,
            c_uint32,
            c_size_t,
            POINTER(c_size_t),
            POINTER(c_int32),
            POINTER(c_uint),
            POINTER(c_char),
        ]
        gl.glGetActiveUniform.restype = None
        gl.glGetActiveUniformBlockName.argtypes = [
            c_uint32,
            c_uint32,
            c_size_t,
            POINTER(c_size_t),
            POINTER(c_char),
        ]
        gl.glGetActiveUniformBlockName.restype = None
        gl.glGetActiveUniformBlockiv.argtypes = [
            c_uint32,
            c_uint32,
            c_uint,
            POINTER(c_int32),
        ]
        gl.glGetActiveUniformBlockiv.restype = None
        gl.glGetActiveUniformsiv.argtypes = [
            c_uint32,
            c_size_t,
            POINTER(c_uint32),
            c_uint,
            POINTER(c_int32),
        ]
        gl.glGetActiveUniformsiv.restype = None
        gl.glGetAttachedShaders.argtypes = [
            c_uint32,
            c_size_t,
            POINTER(c_size_t),
            POINTER(c_uint32),
        ]
        gl.glGetAttachedShaders.restype = None
        gl.glGetAttribLocation.argtypes = [c_uint32, POINTER(c_char)]
        gl.glGetAttribLocation.restype = c_int32
        gl.glGetBooleanv.argtypes = [c_uint, POINTER(c_ubyte)]
        gl.glGetBooleanv.restype = None
        gl.glGetBufferParameteri64v.argtypes = [
            c_uint,
            c_uint,
            POINTER(c_int64),
        ]
        gl.glGetBufferParameteri64v.restype = None
        gl.glGetBufferParameteriv.argtypes = [c_uint, c_uint, POINTER(c_int32)]
        gl.glGetBufferParameteriv.restype = None
        gl.glGetBufferPointerv.argtypes = [c_uint, c_uint, POINTER(c_void_p)]
        gl.glGetBufferPointerv.restype = None
        gl.glGetDebugMessageLog.argtypes = [
            c_uint32,
            c_size_t,
            POINTER(c_uint),
            POINTER(c_uint),
            POINTER(c_uint32),
            POINTER(c_uint),
            POINTER(c_size_t),
            POINTER(c_char),
        ]
        gl.glGetDebugMessageLog.restype = c_uint32
        gl.glGetError.argtypes = None
        gl.glGetError.restype = c_uint
        gl.glGetFloatv.argtypes = [c_uint, POINTER(c_float)]
        gl.glGetFloatv.restype = None
        gl.glGetFragDataLocation.argtypes = [c_uint32, POINTER(c_char)]
        gl.glGetFragDataLocation.restype = c_int32
        gl.glGetFramebufferAttachmentParameteriv.argtypes = [
            c_uint,
            c_uint,
            c_uint,
            POINTER(c_int32),
        ]
        gl.glGetFramebufferAttachmentParameteriv.restype = None
        gl.glGetFramebufferParameteriv.argtypes = [
            c_uint,
            c_uint,
            POINTER(c_int32),
        ]
        gl.glGetFramebufferParameteriv.restype = None
        gl.glGetInteger64v.argtypes = [c_uint, POINTER(c_int64)]
        gl.glGetInteger64v.restype = None
        gl.glGetIntegerv.argtypes = [c_uint, POINTER(c_int32)]
        gl.glGetIntegerv.restype = None
        gl.glGetInternalformativ.argtypes = [
            c_uint,
            c_uint,
            c_uint,
            c_size_t,
            POINTER(c_int32),
        ]
        gl.glGetInternalformativ.restype = None
        gl.glGetMultisamplefv.argtypes = [c_uint, c_uint32, POINTER(c_float)]
        gl.glGetMultisamplefv.restype = None
        gl.glGetObjectLabel.argtypes = [
            c_uint,
            c_uint32,
            c_size_t,
            POINTER(c_size_t),
            POINTER(c_char),
        ]
        gl.glGetObjectLabel.restype = None
        gl.glGetObjectPtrLabel.argtypes = [
            c_void_p,
            c_size_t,
            POINTER(c_size_t),
            POINTER(c_char),
        ]
        gl.glGetObjectPtrLabel.restype = None
        gl.glGetPointerv.argtypes = [c_uint, POINTER(c_void_p)]
        gl.glGetPointerv.restype = None
        gl.glGetProgramBinary.argtypes = [
            c_uint32,
            c_size_t,
            POINTER(c_size_t),
            POINTER(c_uint),
            c_void_p,
        ]
        gl.glGetProgramBinary.restype = None
        gl.glGetProgramInfoLog.argtypes = [
            c_uint32,
            c_size_t,
            POINTER(c_size_t),
            POINTER(c_char),
        ]
        gl.glGetProgramInfoLog.restype = None
        gl.glGetProgramInterfaceiv.argtypes = [
            c_uint32,
            c_uint,
            c_uint,
            POINTER(c_int32),
        ]
        gl.glGetProgramInterfaceiv.restype = None
        gl.glGetProgramPipelineInfoLog.argtypes = [
            c_uint32,
            c_size_t,
            POINTER(c_size_t),
            POINTER(c_char),
        ]
        gl.glGetProgramPipelineInfoLog.restype = None
        gl.glGetProgramPipelineiv.argtypes = [
            c_uint32,
            c_uint,
            POINTER(c_int32),
        ]
        gl.glGetProgramPipelineiv.restype = None
        gl.glGetProgramResourceIndex.argtypes = [
            c_uint32,
            c_uint,
            POINTER(c_char),
        ]
        gl.glGetProgramResourceIndex.restype = c_uint32
        gl.glGetProgramResourceLocation.argtypes = [
            c_uint32,
            c_uint,
            POINTER(c_char),
        ]
        gl.glGetProgramResourceLocation.restype = c_int32
        gl.glGetProgramResourceName.argtypes = [
            c_uint32,
            c_uint,
            c_uint32,
            c_size_t,
            POINTER(c_size_t),
            POINTER(c_char),
        ]
        gl.glGetProgramResourceName.restype = None
        gl.glGetProgramResourceiv.argtypes = [
            c_uint32,
            c_uint,
            c_uint32,
            c_size_t,
            POINTER(c_uint),
            c_size_t,
            POINTER(c_size_t),
            POINTER(c_int32),
        ]
        gl.glGetProgramResourceiv.restype = None
        gl.glGetProgramiv.argtypes = [c_uint32, c_uint, POINTER(c_int32)]
        gl.glGetProgramiv.restype = None
        gl.glGetQueryObjectuiv.argtypes = [c_uint32, c_uint, POINTER(c_uint32)]
        gl.glGetQueryObjectuiv.restype = None
        gl.glGetQueryiv.argtypes = [c_uint, c_uint, POINTER(c_int32)]
        gl.glGetQueryiv.restype = None
        gl.glGetRenderbufferParameteriv.argtypes = [
            c_uint,
            c_uint,
            POINTER(c_int32),
        ]
        gl.glGetRenderbufferParameteriv.restype = None
        gl.glGetSamplerParameterIiv.argtypes = [
            c_uint32,
            c_uint,
            POINTER(c_int32),
        ]
        gl.glGetSamplerParameterIiv.restype = None
        gl.glGetSamplerParameterIuiv.argtypes = [
            c_uint32,
            c_uint,
            POINTER(c_uint32),
        ]
        gl.glGetSamplerParameterIuiv.restype = None
        gl.glGetSamplerParameterfv.argtypes = [
            c_uint32,
            c_uint,
            POINTER(c_float),
        ]
        gl.glGetSamplerParameterfv.restype = None
        gl.glGetSamplerParameteriv.argtypes = [
            c_uint32,
            c_uint,
            POINTER(c_int32),
        ]
        gl.glGetSamplerParameteriv.restype = None
        gl.glGetShaderInfoLog.argtypes = [
            c_uint32,
            c_size_t,
            POINTER(c_size_t),
            POINTER(c_char),
        ]
        gl.glGetShaderInfoLog.restype = None
        gl.glGetShaderPrecisionFormat.argtypes = [
            c_uint,
            c_uint,
            POINTER(c_int32),
            POINTER(c_int32),
        ]
        gl.glGetShaderPrecisionFormat.restype = None
        gl.glGetShaderSource.argtypes = [
            c_uint32,
            c_size_t,
            POINTER(c_size_t),
            POINTER(c_char),
        ]
        gl.glGetShaderSource.restype = None
        gl.glGetShaderiv.argtypes = [c_uint32, c_uint, POINTER(c_int32)]
        gl.glGetShaderiv.restype = None
        gl.glGetString.argtypes = [c_uint]
        gl.glGetString.restype = c_char_p
        gl.glGetStringi.argtypes = [c_uint, c_uint32]
        gl.glGetStringi.restype = c_char_p
        gl.glGetTexLevelParameterfv.argtypes = [
            c_uint,
            c_long,
            c_uint,
            POINTER(c_float),
        ]
        gl.glGetTexLevelParameterfv.restype = None
        gl.glGetTexLevelParameteriv.argtypes = [
            c_uint,
            c_long,
            c_uint,
            POINTER(c_int32),
        ]
        gl.glGetTexLevelParameteriv.restype = None
        gl.glGetTexParameterIiv.argtypes = [c_uint, c_uint, POINTER(c_int32)]
        gl.glGetTexParameterIiv.restype = None
        gl.glGetTexParameterIuiv.argtypes = [c_uint, c_uint, POINTER(c_uint32)]
        gl.glGetTexParameterIuiv.restype = None
        gl.glGetTexParameterfv.argtypes = [c_uint, c_uint, POINTER(c_float)]
        gl.glGetTexParameterfv.restype = None
        gl.glGetTexParameteriv.argtypes = [c_uint, c_uint, POINTER(c_int32)]
        gl.glGetTexParameteriv.restype = None
        gl.glGetTransformFeedbackVarying.argtypes = [
            c_uint32,
            c_uint32,
            c_size_t,
            POINTER(c_size_t),
            POINTER(c_size_t),
            POINTER(c_uint),
            POINTER(c_char),
        ]
        gl.glGetTransformFeedbackVarying.restype = None
        gl.glGetUniformBlockIndex.argtypes = [c_uint32, POINTER(c_char)]
        gl.glGetUniformBlockIndex.restype = c_uint32
        gl.glGetUniformIndices.argtypes = [
            c_uint32,
            c_size_t,
            POINTER(c_char_p),
            POINTER(c_uint32),
        ]
        gl.glGetUniformIndices.restype = None
        gl.glGetUniformLocation.argtypes = [c_uint32, POINTER(c_char)]
        gl.glGetUniformLocation.restype = c_int32
        gl.glGetUniformfv.argtypes = [c_uint32, c_int32, POINTER(c_float)]
        gl.glGetUniformfv.restype = None
        gl.glGetUniformiv.argtypes = [c_uint32, c_int32, POINTER(c_int32)]
        gl.glGetUniformiv.restype = None
        gl.glGetUniformuiv.argtypes = [c_uint32, c_int32, POINTER(c_uint32)]
        gl.glGetUniformuiv.restype = None
        gl.glGetVertexAttribIiv.argtypes = [c_uint32, c_uint, POINTER(c_int32)]
        gl.glGetVertexAttribIiv.restype = None
        gl.glGetVertexAttribIuiv.argtypes = [
            c_uint32,
            c_uint,
            POINTER(c_uint32),
        ]
        gl.glGetVertexAttribIuiv.restype = None
        gl.glGetVertexAttribPointerv.argtypes = [
            c_uint32,
            c_uint,
            POINTER(c_void_p),
        ]
        gl.glGetVertexAttribPointerv.restype = None
        gl.glGetVertexAttribfv.argtypes = [c_uint32, c_uint, POINTER(c_float)]
        gl.glGetVertexAttribfv.restype = None
        gl.glGetVertexAttribiv.argtypes = [c_uint32, c_uint, POINTER(c_int32)]
        gl.glGetVertexAttribiv.restype = None
        gl.glHint.argtypes = [c_uint, c_uint]
        gl.glHint.restype = None
        gl.glInvalidateFramebuffer.argtypes = [
            c_uint,
            c_size_t,
            POINTER(c_uint),
        ]
        gl.glInvalidateFramebuffer.restype = None
        gl.glInvalidateSubFramebuffer.argtypes = [
            c_uint,
            c_size_t,
            POINTER(c_uint),
            c_int32,
            c_int32,
            c_size_t,
            c_size_t,
        ]
        gl.glInvalidateSubFramebuffer.restype = None
        gl.glIsBuffer.argtypes = [c_uint32]
        gl.glIsBuffer.restype = c_ubyte
        gl.glIsEnabled.argtypes = [c_uint]
        gl.glIsEnabled.restype = c_ubyte
        gl.glIsEnabledi.argtypes = [c_uint, c_uint32]
        gl.glIsEnabledi.restype = c_ubyte
        gl.glIsFramebuffer.argtypes = [c_uint32]
        gl.glIsFramebuffer.restype = c_ubyte
        gl.glIsProgram.argtypes = [c_uint32]
        gl.glIsProgram.restype = c_ubyte
        gl.glIsProgramPipeline.argtypes = [c_uint32]
        gl.glIsProgramPipeline.restype = c_ubyte
        gl.glIsQuery.argtypes = [c_uint32]
        gl.glIsQuery.restype = c_ubyte
        gl.glIsRenderbuffer.argtypes = [c_uint32]
        gl.glIsRenderbuffer.restype = c_ubyte
        gl.glIsSampler.argtypes = [c_uint32]
        gl.glIsSampler.restype = c_ubyte
        gl.glIsShader.argtypes = [c_uint32]
        gl.glIsShader.restype = c_ubyte
        gl.glIsTexture.argtypes = [c_uint]
        gl.glIsTexture.restype = c_ubyte
        gl.glIsTransformFeedback.argtypes = [c_uint32]
        gl.glIsTransformFeedback.restype = c_ubyte
        gl.glIsVertexArray.argtypes = [c_uint32]
        gl.glIsVertexArray.restype = c_ubyte
        gl.glLineWidth.argtypes = [c_float]
        gl.glLineWidth.restype = None
        gl.glLinkProgram.argtypes = [c_uint32]
        gl.glLinkProgram.restype = None
        gl.glMapBufferRange.argtypes = [c_uint, c_size_t, c_ssize_t, c_uint]
        gl.glMapBufferRange.restype = c_void_p
        gl.glMemoryBarrier.argtypes = [c_uint]
        gl.glMemoryBarrier.restype = None
        gl.glMinSampleShading.argtypes = [c_float]
        gl.glMinSampleShading.restype = None
        gl.glObjectLabel.argtypes = [
            c_uint,
            c_uint32,
            c_size_t,
            POINTER(c_char),
        ]
        gl.glObjectLabel.restype = None
        gl.glObjectPtrLabel.argtypes = [c_void_p, c_size_t, POINTER(c_char)]
        gl.glObjectPtrLabel.restype = None
        gl.glPatchParameteri.argtypes = [c_uint, c_int32]
        gl.glPatchParameteri.restype = None
        gl.glPauseTransformFeedback.argtypes = None
        gl.glPauseTransformFeedback.restype = None
        gl.glPixelStorei.argtypes = [c_uint, c_long]
        gl.glPixelStorei.restype = None
        gl.glPolygonOffset.argtypes = [c_float, c_float]
        gl.glPolygonOffset.restype = None
        gl.glPopDebugGroup.argtypes = None
        gl.glPopDebugGroup.restype = None
        gl.glProgramBinary.argtypes = [c_uint32, c_uint, c_void_p, c_size_t]
        gl.glProgramBinary.restype = None
        gl.glProgramParameteri.argtypes = [c_uint32, c_uint, c_int32]
        gl.glProgramParameteri.restype = None
        gl.glProgramUniform1f.argtypes = [c_uint32, c_int32, c_float]
        gl.glProgramUniform1f.restype = None
        gl.glProgramUniform1fv.argtypes = [
            c_uint32,
            c_int32,
            c_size_t,
            POINTER(c_float),
        ]
        gl.glProgramUniform1fv.restype = None
        gl.glProgramUniform1i.argtypes = [c_uint32, c_int32, c_int32]
        gl.glProgramUniform1i.restype = None
        gl.glProgramUniform1iv.argtypes = [
            c_uint32,
            c_int32,
            c_size_t,
            POINTER(c_int32),
        ]
        gl.glProgramUniform1iv.restype = None
        gl.glProgramUniform1ui.argtypes = [c_uint32, c_int32, c_uint32]
        gl.glProgramUniform1ui.restype = None
        gl.glProgramUniform1uiv.argtypes = [
            c_uint32,
            c_int32,
            c_size_t,
            POINTER(c_uint32),
        ]
        gl.glProgramUniform1uiv.restype = None
        gl.glProgramUniform2f.argtypes = [c_uint32, c_int32, c_float, c_float]
        gl.glProgramUniform2f.restype = None
        gl.glProgramUniform2fv.argtypes = [
            c_uint32,
            c_int32,
            c_size_t,
            POINTER(c_float),
        ]
        gl.glProgramUniform2fv.restype = None
        gl.glProgramUniform2i.argtypes = [c_uint32, c_int32, c_int32, c_int32]
        gl.glProgramUniform2i.restype = None
        gl.glProgramUniform2iv.argtypes = [
            c_uint32,
            c_int32,
            c_size_t,
            POINTER(c_int32),
        ]
        gl.glProgramUniform2iv.restype = None
        gl.glProgramUniform2ui.argtypes = [
            c_uint32,
            c_int32,
            c_uint32,
            c_uint32,
        ]
        gl.glProgramUniform2ui.restype = None
        gl.glProgramUniform2uiv.argtypes = [
            c_uint32,
            c_int32,
            c_size_t,
            POINTER(c_uint32),
        ]
        gl.glProgramUniform2uiv.restype = None
        gl.glProgramUniform3f.argtypes = [
            c_uint32,
            c_int32,
            c_float,
            c_float,
            c_float,
        ]
        gl.glProgramUniform3f.restype = None
        gl.glProgramUniform3fv.argtypes = [
            c_uint32,
            c_int32,
            c_size_t,
            POINTER(c_float),
        ]
        gl.glProgramUniform3fv.restype = None
        gl.glProgramUniform3i.argtypes = [
            c_uint32,
            c_int32,
            c_int32,
            c_int32,
            c_int32,
        ]
        gl.glProgramUniform3i.restype = None
        gl.glProgramUniform3iv.argtypes = [
            c_uint32,
            c_int32,
            c_size_t,
            POINTER(c_int32),
        ]
        gl.glProgramUniform3iv.restype = None
        gl.glProgramUniform3ui.argtypes = [
            c_uint32,
            c_int32,
            c_uint32,
            c_uint32,
            c_uint32,
        ]
        gl.glProgramUniform3ui.restype = None
        gl.glProgramUniform3uiv.argtypes = [
            c_uint32,
            c_int32,
            c_size_t,
            POINTER(c_uint32),
        ]
        gl.glProgramUniform3uiv.restype = None
        gl.glProgramUniform4f.argtypes = [
            c_uint32,
            c_int32,
            c_float,
            c_float,
            c_float,
            c_float,
        ]
        gl.glProgramUniform4f.restype = None
        gl.glProgramUniform4fv.argtypes = [
            c_uint32,
            c_int32,
            c_size_t,
            POINTER(c_float),
        ]
        gl.glProgramUniform4fv.restype = None
        gl.glProgramUniform4i.argtypes = [
            c_uint32,
            c_int32,
            c_int32,
            c_int32,
            c_int32,
            c_int32,
        ]
        gl.glProgramUniform4i.restype = None
        gl.glProgramUniform4iv.argtypes = [
            c_uint32,
            c_int32,
            c_size_t,
            POINTER(c_int32),
        ]
        gl.glProgramUniform4iv.restype = None
        gl.glProgramUniform4ui.argtypes = [
            c_uint32,
            c_int32,
            c_uint32,
            c_uint32,
            c_uint32,
            c_uint32,
        ]
        gl.glProgramUniform4ui.restype = None
        gl.glProgramUniform4uiv.argtypes = [
            c_uint32,
            c_int32,
            c_size_t,
            POINTER(c_uint32),
        ]
        gl.glProgramUniform4uiv.restype = None
        gl.glProgramUniformMatrix2fv.argtypes = [
            c_uint32,
            c_int32,
            c_size_t,
            c_ubyte,
            POINTER(c_float),
        ]
        gl.glProgramUniformMatrix2fv.restype = None
        gl.glProgramUniformMatrix2x3fv.argtypes = [
            c_uint32,
            c_int32,
            c_size_t,
            c_ubyte,
            POINTER(c_float),
        ]
        gl.glProgramUniformMatrix2x3fv.restype = None
        gl.glProgramUniformMatrix2x4fv.argtypes = [
            c_uint32,
            c_int32,
            c_size_t,
            c_ubyte,
            POINTER(c_float),
        ]
        gl.glProgramUniformMatrix2x4fv.restype = None
        gl.glProgramUniformMatrix3fv.argtypes = [
            c_uint32,
            c_int32,
            c_size_t,
            c_ubyte,
            POINTER(c_float),
        ]
        gl.glProgramUniformMatrix3fv.restype = None
        gl.glProgramUniformMatrix3x2fv.argtypes = [
            c_uint32,
            c_int32,
            c_size_t,
            c_ubyte,
            POINTER(c_float),
        ]
        gl.glProgramUniformMatrix3x2fv.restype = None
        gl.glProgramUniformMatrix3x4fv.argtypes = [
            c_uint32,
            c_int32,
            c_size_t,
            c_ubyte,
            POINTER(c_float),
        ]
        gl.glProgramUniformMatrix3x4fv.restype = None
        gl.glProgramUniformMatrix4fv.argtypes = [
            c_uint32,
            c_int32,
            c_size_t,
            c_ubyte,
            POINTER(c_float),
        ]
        gl.glProgramUniformMatrix4fv.restype = None
        gl.glProgramUniformMatrix4x2fv.argtypes = [
            c_uint32,
            c_int32,
            c_size_t,
            c_ubyte,
            POINTER(c_float),
        ]
        gl.glProgramUniformMatrix4x2fv.restype = None
        gl.glProgramUniformMatrix4x3fv.argtypes = [
            c_uint32,
            c_int32,
            c_size_t,
            c_ubyte,
            POINTER(c_float),
        ]
        gl.glProgramUniformMatrix4x3fv.restype = None
        gl.glPushDebugGroup.argtypes = [
            c_uint,
            c_uint32,
            c_size_t,
            POINTER(c_char),
        ]
        gl.glPushDebugGroup.restype = None
        gl.glReadBuffer.argtypes = [c_uint]
        gl.glReadBuffer.restype = None
        gl.glReadPixels.argtypes = [
            c_int,
            c_int,
            c_size_t,
            c_size_t,
            c_uint,
            c_uint,
            c_void_p,
        ]
        gl.glReadPixels.restype = None
        gl.glReleaseShaderCompiler.argtypes = None
        gl.glReleaseShaderCompiler.restype = None
        gl.glRenderbufferStorage.argtypes = [
            c_uint,
            c_uint,
            c_size_t,
            c_size_t,
        ]
        gl.glRenderbufferStorage.restype = None
        gl.glRenderbufferStorageMultisample.argtypes = [
            c_uint,
            c_size_t,
            c_uint,
            c_size_t,
            c_size_t,
        ]
        gl.glRenderbufferStorageMultisample.restype = None
        gl.glResumeTransformFeedback.argtypes = None
        gl.glResumeTransformFeedback.restype = None
        gl.glSampleCoverage.argtypes = [c_float, c_ubyte]
        gl.glSampleCoverage.restype = None
        gl.glSampleMaski.argtypes = [c_uint32, c_uint]
        gl.glSampleMaski.restype = None
        gl.glSamplerParameterIiv.argtypes = [
            c_uint32,
            c_uint,
            POINTER(c_int32),
        ]
        gl.glSamplerParameterIiv.restype = None
        gl.glSamplerParameterIuiv.argtypes = [
            c_uint32,
            c_uint,
            POINTER(c_uint32),
        ]
        gl.glSamplerParameterIuiv.restype = None
        gl.glSamplerParameterf.argtypes = [c_uint32, c_uint, c_float]
        gl.glSamplerParameterf.restype = None
        gl.glSamplerParameterfv.argtypes = [c_uint32, c_uint, POINTER(c_float)]
        gl.glSamplerParameterfv.restype = None
        gl.glSamplerParameteri.argtypes = [c_uint32, c_uint, c_int32]
        gl.glSamplerParameteri.restype = None
        gl.glSamplerParameteriv.argtypes = [c_uint32, c_uint, POINTER(c_int32)]
        gl.glSamplerParameteriv.restype = None
        gl.glScissor.argtypes = [c_int, c_int, c_size_t, c_size_t]
        gl.glScissor.restype = None
        gl.glShaderBinary.argtypes = [
            c_size_t,
            POINTER(c_uint32),
            c_uint,
            c_void_p,
            c_size_t,
        ]
        gl.glShaderBinary.restype = None
        gl.glShaderSource.argtypes = [
            c_uint32,
            c_size_t,
            POINTER(c_char_p),
            POINTER(c_int32),
        ]
        gl.glShaderSource.restype = None
        gl.glStencilFunc.argtypes = [c_uint, c_int, c_uint]
        gl.glStencilFunc.restype = None
        gl.glStencilFuncSeparate.argtypes = [c_uint, c_uint, c_int, c_uint]
        gl.glStencilFuncSeparate.restype = None
        gl.glStencilMask.argtypes = [c_uint]
        gl.glStencilMask.restype = None
        gl.glStencilMaskSeparate.argtypes = [c_uint, c_uint]
        gl.glStencilMaskSeparate.restype = None
        gl.glStencilOp.argtypes = [c_uint, c_uint, c_uint]
        gl.glStencilOp.restype = None
        gl.glStencilOpSeparate.argtypes = [c_uint, c_uint, c_uint, c_uint]
        gl.glStencilOpSeparate.restype = None
        gl.glTexBuffer.argtypes = [c_uint, c_uint, c_uint32]
        gl.glTexBuffer.restype = None
        gl.glTexBufferRange.argtypes = [
            c_uint,
            c_uint,
            c_uint32,
            c_size_t,
            c_ssize_t,
        ]
        gl.glTexBufferRange.restype = None
        gl.glTexImage2D.argtypes = [
            c_uint,
            c_long,
            c_int,
            c_size_t,
            c_size_t,
            c_long,
            c_uint,
            c_uint,
            c_void_p,
        ]
        gl.glTexImage2D.restype = None
        gl.glTexParameterIiv.argtypes = [c_uint, c_uint, POINTER(c_int32)]
        gl.glTexParameterIiv.restype = None
        gl.glTexParameterIuiv.argtypes = [c_uint, c_uint, POINTER(c_uint32)]
        gl.glTexParameterIuiv.restype = None
        gl.glTexParameterf.argtypes = [c_uint, c_uint, c_float]
        gl.glTexParameterf.restype = None
        gl.glTexParameterfv.argtypes = [c_uint, c_uint, POINTER(c_float)]
        gl.glTexParameterfv.restype = None
        gl.glTexParameteri.argtypes = [c_uint, c_uint, c_long]
        gl.glTexParameteri.restype = None
        gl.glTexParameteriv.argtypes = [c_uint, c_uint, POINTER(c_long)]
        gl.glTexParameteriv.restype = None
        gl.glTexStorage2D.argtypes = [
            c_uint,
            c_size_t,
            c_uint,
            c_size_t,
            c_size_t,
        ]
        gl.glTexStorage2D.restype = None
        gl.glTexStorage2DMultisample.argtypes = [
            c_uint,
            c_size_t,
            c_uint,
            c_size_t,
            c_size_t,
            c_ubyte,
        ]
        gl.glTexStorage2DMultisample.restype = None
        gl.glTexStorage3D.argtypes = [
            c_uint,
            c_size_t,
            c_uint,
            c_size_t,
            c_size_t,
            c_size_t,
        ]
        gl.glTexStorage3D.restype = None
        gl.glTexStorage3DMultisample.argtypes = [
            c_uint,
            c_size_t,
            c_uint,
            c_size_t,
            c_size_t,
            c_size_t,
            c_ubyte,
        ]
        gl.glTexStorage3DMultisample.restype = None
        gl.glTexSubImage2D.argtypes = [
            c_uint,
            c_long,
            c_long,
            c_long,
            c_size_t,
            c_size_t,
            c_uint,
            c_uint,
            c_void_p,
        ]
        gl.glTexSubImage2D.restype = None
        gl.glTexSubImage3D.argtypes = [
            c_uint,
            c_long,
            c_long,
            c_long,
            c_long,
            c_size_t,
            c_size_t,
            c_size_t,
            c_uint,
            c_uint,
            c_void_p,
        ]
        gl.glTexSubImage3D.restype = None
        gl.glTransformFeedbackVaryings.argtypes = [
            c_uint32,
            c_size_t,
            POINTER(c_char_p),
            c_uint,
        ]
        gl.glTransformFeedbackVaryings.restype = None
        gl.glUniform1f.argtypes = [c_int32, c_float]
        gl.glUniform1f.restype = None
        gl.glUniform1fv.argtypes = [c_int32, c_size_t, POINTER(c_float)]
        gl.glUniform1fv.restype = None
        gl.glUniform1i.argtypes = [c_int32, c_int32]
        gl.glUniform1i.restype = None
        gl.glUniform1iv.argtypes = [c_int32, c_size_t, POINTER(c_int32)]
        gl.glUniform1iv.restype = None
        gl.glUniform1ui.argtypes = [c_int32, c_uint32]
        gl.glUniform1ui.restype = None
        gl.glUniform1uiv.argtypes = [c_int32, c_size_t, POINTER(c_uint32)]
        gl.glUniform1uiv.restype = None
        gl.glUniform2f.argtypes = [c_int32, c_float, c_float]
        gl.glUniform2f.restype = None
        gl.glUniform2fv.argtypes = [c_int32, c_size_t, POINTER(c_float)]
        gl.glUniform2fv.restype = None
        gl.glUniform2i.argtypes = [c_int32, c_int32, c_int32]
        gl.glUniform2i.restype = None
        gl.glUniform2iv.argtypes = [c_int32, c_size_t, POINTER(c_int32)]
        gl.glUniform2iv.restype = None
        gl.glUniform2ui.argtypes = [c_int32, c_uint32, c_uint32]
        gl.glUniform2ui.restype = None
        gl.glUniform2uiv.argtypes = [c_int32, c_size_t, POINTER(c_uint32)]
        gl.glUniform2uiv.restype = None
        gl.glUniform3f.argtypes = [c_int32, c_float, c_float, c_float]
        gl.glUniform3f.restype = None
        gl.glUniform3fv.argtypes = [c_int32, c_size_t, POINTER(c_float)]
        gl.glUniform3fv.restype = None
        gl.glUniform3i.argtypes = [c_int32, c_int32, c_int32, c_int32]
        gl.glUniform3i.restype = None
        gl.glUniform3iv.argtypes = [c_int32, c_size_t, POINTER(c_int32)]
        gl.glUniform3iv.restype = None
        gl.glUniform3ui.argtypes = [c_int32, c_uint32, c_uint32, c_uint32]
        gl.glUniform3ui.restype = None
        gl.glUniform3uiv.argtypes = [c_int32, c_size_t, POINTER(c_uint32)]
        gl.glUniform3uiv.restype = None
        gl.glUniform4f.argtypes = [c_int32, c_float, c_float, c_float, c_float]
        gl.glUniform4f.restype = None
        gl.glUniform4fv.argtypes = [c_int32, c_size_t, POINTER(c_float)]
        gl.glUniform4fv.restype = None
        gl.glUniform4i.argtypes = [c_int32, c_int32, c_int32, c_int32, c_int32]
        gl.glUniform4i.restype = None
        gl.glUniform4iv.argtypes = [c_int32, c_size_t, POINTER(c_int32)]
        gl.glUniform4iv.restype = None
        gl.glUniform4ui.argtypes = [
            c_int32,
            c_uint32,
            c_uint32,
            c_uint32,
            c_uint32,
        ]
        gl.glUniform4ui.restype = None
        gl.glUniform4uiv.argtypes = [c_int32, c_size_t, POINTER(c_uint32)]
        gl.glUniform4uiv.restype = None
        gl.glUniformBlockBinding.argtypes = [c_uint32, c_uint32, c_uint32]
        gl.glUniformBlockBinding.restype = None
        gl.glUniformMatrix2fv.argtypes = [
            c_int32,
            c_size_t,
            c_ubyte,
            POINTER(c_float),
        ]
        gl.glUniformMatrix2fv.restype = None
        gl.glUniformMatrix2x3fv.argtypes = [
            c_int32,
            c_size_t,
            c_ubyte,
            POINTER(c_float),
        ]
        gl.glUniformMatrix2x3fv.restype = None
        gl.glUniformMatrix2x4fv.argtypes = [
            c_int32,
            c_size_t,
            c_ubyte,
            POINTER(c_float),
        ]
        gl.glUniformMatrix2x4fv.restype = None
        gl.glUniformMatrix3fv.argtypes = [
            c_int32,
            c_size_t,
            c_ubyte,
            POINTER(c_float),
        ]
        gl.glUniformMatrix3fv.restype = None
        gl.glUniformMatrix3x2fv.argtypes = [
            c_int32,
            c_size_t,
            c_ubyte,
            POINTER(c_float),
        ]
        gl.glUniformMatrix3x2fv.restype = None
        gl.glUniformMatrix3x4fv.argtypes = [
            c_int32,
            c_size_t,
            c_ubyte,
            POINTER(c_float),
        ]
        gl.glUniformMatrix3x4fv.restype = None
        gl.glUniformMatrix4fv.argtypes = [
            c_int32,
            c_size_t,
            c_ubyte,
            POINTER(c_float),
        ]
        gl.glUniformMatrix4fv.restype = None
        gl.glUniformMatrix4x2fv.argtypes = [
            c_int32,
            c_size_t,
            c_ubyte,
            POINTER(c_float),
        ]
        gl.glUniformMatrix4x2fv.restype = None
        gl.glUniformMatrix4x3fv.argtypes = [
            c_int32,
            c_size_t,
            c_ubyte,
            POINTER(c_float),
        ]
        gl.glUniformMatrix4x3fv.restype = None
        gl.glUnmapBuffer.argtypes = [c_uint]
        gl.glUnmapBuffer.restype = c_ubyte
        gl.glUseProgram.argtypes = [c_uint32]
        gl.glUseProgram.restype = None
        gl.glUseProgramStages.argtypes = [c_uint32, c_uint, c_uint32]
        gl.glUseProgramStages.restype = None
        gl.glValidateProgram.argtypes = [c_uint32]
        gl.glValidateProgram.restype = None
        gl.glValidateProgramPipeline.argtypes = [c_uint32]
        gl.glValidateProgramPipeline.restype = None
        gl.glVertexAttribBinding.argtypes = [c_uint32, c_uint32]
        gl.glVertexAttribBinding.restype = None
        gl.glVertexAttribDivisor.argtypes = [c_uint32, c_uint32]
        gl.glVertexAttribDivisor.restype = None
        gl.glVertexAttribFormat.argtypes = [
            c_uint32,
            c_int32,
            c_uint,
            c_ubyte,
            c_uint32,
        ]
        gl.glVertexAttribFormat.restype = None
        gl.glVertexAttribIFormat.argtypes = [
            c_uint32,
            c_int32,
            c_uint,
            c_uint32,
        ]
        gl.glVertexAttribIFormat.restype = None
        gl.glVertexAttribIPointer.argtypes = [
            c_uint32,
            c_int32,
            c_uint,
            c_size_t,
            c_void_p,
        ]
        gl.glVertexAttribIPointer.restype = None
        gl.glVertexAttribPointer.argtypes = [
            c_uint32,
            c_int32,
            c_uint,
            c_ubyte,
            c_size_t,
            c_void_p,
        ]
        gl.glVertexAttribPointer.restype = None
        gl.glVertexBindingDivisor.argtypes = [c_uint32, c_uint32]
        gl.glVertexBindingDivisor.restype = None
        gl.glViewport.argtypes = [c_int, c_int, c_size_t, c_size_t]
        gl.glViewport.restype = None
'''


class PageAnalyzer(object):
    """Analyzer for kernel page"""

    # page flags from kernel/include/uapi/linux/kernel-page-flags.h #
    flagList = [
        "KPF_LOCKED",  # 0
        "KPF_ERROR",  # 1
        "KPF_REFERENCED",  # 2
        "KPF_UPTODATE",  # 3
        "KPF_DIRTY",  # 4
        "KPF_LRU",  # 5
        "KPF_ACTIVE",  # 6
        "KPF_SLAB",  # 7
        "KPF_WRITEBACK",  # 8
        "KPF_RECLAIM",  # 9
        "KPF_BUDDY",  # 10
        "KPF_MMAP",  # 11
        "KPF_ANON",  # 12
        "KPF_SWAPCACHE",  # 13
        "KPF_SWAPBACKED",  # 14
        "KPF_COMPOUND_HEAD",  # 15
        "KPF_COMPOUND_TAIL",  # 16
        "KPF_HUGE",  # 17
        "KPF_UNEVICTABLE",  # 18
        "KPF_HWPOISON",  # 19
        "KPF_NOPAGE",  # 20
        "KPF_KSM",  # 21
        "KPF_THP",  # 22
        "KPF_BALLOON",  # 23
        "KPF_ZERO_PAGE",  # 24
        "KPF_IDLE",  # 25
    ]

    @staticmethod
    def getPageInfo(
        pid,
        vaddr,
        markIdle=False,
        checkIdle=False,
        retList=False,
        verb=True,
        progress=False,
    ):
        try:
            if not pid:
                raise Exception("no pid")
            elif type(pid) is not list:
                raise Exception("wrong pid")

            pids = []
            for item in pid:
                ret = SysMgr.getTids(item, isThread=False)
                if ret:
                    pids += ret
            if not pids:
                raise Exception("no task")
        except SystemExit:
            sys.exit(0)
        except:
            if pid:
                targetStr = " for '%s'" % ", ".join(pid)
            else:
                targetStr = ""

            SysMgr.printErr("failed to find task%s" % targetStr, reason=True)

            sys.exit(-1)

        # check root permission #
        SysMgr.checkRootPerm()

        # get target addresses #
        if vaddr:
            vaddrOrig = UtilMgr.cleanItem(vaddr.split(","), False)
        else:
            vaddrOrig = None

        # update verb #
        if verb and not SysMgr.printEnable:
            verb = False

        # set print function #
        if verb:
            _printPipe = SysMgr.printPipe
        else:
            _printPipe = lambda _: True

        # check idle page marking #
        if "MARKIDLE" in SysMgr.environList:
            markIdle = True
            if not SysMgr.checkIdlePageCond():
                sys.exit(-1)

        # check idle page checking #
        if "CHECKIDLE" in SysMgr.environList:
            checkIdle = True

        # check bitmap saving #
        if "SAVEBITMAP" in SysMgr.environList:
            saveBitmapFlag = True
        else:
            saveBitmapFlag = False

        # define shortcut variables #
        convNum = UtilMgr.convNum
        convSize = UtilMgr.convSize2Unit
        errMsg = (
            "failed to recognize addresses, "
            "input the address such as 102400 or 0x1234a-0x123ff"
        )

        idlePageList = {}

        for pidx, pid in enumerate(sorted(pids)):
            # read whole bitmap for idle pages #
            if checkIdle:
                bitmap = SysMgr.getIdleMap()
            else:
                bitmap = None

            # get process name #
            comm = SysMgr.getComm(pid)
            vaddrs = vaddrOrig
            if not vaddrs:
                PageAnalyzer.printMemoryArea(
                    pid, comm=comm, showall=SysMgr.showAll, lastLine=True
                )
                continue

            if retList:
                idlePageList.setdefault(pid, [])

            # get target address ranges #
            targetList = []
            for vaddr in vaddrs:
                if not vaddr:
                    continue

                # get address range #
                if vaddr in ("heap", "stack"):
                    vaddr = "[%s]" % vaddr

                    # get addresses by name #
                    vrange = FileAnalyzer.getMapAddr(pid, vaddr)
                    if not vrange:
                        SysMgr.printErr(
                            "failed to find memory address for '%s'" % vaddr
                        )
                        continue

                    targetList.append(vrange)
                else:
                    # get addresses by file #
                    vranges = FileAnalyzer.getMapAddr(pid, vaddr, retList=True)
                    if vranges:
                        targetList += vranges
                    else:
                        vrange = UtilMgr.cleanItem(vaddr.split("-"), False)
                        targetList.append(vrange)

            procPresent = 0
            procSwapped = 0
            procSoftdirty = 0
            procExmapped = 0
            procFile = 0
            procRef = 0
            procIdle = 0
            procTotalFlags = 0
            pageTable = []

            # print page info in target address ranges #
            for vcnt, vrange in enumerate(targetList):
                # print progress #
                if progress:
                    UtilMgr.printProgress(vcnt, len(targetList))

                rangeCnt = len(vrange)

                # check input count #
                if rangeCnt > 2:
                    SysMgr.printErr(errMsg, True)
                    sys.exit(-1)

                # check input format #
                try:
                    addrs = long(vrange[0], base=16)
                    addre = addrs
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(errMsg, True)
                    sys.exit(-1)

                try:
                    if rangeCnt == 2:
                        addre = long(vrange[1], base=16)
                        offset = 0
                    else:
                        offset = SysMgr.PAGESIZE

                    # check range #
                    if addrs > addre:
                        if verb:
                            # print memory area #
                            PageAnalyzer.printMemoryArea(
                                pid, comm=comm, showall=True, lastLine=True
                            )

                        # print error message #
                        SysMgr.printErr(
                            (
                                "failed to recognize addresses, "
                                "the first address (%s) is bigger than "
                                "the second address (%s)"
                            )
                            % (hex(addrs), hex(addre))
                        )
                        sys.exit(-1)
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(errMsg, True)
                    sys.exit(-1)

                _printPipe(
                    "\n[Mem Info] [Proc: %s(%s)] [AREA: %s] [HELP: %s]"
                    % (comm, pid, vaddr, "kernel/Documentation/vm/pagemap.txt")
                )

                # print memory area info #
                if verb:
                    PageAnalyzer.printMemoryArea(
                        pid, addrs, addre, lastLine=True
                    )

                # print menu #
                _printPipe(
                    (
                        "{0:^19}|{1:^16}|{2:>5}|{3:>5}|{4:>5}|{5:>5}|"
                        "{6:>5}|{7:>5}|{8:>5}| {9} ({10})\n{11}"
                    ).format(
                        "VADDR",
                        "PFN",
                        "PRES",
                        "SWAP",
                        "FILE",
                        "SHR",
                        "SDRT",
                        "EXMAP",
                        "IDLE",
                        "ATTRIBUTES",
                        "BITS",
                        oneLine,
                    )
                )

                # init total variables #
                totalPresent = 0
                totalSwapped = 0
                totalSoftdirty = 0
                totalExmapped = 0
                totalFile = 0
                totalRef = 0
                totalIdle = 0
                totalFlags = 0

                # read pagemap #
                addreNew = addre + offset
                length = addreNew - addrs
                pagemap = PageAnalyzer.getPagemap(pid, addrs, length)

                # create a new pagetable for this area #
                if retList or (saveBitmapFlag and checkIdle):
                    pageSubTable = [1] * long(length / SysMgr.PAGESIZE)

                idx = 0
                for addr in xrange(addrs, addreNew, SysMgr.PAGESIZE):
                    # get page frame info #
                    try:
                        entry = struct.unpack("Q", pagemap[idx : idx + 8])[0]
                    except SystemExit:
                        sys.exit(0)
                    except:
                        entry = 0
                    finally:
                        idx += 8

                    # get page frame number #
                    pfn = PageAnalyzer.getPfn(entry)

                    # no page #
                    isIdle = "-"
                    # mark idle pages #
                    if markIdle:
                        if SysMgr.handleIdlePage(pfn, write=True):
                            isIdle = True
                            totalIdle += 1
                            procIdle += 1
                    # check idle pages #
                    elif checkIdle:
                        isIdle = SysMgr.handleIdlePage(
                            pfn, write=False, bitmap=bitmap
                        )
                        if isIdle is None:
                            isIdle = "-"
                        elif isIdle:
                            totalIdle += 1
                            procIdle += 1

                            # change a bit in a pagetable #
                            if retList or saveBitmapFlag:
                                try:
                                    pageSubTable[long(idx / 8) - 1] = 0
                                except:
                                    SysMgr.printWarn(
                                        "failed to save an idle page status",
                                        always=True,
                                        reason=True,
                                    )

                    # check skip condition #
                    if not verb:
                        continue

                    isPresent = PageAnalyzer.isPresent(entry)
                    if isPresent:
                        totalPresent += 1
                        procPresent += 1

                    isSwapped = PageAnalyzer.isSwapped(entry)
                    if isSwapped:
                        totalSwapped += 1
                        procSwapped += 1

                    isSoftdirty = PageAnalyzer.isSoftdirty(entry)
                    if isSoftdirty:
                        totalSoftdirty += 1
                        procSoftdirty += 1

                    isExmapped = PageAnalyzer.isExmapped(entry)
                    if isExmapped:
                        totalExmapped += 1
                        procExmapped += 1

                    isFile = PageAnalyzer.isFilePage(entry)
                    if isFile:
                        totalFile += 1
                        procFile += 1

                    refCnt = PageAnalyzer.getPageCount(pfn)
                    if refCnt > 1:
                        refCnt = 1
                        totalRef += 1
                        procRef += 1
                    else:
                        refCnt = 0

                    kflags = PageAnalyzer.getPageFlags(pfn)
                    totalFlags |= kflags
                    if kflags:
                        bflags = hex(kflags).rstrip("L")
                        sflags = PageAnalyzer.getFlagTypes(bflags)
                        bflags = "(%s)" % bflags
                    else:
                        sflags = bflags = ""

                    if SysMgr.showAll:
                        SysMgr.addPrint(
                            (
                                "{0:>18} |{1:>15} |{2:>5}|{3:>5}|{4:>5}|"
                                "{5:>5}|{6:>5}|{7:>5}|{8:>5}| {9} {10}\n"
                            ).format(
                                hex(addr).rstrip("L"),
                                hex(pfn).rstrip("L") if pfn else "",
                                isPresent,
                                isSwapped,
                                isFile,
                                convSize(refCnt, isInt=True),
                                isSoftdirty,
                                isExmapped,
                                isIdle,
                                sflags,
                                bflags,
                            ),
                            force=True,
                            isList=True,
                        )

                procTotalFlags |= totalFlags
                totalFlagsStr = hex(totalFlags).rstrip("L")

                # print total stats #
                _printPipe(
                    (
                        "{0:>18} |{1:>15} |{2:>5}|{3:>5}|{4:>5}|"
                        "{5:>5}|{6:>5}|{7:>5}|{8:>5}| {9} ({10})\n{11:1}"
                    ).format(
                        "[TOTAL]",
                        "",
                        convSize(totalPresent, isInt=True),
                        convSize(totalSwapped, isInt=True),
                        convSize(totalFile, isInt=True),
                        convSize(totalRef, isInt=True),
                        convSize(totalSoftdirty, isInt=True),
                        convSize(totalExmapped, isInt=True),
                        convSize(totalIdle, isInt=True),
                        PageAnalyzer.getFlagTypes(totalFlagsStr),
                        totalFlagsStr,
                        oneLine,
                    )
                )

                # print all items #
                if verb:
                    SysMgr.doPrint(newline=False, clear=True, isList=True)
                    if SysMgr.showAll:
                        _printPipe("%s\n" % oneLine)
                else:
                    SysMgr.clearPrint()

                # add a new area to list #
                if retList:
                    idlePageList[pid].append([addrs, addreNew, pageSubTable])

                # merge pagetables #
                if saveBitmapFlag and checkIdle:
                    pageTable += pageSubTable

            if progress:
                UtilMgr.deleteProgress()

            # print process memory info #
            _printPipe(
                "\n[Mem Info] [Proc: %s(%s)] [Area: %s)\n%s"
                % (SysMgr.getComm(pid), pid, convNum(len(targetList)), twoLine)
            )

            _printPipe(
                (
                    "{0:^10}|{1:^8}|{2:^8}|{3:^8}|{4:^8}|"
                    "{5:^8}|{6:^8}|{7:^8}| {8} ({9})\n{10}"
                ).format(
                    "[TOTAL]",
                    "PRESENT",
                    "SWAP",
                    "FILE",
                    "SHR",
                    "SDRT",
                    "EXMAP",
                    "IDLE",
                    "ATTRIBUTES",
                    "BITS",
                    oneLine,
                )
            )

            procTotalFlagsStr = hex(procTotalFlags).rstrip("L")

            # print total page stats #
            _printPipe(
                (
                    "{0:^9} |{1:>7} |{2:>7} |{3:>7} |"
                    "{4:>7} |{5:>7} |{6:>7} |{7:>7} | {8}"
                ).format(
                    "PAGE",
                    convNum(procPresent),
                    convNum(procSwapped),
                    convNum(procFile),
                    convSize(procRef, isInt=True),
                    convNum(procSoftdirty),
                    convNum(procExmapped),
                    convNum(procIdle) if checkIdle or markIdle else "-",
                    PageAnalyzer.getFlagTypes(procTotalFlagsStr),
                )
            )

            # print total size stats #
            _printPipe(
                (
                    "{0:^9} |{1:>7} |{2:>7} |{3:>7} |"
                    "{4:>7} |{5:>7} |{6:>7} |{7:>7} | {8}\n{9}"
                ).format(
                    "SIZE",
                    convSize(procPresent << 12),
                    convSize(procSwapped << 12),
                    convSize(procFile << 12),
                    convSize(procRef << 12, isInt=True),
                    convSize(procSoftdirty << 12),
                    convSize(procExmapped << 12),
                    convSize(procIdle << 12) if checkIdle or markIdle else "-",
                    procTotalFlagsStr,
                    oneLine,
                )
            )

            # save idle bitmap to the file #
            if saveBitmapFlag and checkIdle:
                if SysMgr.printFd:
                    filename = SysMgr.printFd.name
                    name, ext = os.path.splitext(filename)
                    filename = "%s_idlemap%s%s" % (name, pid, ext)
                else:
                    filename = "idlemap.out"

                # backup #
                SysMgr.backupFile(filename)

                # save bitmap to the file #
                try:
                    with open(filename, "wb") as fd:
                        btable = bytes(pageTable)
                        fd.write(btable)
                    os.chmod(filename, 0o777)
                except:
                    SysMgr.printOpenErr(filename)
                    continue

                # get output size #
                fsize = UtilMgr.getFileSizeStr(filename)

                SysMgr.printStat(
                    "saved the bitmap data to '%s'%s successfully"
                    % (filename, fsize)
                )

            # print split line between proceses #
            if pidx < len(pids) - 1:
                _printPipe("\n\n" + splitLine + "\n\n")

        return idlePageList

    @staticmethod
    def printMemoryArea(
        pid, start=-1, end=-1, comm=None, lastLine=False, showall=True
    ):

        count = 0
        switch = False
        fpath = "%s/%s/maps" % (SysMgr.procPath, pid)

        if start == end == -1 and not showall:
            summaryFlag = True
        else:
            summaryFlag = False

        # read all map info #
        try:
            # summary #
            if summaryFlag:
                buf = FileAnalyzer.getProcMapInfo(pid, saveAll=True)
            else:
                with open(fpath, "r") as fd:
                    buf = fd.readlines()
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenErr(fpath)
            sys.exit(-1)

        convSize = UtilMgr.convSize2Unit

        if start == end == -1:
            if not comm:
                comm = SysMgr.getComm(pid)

            # get mem stat #
            mlist = SysMgr.getMemStat(pid)
            mstat = SysMgr.convMemStat(mlist)
            vss = convSize(mstat["vss"])
            rss = convSize(mstat["rss"])
            SysMgr.printPipe(
                "\n[Mem Info] [Proc: %s(%s)] [VSS: %s] [RSS: %s]"
                % (comm, pid, vss, rss)
            )

        startHex = hex(start)
        endHex = hex(end)
        allHex = hex(-1)

        # print menu #
        menuStr = ""
        menuBuf = menuList = [
            "AREA",
            "PERM",
            "%8s" % "OFFSET",
            "%6s" % "DEV",
            "%12s" % "INODE",
            "%5s" % "SIZE",
        ]

        for idx, value in enumerate(menuBuf):
            if idx < 6:
                if idx == 0:
                    text = "{0:^38}".format(menuList[idx])
                else:
                    text = menuList[idx]
            else:
                break

            value = " " * (len(value) - len(text) + 1)
            menuStr = "%s%s%s" % (menuStr, text, value)

        menuStr += "TARGET"
        SysMgr.printPipe("%s\n%s\n%s" % (twoLine, menuStr, oneLine))

        # set text position #
        tstr = menuStr.split()
        pstr = tstr[1]

        # print summarized map info #
        if summaryFlag:
            for fname, info in sorted(
                buf.items(), key=lambda e: e[1]["vstart"]
            ):
                # skip non-contiguous segments #
                if SysMgr.magicStr in fname:
                    continue

                try:
                    soffset = hex(info["vstart"]).rstrip("L")
                    eoffset = hex(info["vend"]).rstrip("L")
                    size = convSize(
                        long(eoffset, 16) - long(soffset, 16), True
                    )

                    if not fname.startswith("/"):
                        fname = "[%s]" % fname

                    SysMgr.printPipe(
                        "%18s %18s %4s %8s %6s %12s %5s %s"
                        % (
                            soffset,
                            eoffset,
                            info["perm"],
                            info["offset"],
                            info["devid"],
                            info["inode"],
                            size,
                            fname,
                        )
                    )

                    count += 1

                except SystemExit:
                    sys.exit(0)
                except:
                    pass

            if count == 0:
                SysMgr.printPipe("no involved memory area")

            if lastLine:
                SysMgr.printPipe(oneLine)

            return

        # print all map info #
        for line in buf:
            tmplist = line.split()
            soffset, eoffset = tmplist[0].split("-")

            soffset = long(soffset, base=16)
            eoffset = long(eoffset, base=16)

            if startHex == endHex == allHex:
                switch = False
            elif "-" in line:
                if soffset <= start < eoffset:
                    switch = True
                elif not switch:
                    continue
                elif end < eoffset:
                    break

            try:
                target = line[:-1].split()

                target[4] = "%12s" % target[4]

                soffsetHex = hex(soffset)
                eoffsetHex = hex(eoffset)

                if not soffsetHex.startswith("0x"):
                    soffsetHex = "0x%s" % soffsetHex

                if not eoffsetHex.startswith("0x"):
                    eoffsetHex = "0x%s" % eoffsetHex

                size = convSize(eoffset - soffset, True)

                SysMgr.printPipe(
                    "%18s %18s %4s %8s %6s %12s %5s %s"
                    % (
                        soffsetHex,
                        eoffsetHex,
                        target[1],
                        target[2],
                        target[3],
                        target[4],
                        size,
                        target[5] if len(target) > 5 else " ",
                    )
                )
            except SystemExit:
                sys.exit(0)
            except:
                pass

            count += 1

            if switch and end <= eoffset:
                break

        if count == 0:
            SysMgr.printPipe("no involved memory area")

        if lastLine:
            SysMgr.printPipe(oneLine)

    @staticmethod
    def getFlagTypes(flags):
        sflags = ""

        for idx, val in enumerate(PageAnalyzer.flagList):
            if (long(flags, 16) & (1 << long(idx))) != 0:
                sflags += val[4:] + "|"

        return sflags[:-1]

    @staticmethod
    def readEntry(path, offset, size=8):
        try:
            f = SysMgr.getFd(path)
            f.seek(offset, 0)
            data = f.read(size)
            if data:
                return struct.unpack("Q" if size == 8 else "I", data)[0]
            else:
                return 0
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to read %s byte from %s of %s" % (size, offset, path),
                reason=True,
            )
            sys.exit(-1)

    @staticmethod
    def getPagemapPath(pid):
        path = "{0}/{1}/pagemap".format(SysMgr.procPath, pid)
        if not os.path.isfile(path):
            SysMgr.printErr("failed to find the process with PID %s" % pid)
            sys.exit(-1)
        return path

    @staticmethod
    def getPagemap(pid, addr, size):
        path = PageAnalyzer.getPagemapPath(pid)
        offset = long(addr / SysMgr.PAGESIZE) * 8
        size = long(size / SysMgr.PAGESIZE) * 8

        try:
            f = SysMgr.getFd(path)
            f.seek(offset, 0)
            return f.read(size)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to read %s byte from %s of %s" % (size, offset, path),
                reason=True,
            )
            sys.exit(-1)

    @staticmethod
    def getPagemapEntry(pid, addr):
        path = PageAnalyzer.getPagemapPath(pid)
        offset = long(addr / SysMgr.PAGESIZE) * 8
        return PageAnalyzer.readEntry(path, offset)

    @staticmethod
    def getPfn(entry):
        return entry & 0x7FFFFFFFFFFFFF

    @staticmethod
    def isPresent(entry):
        return (entry & (1 << 63)) != 0

    @staticmethod
    def isSoftdirty(entry):
        return (entry & (1 << 55)) != 0

    @staticmethod
    def isExmapped(entry):
        return (entry & (1 << 56)) != 0

    @staticmethod
    def isSwapped(entry):
        return (entry & (1 << 62)) != 0

    @staticmethod
    def isFilePage(entry):
        return (entry & (1 << 61)) != 0

    @staticmethod
    def getPageCount(pfn):
        path = SysMgr.procPath + "/kpagecount"
        return PageAnalyzer.readEntry(path, pfn * 8)

    @staticmethod
    def getPageFlags(pfn):
        path = SysMgr.procPath + "/kpageflags"
        return PageAnalyzer.readEntry(path, pfn * 8)


class FunctionAnalyzer(object):
    """Analyzer for function profiling"""

    symStackIdxTable = [
        "CPU_TICK",
        "STACK",
        "PAGE_ALLOC",
        "PAGE_FREE",
        "BLK_READ",
        "ARGUMENT",
        "HEAP_EXPAND",
        "HEAP_REDUCE",
        "IGNORE",
        "BLK_WRITE",
        "LOCK_TRY",
        "UNLOCK",
        "SYSCALL",
        "CUSTOM",
    ]

    def __init__(self, logFile):
        self.cpuEnabled = False
        self.memEnabled = False
        self.heapEnabled = False
        self.breadEnabled = False
        self.bwriteEnabled = False
        self.sigEnabled = False
        self.lockEnabled = False
        self.sysEnabled = False

        self.sort = "sym"
        self.connObj = None

        self.finishTime = "0"
        self.lastTime = "0"
        self.totalTime = 0
        self.totalTick = 0
        self.prevTime = "0"
        self.prevTid = "0"

        self.lastCore = None
        self.coreCtx = {}
        self.nowCtx = None
        self.nowEvent = None
        self.savedEvent = None
        self.nestedEvent = None
        self.nowCnt = 0
        self.savedCnt = 0
        self.nestedCnt = 0
        self.nowArg = 0
        self.savedArg = 0
        self.nestedArg = 0

        self.duplicatedPos = 0
        self.periodicEventCnt = 0
        self.periodicContEventCnt = 0
        self.periodicEventInterval = 0
        self.heapExpEventCnt = 0
        self.heapExpSize = 0
        self.heapRedEventCnt = 0
        self.heapRedSize = 0
        self.pageAllocEventCnt = 0
        self.pageAllocCnt = 0
        self.pageFreeEventCnt = 0
        self.pageFreeCnt = 0
        self.pageUnknownFreeCnt = 0
        self.pageUsageCnt = 0
        self.blockRdEventCnt = 0
        self.blockRdUsageCnt = 0
        self.blockWrEventCnt = 0
        self.blockWrUsageCnt = 0
        self.lockTryEventCnt = 0
        self.unlockEventCnt = 0
        self.customCnt = 0
        self.customTotal = 0
        self.syscallCnt = 0

        self.customEventTable = {}
        self.ignoreTable = {}
        self.mapData = []
        self.pageTable = {}
        self.oldPageTable = {}
        self.heapTable = {}
        self.oldHeapTable = {}
        self.posData = {}
        self.userSymData = {}
        self.userFileData = {}
        self.kerSymData = {}
        self.threadData = {}
        self.syscallTable = {}
        self.customCallData = []
        self.lockCallData = []
        self.sysCallData = []
        self.userCallData = []
        self.kernelCallData = []
        """
        userCallData = kernelCallData = \
            [pos, stack, event, eventCnt, eventArg]
        """

        self.init_threadData = {
            "comm": "?",
            "tgid": "-" * 5,
            "target": False,
            "cpuTick": 0,
            "die": False,
            "new": False,
            "nrPages": 0,
            "userPages": 0,
            "cachePages": 0,
            "kernelPages": 0,
            "heapSize": 0,
            "eventCnt": 0,
            "nrWrBlocks": 0,
            "customCnt": 0,
            "nrUnknownFreePages": 0,
            "nrKnownFreePages": 0,
            "nrRdBlocks": 0,
            "nrLockTry": 0,
            "nrUnlock": 0,
            "customTotal": 0,
            "nrSyscall": 0,
            "syscallTable": None,
            "lastNrSyscall": -1,
        }

        self.init_posData = {
            "symbol": "",
            "binary": "",
            "origBin": "",
            "offset": hex(0),
            "posCnt": 0,
            "userPageCnt": 0,
            "cachePageCnt": 0,
            "kernelPageCnt": 0,
            "totalCnt": 0,
            "blockRdCnt": 0,
            "blockWrCnt": 0,
            "pageCnt": 0,
            "heapSize": 0,
            "unknownPageFreeCnt": 0,
            "src": "",
            "customCnt": 0,
            "customTotal": 0,
            "lockTryCnt": 0,
            "unlockCnt": 0,
            "syscallCnt": 0,
        }

        self.init_symData = {
            "pos": "",
            "origBin": "",
            "tickCnt": 0,
            "blockRdCnt": 0,
            "pageCnt": 0,
            "unknownPageFreeCnt": 0,
            "stack": None,
            "symStack": None,
            "userPageCnt": 0,
            "cachePageCnt": 0,
            "kernelPageCnt": 0,
            "heapSize": 0,
            "blockWrCnt": 0,
            "customCnt": 0,
            "customTotal": 0,
            "pagePair": None,
            "pagePairCnt": 0,
            "pagePairTotal": 0.0,
            "pagePairMin": 0.0,
            "pagePairMax": 0.0,
            "pagePairAvr": 0.0,
            "pageRemainMin": 0.0,
            "pageRemainMax": 0.0,
            "pageRemainAvr": 0.0,
            "pageRemainTotal": 0.0,
            "lockTryCnt": 0,
            "unlockCnt": 0,
            "syscallCnt": 0,
            "totalTickCnt": 0,
        }

        self.init_ctxData = {
            "nestedEvent": None,
            "savedEvent": None,
            "nowEvent": None,
            "nested": 0,
            "recStat": False,
            "nestedCnt": 0,
            "savedCnt": 0,
            "nowCnt": 0,
            "nestedArg": None,
            "savedArg": None,
            "prevMode": None,
            "curMode": None,
            "userLastPos": "",
            "userStack": None,
            "kerLastPos": "",
            "kerStack": None,
            "prevKerLastPos": "",
            "prevKerStack": None,
            "nowArg": None,
            "prevTid": None,
            "prevTime": None,
        }

        self.init_pageLinkData = {
            "sym": "0",
            "subStackAddr": 0,
            "ksym": "0",
            "ksubStackAddr": 0,
            "type": "0",
            "time": "0",
        }

        self.init_heapSegData = {
            "tid": "0",
            "size": 0,
            "sym": "0",
            "subStackAddr": 0,
            "ksym": "0",
            "ksubStackAddr": 0,
            "time": 0.0,
            "core": "0",
        }

        self.init_pageData = {
            "tid": "0",
            "page": "0",
            "flags": "0",
            "type": "0",
            "time": "0",
        }

        self.init_glueData = {
            "count": 0,
            "size": 0,
            "timeList": None,
            "valueList": None,
        }

        self.init_subStackPageInfo = [0, 0, 0]
        # subStackPageInfo = [userPageCnt, cachePageCnt, kernelPageCnt]

        # read trace data #
        lines = TaskAnalyzer.readTraceData(logFile)

        # save trace data and stop analysis #
        if SysMgr.outputFile:
            SysMgr.saveTraceData(lines)
            sys.exit(0)

        # Check target thread setting #
        if not SysMgr.filterGroup:
            SysMgr.filterGroup.insert(0, "")
            self.target = []
        else:
            self.target = SysMgr.filterGroup

        # Check root path #
        if SysMgr.userEnable:
            if SysMgr.rootPath == "":
                rootPath = "/"
            else:
                rootPath = SysMgr.rootPath
            SysMgr.printInfo("use '%s' as the sysroot path" % rootPath)

        # Register None pos #
        self.posData["0"] = dict(self.init_posData)

        # get process tree #
        SysMgr.getProcTreeInfo()

        # start parsing logs #
        SysMgr.totalLine = len(lines)
        SysMgr.printStat("start analyzing data... [ STOP(Ctrl+c) ]")

        # parse logs #
        self.parseLines(lines, SysMgr.filterGroup)

        # Check whether data of target thread is collected or nothing #
        if (
            not self.userCallData
            and not self.kernelCallData
            and len(self.target) > 0
        ):
            if not self.target:
                SysMgr.printErr("no collected stack data")
            else:
                targetStr = ", ".join(self.target)
                SysMgr.printErr(
                    "no collected stack related to '%s'" % targetStr
                )
            sys.exit(-1)
        elif (
            SysMgr.userEnable
            and len(self.userCallData) == 1
            and self.userCallData[0][0] == "0"
        ):
            SysMgr.userEnable = False
            if self.target == []:
                SysMgr.printWarn("no collected user stack data", True)
            else:
                targetStr = ", ".join(self.target)
                SysMgr.printWarn(
                    "no collected user stack related to '%s'" % targetStr, True
                )

        # Get symbols from call address #
        SysMgr.printStat("start resolving symbols... [ STOP(Ctrl+c) ]")
        self.getSymbols()

        # Merge callstacks by symbol and address #
        SysMgr.printStat("start summarizing functions... [ STOP(Ctrl+c) ]")
        self.mergeStacks()

    def __del__(self):
        pass

    def handleHeapExpand(self, sym, ksym, stackAddr, kstackAddr, size, arg):
        addr = arg[0]
        time = arg[1]
        core = arg[2]
        tid = arg[3]

        self.userSymData[sym]["heapSize"] += size
        self.kerSymData[ksym]["heapSize"] += size

        self.heapTable.setdefault(addr, dict(self.init_heapSegData))
        self.heapTable[addr]["size"] = size
        self.heapTable[addr]["sym"] = sym
        self.heapTable[addr]["ksym"] = ksym
        self.heapTable[addr]["subStackAddr"] = stackAddr
        self.heapTable[addr]["ksubStackAddr"] = kstackAddr
        self.heapTable[addr]["time"] = time
        self.heapTable[addr]["core"] = core
        self.heapTable[addr]["tid"] = tid

    def handleHeapReduce(self, size, arg):
        addr = arg[0]

        subStackIndex = FunctionAnalyzer.symStackIdxTable.index("STACK")
        heapExpIndex = FunctionAnalyzer.symStackIdxTable.index("HEAP_EXPAND")

        try:
            sym = self.heapTable[addr]["sym"]
            ksym = self.heapTable[addr]["ksym"]
            stackAddr = self.heapTable[addr]["subStackAddr"]
            kstackAddr = self.heapTable[addr]["ksubStackAddr"]

            self.userSymData[sym]["heapSize"] -= size
            self.kerSymData[ksym]["heapSize"] -= size
        except:
            SysMgr.printWarn("failed to find heap segment to be freed")
            return

        # Set user stack list #
        if self.sort == "sym":
            targetStack = self.userSymData[sym]["symStack"]
        elif self.sort == "pos":
            targetStack = self.userSymData[sym]["stack"]

        # Find user stack of symbol allocated this segment #
        for val in targetStack:
            if id(val[subStackIndex]) == stackAddr:
                # Increase heap count of subStack #
                val[heapExpIndex] -= size
                break

        # Set kernel stack list #
        kernelTargetStack = self.kerSymData[ksym]["stack"]

        # Find kernel stack of symbol allocated this segment #
        for val in kernelTargetStack:
            if id(val[subStackIndex]) == kstackAddr:
                # Increase heap count of subStack #
                val[heapExpIndex] -= size
                break

        self.heapTable.pop(addr)

    def handlePageFree(
        self,
        sym,
        ksym,
        stackAddr,
        kstackAddr,
        pageFreeCnt,
        pageType,
        pfn,
        atime,
    ):

        subStackIndex = FunctionAnalyzer.symStackIdxTable.index("STACK")
        pageAllocIndex = FunctionAnalyzer.symStackIdxTable.index("PAGE_ALLOC")
        pageFreeIndex = FunctionAnalyzer.symStackIdxTable.index("PAGE_FREE")
        argIndex = FunctionAnalyzer.symStackIdxTable.index("ARGUMENT")

        for cnt in xrange(pageFreeCnt):
            pfnv = pfn + cnt
            subStackPageInfoIdx = 0

            try:
                # Decrease page count of symbol allocated page #
                # TODO: fix bug about wrong count of pos #
                allocSym = self.pageTable[pfnv]["sym"]
                allocStackAddr = self.pageTable[pfnv]["subStackAddr"]
                allocKernelSym = self.pageTable[pfnv]["ksym"]
                allocKernelStackAddr = self.pageTable[pfnv]["ksubStackAddr"]
                allocTime = self.pageTable[pfnv]["time"]

                self.pageUsageCnt -= 1
                self.userSymData[allocSym]["pageCnt"] -= 1
                self.kerSymData[allocKernelSym]["pageCnt"] -= 1

                if pageType == "USER":
                    self.userSymData[allocSym]["userPageCnt"] -= 1
                    self.kerSymData[allocKernelSym]["userPageCnt"] -= 1
                    subStackPageInfoIdx = 0
                elif pageType == "CACHE":
                    self.userSymData[allocSym]["cachePageCnt"] -= 1
                    self.kerSymData[allocKernelSym]["cachePageCnt"] -= 1
                    subStackPageInfoIdx = 1
                elif pageType == "KERNEL":
                    self.userSymData[allocSym]["kernelPageCnt"] -= 1
                    self.kerSymData[allocKernelSym]["kernelPageCnt"] -= 1
                    subStackPageInfoIdx = 2

                # get page lifetime #
                lifeTime = float(atime) - float(allocTime)

                # Set user page lifetime #
                if lifeTime > self.userSymData[allocSym]["pagePairMax"]:
                    self.userSymData[allocSym]["pagePairMax"] = lifeTime
                if (
                    self.userSymData[allocSym]["pagePairMin"] == 0
                    or lifeTime < self.userSymData[allocSym]["pagePairMin"]
                ):
                    self.userSymData[allocSym]["pagePairMin"] = lifeTime
                self.userSymData[allocSym]["pagePairTotal"] += lifeTime

                # Set kernel page lifetime #
                if lifeTime > self.kerSymData[allocKernelSym]["pagePairMax"]:
                    self.kerSymData[allocKernelSym]["pagePairMax"] = lifeTime
                if (
                    self.kerSymData[allocKernelSym]["pagePairMin"] == 0
                    or lifeTime
                    < self.kerSymData[allocKernelSym]["pagePairMin"]
                ):
                    self.kerSymData[allocKernelSym]["pagePairMin"] = lifeTime
                self.kerSymData[allocKernelSym]["pagePairTotal"] += lifeTime

                # Set user stack list #
                if self.sort == "sym":
                    targetStack = self.userSymData[allocSym]["symStack"]
                elif self.sort == "pos":
                    targetStack = self.userSymData[allocSym]["stack"]

                # Find user stack allocated this page #
                for val in targetStack:
                    if id(val[subStackIndex]) != allocStackAddr:
                        continue

                    val[pageAllocIndex] -= 1
                    val[argIndex][subStackPageInfoIdx] -= 1

                    # Set user stack list to free this page #
                    if self.sort == "sym":
                        subTargetStack = self.userSymData[sym]["symStack"]
                    elif self.sort == "pos":
                        subTargetStack = self.userSymData[sym]["stack"]

                    # Find user stack to free this page #
                    for sval in subTargetStack:
                        if id(sval[subStackIndex]) != stackAddr:
                            continue

                        if not self.userSymData[allocSym]["pagePair"]:
                            self.userSymData[allocSym]["pagePair"] = {}

                        allocCall = ""
                        freeCall = ""

                        try:
                            tsym = val[subStackIndex][0]
                            allocCall = "%s [%s]" % (
                                val[subStackIndex][0],
                                self.userSymData[tsym]["origBin"],
                            )
                            for usym in val[subStackIndex][1:]:
                                allocCall = "%s <- %s [%s]" % (
                                    allocCall,
                                    usym,
                                    self.userSymData[sym]["origBin"],
                                )
                        except:
                            if allocCall == "":
                                allocCall = "None"

                        try:
                            freeCall = "%s [%s]" % (
                                sym,
                                self.userSymData[sym]["origBin"],
                            )
                            for usym in sval[subStackIndex][1:]:
                                freeCall = "%s <- %s[%s]" % (
                                    freeCall,
                                    usym,
                                    self.userSymData[sym]["origBin"],
                                )
                        except:
                            if freeCall == "":
                                freeCall = "None"

                        pairId = "%s#%s" % (allocCall, freeCall)

                        try:
                            self.userSymData[allocSym]["pagePair"][pairId]
                        except:
                            self.userSymData[allocSym]["pagePair"][
                                pairId
                            ] = dict(self.init_glueData)

                        self.userSymData[allocSym]["pagePairCnt"] += 1
                        allocator = self.userSymData[allocSym]["pagePair"][
                            pairId
                        ]
                        allocator["size"] += 1

                        if not allocator["valueList"]:
                            allocator["valueList"] = {}
                        try:
                            allocator["valueList"][pageType] += 1
                        except:
                            allocator["valueList"][pageType] = 1

                        break
                    break

                # Set kernel stack list #
                kernelTargetStack = self.kerSymData[allocKernelSym]["stack"]

                # Find kernel stack allocated this page #
                for val in kernelTargetStack:
                    if id(val[subStackIndex]) != allocKernelStackAddr:
                        continue

                    val[pageAllocIndex] -= 1
                    val[argIndex][subStackPageInfoIdx] -= 1

                    # Set kernel stack list to free this page #
                    subTargetStack = self.kerSymData[ksym]["stack"]

                    # Find kernel stack to free this page #
                    for sval in subTargetStack:
                        if id(sval[subStackIndex]) != kstackAddr:
                            continue

                        kernelData = self.kerSymData[allocKernelSym]

                        if not kernelData["pagePair"]:
                            kernelData["pagePair"] = {}

                        allocCall = ""
                        freeCall = ""

                        try:
                            allocCall = (
                                "%s"
                                % self.posData[val[subStackIndex][0]]["symbol"]
                            )
                            for addr in val[subStackIndex][1:]:
                                allocCall = "%s <- %s" % (
                                    allocCall,
                                    self.posData[addr]["symbol"],
                                )
                        except:
                            if allocCall == "":
                                allocCall = "None"

                        try:
                            freeCall = "%s" % ksym
                            for addr in sval[subStackIndex]:
                                freeCall = "%s <- %s" % (
                                    freeCall,
                                    self.posData[addr]["symbol"],
                                )
                        except:
                            if freeCall == "":
                                freeCall = "None"

                        pairId = "%s#%s" % (allocCall, freeCall)

                        try:
                            kernelData["pagePair"][pairId]
                        except:
                            kernelData["pagePair"][pairId] = dict(
                                self.init_glueData
                            )

                        self.kerSymData[allocKernelSym]["pagePairCnt"] += 1
                        allocator = kernelData["pagePair"][pairId]
                        allocator["size"] += 1

                        if not allocator["valueList"]:
                            allocator["valueList"] = {}
                        try:
                            allocator["valueList"][pageType] += 1
                        except:
                            allocator["valueList"][pageType] = 1

                        break

                    break

                self.pageTable.pop(pfnv, None)
            except SystemExit:
                sys.exit(0)
            except:
                # this page is allocated before starting profile #

                self.pageUnknownFreeCnt += 1
                self.userSymData[sym]["unknownPageFreeCnt"] += 1
                self.kerSymData[ksym]["unknownPageFreeCnt"] += 1

                # Set user stack list #
                if self.sort == "sym":
                    targetStack = self.userSymData[sym]["symStack"]
                elif self.sort == "pos":
                    targetStack = self.userSymData[sym]["stack"]

                # Find subStack allocated this page #
                for val in targetStack:
                    if id(val[subStackIndex]) == stackAddr:
                        val[pageFreeIndex] += 1
                        break

                # Set kernel stack list #
                kernelTargetStack = self.kerSymData[ksym]["stack"]

                # Find subStack allocated this page #
                for val in kernelTargetStack:
                    if id(val[subStackIndex]) == kstackAddr:
                        val[pageFreeIndex] += 1
                        break

                continue

    def handlePageAlloc(
        self,
        sym,
        ksym,
        stackAddr,
        kstackAddr,
        pageAllocCnt,
        pageType,
        pfn,
        atime,
    ):

        subStackPageInfoIdx = 0

        subStackIndex = FunctionAnalyzer.symStackIdxTable.index("STACK")
        pageAllocIndex = FunctionAnalyzer.symStackIdxTable.index("PAGE_ALLOC")
        argIndex = FunctionAnalyzer.symStackIdxTable.index("ARGUMENT")

        # Increase counts of page to be allocated #
        self.userSymData[sym]["pageCnt"] += pageAllocCnt
        self.kerSymData[ksym]["pageCnt"] += pageAllocCnt

        if pageType == "USER":
            self.userSymData[sym]["userPageCnt"] += pageAllocCnt
            self.kerSymData[ksym]["userPageCnt"] += pageAllocCnt
            subStackPageInfoIdx = 0
        elif pageType == "CACHE":
            self.userSymData[sym]["cachePageCnt"] += pageAllocCnt
            self.kerSymData[ksym]["cachePageCnt"] += pageAllocCnt
            subStackPageInfoIdx = 1
        elif pageType == "KERNEL":
            self.userSymData[sym]["kernelPageCnt"] += pageAllocCnt
            self.kerSymData[ksym]["kernelPageCnt"] += pageAllocCnt
            subStackPageInfoIdx = 2

        # Set user stack list #
        if self.sort == "sym":
            targetStack = self.userSymData[sym]["symStack"]
        elif self.sort == "pos":
            targetStack = self.userSymData[sym]["stack"]

        # Find user stack of symbol allocated this page #
        for val in targetStack:
            if id(val[subStackIndex]) == stackAddr:
                # Increase page count of subStack #
                val[argIndex][subStackPageInfoIdx] += pageAllocCnt
                break

        # Set kernel stack list #
        kernelTargetStack = self.kerSymData[ksym]["stack"]

        # Find kernel stack of symbol allocated this page #
        for val in kernelTargetStack:
            if id(val[subStackIndex]) == kstackAddr:
                # Increase page count of subStack #
                val[argIndex][subStackPageInfoIdx] += pageAllocCnt
                break

        # Make PTE in page table #
        for cnt in xrange(pageAllocCnt):
            pfnv = pfn + cnt
            subStackPageInfoIdx = 0

            try:
                # Check whether this page is already allocated #
                allocSym = self.pageTable[pfnv]["sym"]

                allocStackAddr = self.pageTable[pfnv]["subStackAddr"]
                allocKernelSym = self.pageTable[pfnv]["ksym"]
                allocKernelStackAddr = self.pageTable[pfnv]["ksubStackAddr"]

                # Decrease counts of page already allocated but no free log #
                self.pageUsageCnt -= 1
                self.userSymData[allocSym]["pageCnt"] -= 1
                self.kerSymData[allocKernelSym]["pageCnt"] -= 1

                origPageType = self.pageTable[pfnv]["type"]
                if origPageType == "USER":
                    self.userSymData[allocSym]["userPageCnt"] -= 1
                    self.kerSymData[allocKernelSym]["userPageCnt"] -= 1
                    subStackPageInfoIdx = 0
                elif origPageType == "CACHE":
                    self.userSymData[allocSym]["cachePageCnt"] -= 1
                    self.kerSymData[allocKernelSym]["cachePageCnt"] -= 1
                    subStackPageInfoIdx = 1
                elif origPageType == "KERNEL":
                    self.userSymData[allocSym]["kernelPageCnt"] -= 1
                    self.kerSymData[allocKernelSym]["kernelPageCnt"] -= 1
                    subStackPageInfoIdx = 2

                # Set user stack list #
                if self.sort == "sym":
                    targetStack = self.userSymData[allocSym]["symStack"]
                elif self.sort == "pos":
                    targetStack = self.userSymData[allocSym]["stack"]

                # Find user stack of symbol allocated this page #
                for val in targetStack:
                    if id(val[subStackIndex]) == allocStackAddr:
                        # Decrease allocated page count of substack #
                        val[pageAllocIndex] -= 1
                        val[argIndex][subStackPageInfoIdx] -= 1
                        break

                # Set kernel stack list #
                kernelTargetStack = self.kerSymData[allocKernelSym]["stack"]

                # Find kernel stack of symbol allocated this page #
                for val in kernelTargetStack:
                    if id(val[subStackIndex]) == allocKernelStackAddr:
                        # Decrease allocated page count of substack #
                        val[pageAllocIndex] -= 1
                        val[argIndex][subStackPageInfoIdx] -= 1
                        break
            except SystemExit:
                sys.exit(0)
            except:
                self.pageTable[pfnv] = dict(self.init_pageLinkData)

            self.pageTable[pfnv]["sym"] = sym
            self.pageTable[pfnv]["ksym"] = ksym
            self.pageTable[pfnv]["type"] = pageType
            self.pageTable[pfnv]["subStackAddr"] = stackAddr
            self.pageTable[pfnv]["ksubStackAddr"] = kstackAddr
            self.pageTable[pfnv]["time"] = atime

    def mergeStacks(self):
        sym = ""
        ksym = ""
        stackAddr = 0
        kstackAddr = 0
        lineCnt = -1
        lastIdx = len(self.userCallData)

        # Backup page table used previously and Initialize it #
        self.oldPageTable = self.pageTable
        self.pageTable = {}

        # Backup heap table used previously and Initialize it #
        self.oldHeapTable = self.heapTable
        self.heapTable = {}

        subStackIndex = FunctionAnalyzer.symStackIdxTable.index("STACK")
        argIndex = FunctionAnalyzer.symStackIdxTable.index("ARGUMENT")

        # Merge call data by symbol or address #
        for val in self.userCallData:
            lineCnt += 1
            UtilMgr.printProgress(lineCnt, lastIdx - 1)

            pos = val[0]
            stack = val[1]
            event = val[2]
            eventCnt = val[3]
            arg = val[4]

            """
            Do not merge PAGE_FREE count
            because it will be merged with unknownPageFreeCnt
            """
            if event == "PAGE_FREE":
                savedEventCnt = eventCnt
                eventCnt = 0

            try:
                eventIndex = FunctionAnalyzer.symStackIdxTable.index(event)
            except:
                eventIndex = FunctionAnalyzer.symStackIdxTable.index("IGNORE")

            kernelPos = self.kernelCallData[lineCnt][0]
            kernelStack = self.kernelCallData[lineCnt][1]
            subStackPageInfo = list(self.init_subStackPageInfo)

            targetStack = []
            kernelTargetStack = []

            # Resolve user symbol #
            try:
                # No symbol related to last pos #
                if self.posData[pos]["symbol"] == "":
                    self.posData[pos]["symbol"] = pos
                    sym = pos
                else:
                    sym = self.posData[pos]["symbol"]
            except:
                continue

            # Resolve kernel symbol #
            try:
                # No symbol related to last pos #
                if self.posData[kernelPos]["symbol"] == "":
                    self.posData[kernelPos]["symbol"] = kernelPos
                    ksym = kernelPos
                else:
                    ksym = self.posData[kernelPos]["symbol"]
            except:
                continue

            # Make user file table of last pos in stack #
            try:
                path = self.posData[pos]["binary"]
                self.userFileData[path]
            except:
                self.userFileData[path] = dict(self.init_symData)

            # Make user symbol table of last pos in stack #
            try:
                self.userSymData[sym]
            except:
                self.userSymData[sym] = dict(self.init_symData)
                self.userSymData[sym]["stack"] = []
                self.userSymData[sym]["symStack"] = []
                self.userSymData[sym]["pos"] = pos
                self.userSymData[sym]["origBin"] = self.posData[pos]["origBin"]

            # Make kernel symbol table of last pos in stack #
            try:
                self.kerSymData[ksym]
            except:
                self.kerSymData[ksym] = dict(self.init_symData)
                self.kerSymData[ksym]["stack"] = []
                self.kerSymData[ksym]["pos"] = kernelPos

            # Set target user stack #
            if self.sort == "sym":
                tempSymStack = []
                # Make temporary symbol stack to merge stacks by symbol #
                for addr in stack:
                    tempSym = self.posData[addr]["symbol"]

                    # Ignore this function if there is no symbol #
                    if (
                        not SysMgr.showAll
                        and self.posData[addr]["origBin"] == "??"
                        and (
                            tempSym == addr
                            or tempSym == self.posData[addr]["offset"]
                            or addr == "00c0ffee"
                        )
                    ):
                        continue

                    # No symbol data #
                    if tempSym == "":
                        if self.posData[addr]["origBin"] == "??":
                            tempSym = "%x" % long(
                                self.posData[addr]["pos"], 16
                            )
                        else:
                            tempSym = "%x" % long(
                                self.posData[addr]["offset"], 16
                            )

                    try:
                        self.userSymData[tempSym]
                    except:
                        self.userSymData[tempSym] = dict(self.init_symData)
                        self.userSymData[tempSym]["stack"] = []
                        self.userSymData[tempSym]["symStack"] = []
                        self.userSymData[tempSym]["pos"] = addr
                        self.userSymData[tempSym]["origBin"] = self.posData[
                            addr
                        ]["origBin"]

                    tempSymStack.append(tempSym)

                # Switch input stack to symbol stack #
                stack = tempSymStack
                targetStack = self.userSymData[sym]["symStack"]
            elif self.sort == "pos":
                targetStack = self.userSymData[sym]["stack"]

            # First user stack related to this symbol #
            if not targetStack:
                tempList = [0] * len(FunctionAnalyzer.symStackIdxTable)
                tempList[eventIndex] = eventCnt
                tempList[subStackIndex] = stack
                tempList[argIndex] = list(subStackPageInfo)
                targetStack.append(tempList)

                stackAddr = id(stack)
            else:
                found = False

                # Find same stack by pos in stack list #
                for stackInfo in targetStack:
                    stackSet = set(stack)
                    subStackSet = set(stackInfo[subStackIndex])

                    # Found same stack #
                    if stackSet == subStackSet:
                        found = True
                        stackInfo[eventIndex] += eventCnt
                        stackAddr = id(stackInfo[subStackIndex])
                        break

                # New stack related to this symbol #
                if not found:
                    tempList = [0] * len(FunctionAnalyzer.symStackIdxTable)
                    tempList[eventIndex] = eventCnt
                    tempList[subStackIndex] = stack
                    tempList[argIndex] = list(subStackPageInfo)
                    targetStack.append(tempList)

                    stackAddr = id(stack)

            # Set target kernel stack #
            kernelTargetStack = self.kerSymData[ksym]["stack"]

            # First stack related to this symbol #
            if not kernelTargetStack:
                tempList = [0] * len(FunctionAnalyzer.symStackIdxTable)
                tempList[eventIndex] = eventCnt
                tempList[subStackIndex] = kernelStack
                tempList[argIndex] = list(subStackPageInfo)
                kernelTargetStack.append(tempList)

                kstackAddr = id(kernelStack)
            else:
                found = False
                for stackInfo in kernelTargetStack:
                    kerStackSet = set(kernelStack)
                    kerSubStackSet = set(stackInfo[subStackIndex])

                    # Found same stack in stack list #
                    if kerStackSet == kerSubStackSet:
                        found = True
                        stackInfo[eventIndex] += eventCnt
                        kstackAddr = id(stackInfo[subStackIndex])
                        break

                # New stack related to this symbol #
                if not found:
                    tempList = [0] * len(FunctionAnalyzer.symStackIdxTable)
                    tempList[eventIndex] = eventCnt
                    tempList[subStackIndex] = kernelStack
                    tempList[argIndex] = list(subStackPageInfo)
                    kernelTargetStack.append(tempList)

                    kstackAddr = id(kernelStack)

            # Recover PAGE_FREE count to merge with unknownPageFreeCnt #
            if event == "PAGE_FREE":
                eventCnt = savedEventCnt

            # memory allocation event #
            if event == "PAGE_ALLOC":
                pageType = arg[0]
                pfn = arg[1]
                atime = arg[2]

                self.handlePageAlloc(
                    sym,
                    ksym,
                    stackAddr,
                    kstackAddr,
                    eventCnt,
                    pageType,
                    pfn,
                    atime,
                )

            # memory free event #
            elif event == "PAGE_FREE":
                pageType = arg[0]
                pfn = arg[1]
                atime = arg[2]

                self.handlePageFree(
                    sym,
                    ksym,
                    stackAddr,
                    kstackAddr,
                    eventCnt,
                    pageType,
                    pfn,
                    atime,
                )

            # heap expand event #
            elif event == "HEAP_EXPAND":
                self.handleHeapExpand(
                    sym, ksym, stackAddr, kstackAddr, eventCnt, arg
                )

            # heap expand event #
            elif event == "HEAP_REDUCE":
                self.handleHeapReduce(eventCnt, arg)

            # block read event #
            elif event == "BLK_READ":
                self.userSymData[sym]["blockRdCnt"] += eventCnt
                self.kerSymData[ksym]["blockRdCnt"] += eventCnt

            # block write event #
            elif event == "BLK_WRITE":
                self.userSymData[sym]["blockWrCnt"] += eventCnt
                self.kerSymData[ksym]["blockWrCnt"] += eventCnt

            # lock try event #
            elif event == "LOCK_TRY":
                self.userSymData[sym]["lockTryCnt"] += eventCnt
                self.kerSymData[ksym]["lockTryCnt"] += eventCnt
                self.userFileData[path]["lockTryCnt"] += eventCnt

            # unlock event #
            elif event == "UNLOCK":
                self.userSymData[sym]["unlockCnt"] += eventCnt
                self.kerSymData[ksym]["unlockCnt"] += eventCnt
                self.userFileData[path]["unlockCnt"] += eventCnt

            # periodic event such as CPU tick #
            elif event == "CPU_TICK":
                self.userSymData[sym]["tickCnt"] += 1
                self.kerSymData[ksym]["tickCnt"] += 1
                self.userFileData[path]["tickCnt"] += 1

            # syscall event #
            elif event == "SYSCALL":
                self.userSymData[sym]["syscallCnt"] += 1
                self.kerSymData[ksym]["syscallCnt"] += 1
                self.userFileData[path]["syscallCnt"] += 1

            # periodic event such as CPU tick #
            elif event == "CUSTOM":
                if eventCnt > 0:
                    self.userSymData[sym]["customTotal"] += 1
                    self.kerSymData[ksym]["customTotal"] += 1
                    self.userFileData[path]["customTotal"] += 1

                self.userSymData[sym]["customCnt"] += eventCnt
                self.kerSymData[ksym]["customCnt"] += eventCnt
                self.userFileData[path]["customCnt"] += eventCnt

            # etc event #
            elif event == "IGNORE":
                try:
                    self.ignoreTable[arg]["ignCnt"] += 1
                except:
                    self.ignoreTable[arg] = {"ignCnt": long(1)}

            else:
                SysMgr.printWarn("failed to recognize event %s" % event)

        UtilMgr.deleteProgress()

        # Print summary about ignored events #
        self.printIgnoreEvents()

    def printIgnoreEvents(self):
        for idx, value in self.ignoreTable.items():
            SysMgr.printWarn(
                "ignore %s event %d times" % (idx, value["ignCnt"])
            )

    def getBinFromServer(self, remoteObj, src, des):
        if not remoteObj or remoteObj == "NONE":
            SysMgr.printErr(
                "wrong remote address, input in the format {IP:PORT}"
            )
            sys.exit(-1)

        # set download command #
        req = "DOWNLOAD:%s@%s" % (src, des)

        # get connection with server #
        self.connObj = NetworkMgr.getServerConn()
        if not self.connObj:
            return None

        # request download command #
        NetworkMgr.requestCmd(self.connObj, req)

    def getSymbols(self):
        binPath = ""
        offsetList = []
        curIdx = 0
        nrNoFile = 0
        lastIdx = len(self.posData)

        # Set alarm handler to handle hanged addr2line #
        signal.signal(signal.SIGALRM, SysMgr.timerHandler)

        # Get symbols and source pos #
        for idx, value in sorted(
            self.posData.items(), key=lambda e: e[1]["binary"], reverse=True
        ):
            curIdx += 1

            UtilMgr.printProgress(curIdx, lastIdx)

            # Handle thumbcode #
            if idx == "00c0ffee":
                value["binary"] = "??"
                value["origBin"] = "??"
                value["symbol"] = "ThumbCode"
                continue

            # Handle address #
            if value["binary"] == "":
                # user pos without offset #
                if value["symbol"] == "" or value["symbol"] == "??":
                    # TODO: find binary path and symbol of pos #
                    value["binary"] = "??"
                    value["origBin"] = "??"
                    value["symbol"] = idx
                continue

            # Get symbols from address list of previous binary #
            if binPath != value["binary"]:
                if binPath != "":
                    # Get symbols #
                    if self.getFileSymbolInfo(binPath, offsetList) == -1:
                        nrNoFile += 1
                    offsetList = []

                if value["offset"] == hex(0):
                    offsetList.append(idx)
                else:
                    offsetList.append(value["offset"])

                # Set new binPath to find symbol from address #
                binPath = value["binary"]

                # Get binary from server #
                if not os.path.isfile(binPath) and SysMgr.remoteServObj:
                    self.getBinFromServer(
                        SysMgr.remoteServObj, value["origBin"], binPath
                    )
            # add address to offsetList #
            else:
                # not relocatable binary #
                if value["offset"] == hex(0):
                    offsetList.append(idx)
                # relocatable binary #
                else:
                    offsetList.append(value["offset"])

        if self.posData:
            UtilMgr.deleteProgress()

        # Get symbols and source path from last binary #
        if binPath != "":
            if self.getFileSymbolInfo(binPath, offsetList) == -1:
                nrNoFile += 1

        if nrNoFile > 0:
            SysMgr.printWarn(
                "failed to find total %s binaries to analyze functions"
                % nrNoFile,
                True,
            )

    def getFileSymbolInfo(self, binPath, offsetList, onlyFunc=True):
        def _updateSymbol(addr, symbol, src, relocated):
            if not addr:
                return -1
            elif symbol == "??":
                symbol = addr

            # Check whether the file is relocatable or not #
            if not relocated:
                try:
                    savedSymbol = self.posData[addr]["symbol"]
                except:
                    return -1

                """
                Check whether saved symbol found by
                previous addr2line is right #
                """
                if (
                    not savedSymbol
                    or savedSymbol == ""
                    or savedSymbol == addr
                    or savedSymbol[0] == "$"
                ):
                    self.posData[addr]["symbol"] = symbol

                    if SysMgr.showAll:
                        self.posData[addr]["src"] = src
                    else:
                        fileIdx = src.rfind("/")
                        if fileIdx >= 0:
                            self.posData[addr]["src"] = src[fileIdx + 1 :]

                return

            inBinArea = False
            for idx, value in sorted(
                self.posData.items(),
                key=lambda e: e[1]["binary"],
                reverse=True,
            ):
                if value["binary"] == binPath:
                    inBinArea = True

                    if value["offset"] == addr:
                        savedSymbol = self.posData[idx]["symbol"]

                        if (
                            not savedSymbol
                            or savedSymbol == ""
                            or savedSymbol == addr
                            or savedSymbol[0] == "$"
                        ):
                            self.posData[idx]["symbol"] = symbol

                            if SysMgr.showAll:
                                self.posData[idx]["src"] = src
                            else:
                                fileIdx = src.rfind("/")
                                if fileIdx >= 0:
                                    self.posData[idx]["src"] = src[
                                        fileIdx + 1 :
                                    ]

                            break
                elif inBinArea:
                    break

        # Recognize binary type #
        relocated = ElfAnalyzer.isRelocFile(binPath)

        # No file exist #
        if not os.path.isfile(binPath):
            for addr in offsetList:
                try:
                    if not relocated:
                        self.posData[addr]["symbol"] = "NoFile"
                        self.posData[addr]["src"] = "NoFile"
                    else:
                        for idx, value in sorted(
                            self.posData.items(),
                            key=lambda e: e[1]["binary"],
                            reverse=True,
                        ):
                            if value["binary"] == binPath and value[
                                "offset"
                            ] == hex(long(addr, 16)):
                                self.posData[idx]["symbol"] = "NoFile"
                                self.posData[idx]["src"] = "NoFile"
                                break
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printWarn("failed to find address %s" % addr)
            return -1

        # check user-mode enabled #
        if not SysMgr.userEnable:
            return None

        # check addr2line path #
        if not "ADDR2LINE" in SysMgr.environList:
            try:
                symbolList = []
                binObj = ElfAnalyzer.getObject(binPath)
                if not binObj:
                    return None

                for offset in offsetList:
                    symbol, size = binObj.getSymbolByOffset(
                        offset, onlyFunc=onlyFunc
                    )

                    symbolList.append("??")

                    _updateSymbol(offset, symbol, "??", relocated)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("failed to get symbol from %s" % binPath, True)

            return None

            # get addr2line path #
            addr2linePath = UtilMgr.which("addr2line")
            if not addr2linePath:
                SysMgr.printErr(
                    (
                        "failed to find addr2line to analyze functions, "
                        "use -q option with ADDR2LINE to set binary path"
                    )
                )
                sys.exit(-1)

            SysMgr.printInfo(
                "use '%s' as the addr2line path" % ", ".join(addr2linePath)
            )
        else:
            for path in SysMgr.environList["ADDR2LINE"]:
                if not os.path.isfile(path):
                    SysMgr.printErr(
                        "failed to find %s to use addr2line" % path
                    )
                    sys.exit(-1)

        # get subprocess object #
        subprocess = SysMgr.getPkg("subprocess")

        for path in SysMgr.environList["ADDR2LINE"]:
            # Set addr2line command #
            args = [path, "-C", "-f", "-a", "-e", binPath]

            # Limit the number of arguments to be passed because of ARG_MAX #
            # ARG_MAX = $(getconf PAGE_SIZE)*32 = 131072 #
            listLen = len(offsetList)
            maxArgLine = 256
            offset = 0
            timeout = 10

            # Get symbol by address of every maxArgLine elements in list #
            while offset < listLen:
                # Launch addr2line #
                try:
                    workload = offsetList[offset : offset + maxArgLine - 1]
                    proc = subprocess.Popen(
                        args + workload,
                        stdout=subprocess.PIPE,
                        stderr=subprocess.PIPE,
                    )
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(
                        "failed to execute %s to pick symbols from binary"
                        % path
                    )
                    sys.exit(-1)

                # Increase offset count in address list #
                offset += maxArgLine

                try:
                    # Set alarm to handle hanged addr2line #
                    signal.alarm(timeout)

                    # Wait for addr2line to finish its job #
                    proc.wait()

                    # Cancel alarm after addr2line respond #
                    signal.alarm(0)
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printWarn(
                        "no response of addr2line for %s" % binPath
                    )
                    continue

                while 1:
                    # Get return of addr2line #
                    addr = (
                        proc.stdout.readline().decode().replace("\n", "")[2:]
                    )
                    try:
                        addr = hex(long(addr, 16)).rstrip("L")
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass

                    symbol = proc.stdout.readline().decode().replace("\n", "")
                    src = proc.stdout.readline().decode().replace("\n", "")

                    err = proc.stderr.readline().decode().replace("\n", "")
                    if err:
                        SysMgr.printWarn(err[err.find(":") + 2 :])

                    if _updateSymbol(addr, symbol, src, relocated):
                        break

    def initStacks(self):
        self.nowCtx["userLastPos"] = "0"
        self.nowCtx["userStack"] = []
        self.nowCtx["kerLastPos"] = "0"
        self.nowCtx["kerStack"] = []

    def swapEvents(self):
        tempEvent = self.nowCtx["nowEvent"]
        self.nowCtx["nowEvent"] = self.nowCtx["savedEvent"]
        self.nowCtx["savedEvent"] = tempEvent

        tempCnt = self.nowCtx["nowCnt"]
        self.nowCtx["nowCnt"] = self.nowCtx["savedCnt"]
        self.nowCtx["savedCnt"] = tempCnt

        tempArg = self.nowCtx["nowArg"]
        self.nowCtx["nowArg"] = self.nowCtx["savedArg"]
        self.nowCtx["savedArg"] = tempArg

    def saveFullStack(
        self,
        kernelPos,
        kernelStack,
        userPos,
        userStack,
        targetEvent,
        targetCnt,
        targetArg,
    ):

        # Save userstack #
        self.userCallData.append(
            [userPos, userStack, targetEvent, targetCnt, targetArg]
        )

        # Save kernelstack #
        self.kernelCallData.append(
            [kernelPos, kernelStack, targetEvent, targetCnt, targetArg]
        )

        # Save custom event stacks #
        if SysMgr.showAll and targetEvent == "CUSTOM":
            self.customCallData.append(
                [
                    targetArg[0],
                    targetArg[1],
                    self.userCallData[-1],
                    self.kernelCallData[-1],
                ]
            )

        # Save lock event stacks #
        if SysMgr.showAll and (
            targetEvent == "LOCK_TRY" or targetEvent == "UNLOCK"
        ):
            self.lockCallData.append(
                [
                    targetArg[0],
                    targetArg[1:],
                    self.userCallData[-1],
                    self.kernelCallData[-1],
                ]
            )

        # Save syscall event stacks #
        if SysMgr.showAll and targetEvent == "SYSCALL":
            self.sysCallData.append(
                [
                    targetArg[0],
                    targetArg[1:],
                    self.userCallData[-1],
                    self.kernelCallData[-1],
                ]
            )

    def saveEventStack(self, targetEvent, targetCnt, targetArg):
        kpos = self.nowCtx["kerLastPos"]
        upos = self.nowCtx["userLastPos"]

        # save count data #
        if targetEvent == "CPU_TICK":
            self.periodicEventCnt += 1

        elif targetEvent == "PAGE_ALLOC":
            self.pageAllocEventCnt += 1
            self.pageAllocCnt += targetCnt
            self.pageUsageCnt += targetCnt
            self.posData[kpos]["pageCnt"] += targetCnt
            self.posData[upos]["pageCnt"] += targetCnt

            pageType = targetArg[0]
            pfn = targetArg[1]
            time = targetArg[2]
            targetArg = [pageType, pfn, time]

        elif targetEvent == "PAGE_FREE":
            self.pageFreeEventCnt += 1
            self.pageFreeCnt += targetCnt

            pageType = targetArg[0]
            pfn = targetArg[1]
            time = targetArg[2]
            targetArg = [pageType, pfn, time]

        elif targetEvent == "BLK_READ":
            self.blockRdEventCnt += 1
            self.blockRdUsageCnt += targetCnt
            self.posData[kpos]["blockRdCnt"] += targetCnt
            self.posData[upos]["blockRdCnt"] += targetCnt

        elif targetEvent == "BLK_WRITE":
            self.blockWrEventCnt += 1
            self.blockWrUsageCnt += targetCnt
            self.posData[kpos]["blockWrCnt"] += targetCnt
            self.posData[upos]["blockWrCnt"] += targetCnt

        elif targetEvent == "LOCK_TRY":
            self.lockTryEventCnt += 1
            self.posData[kpos]["lockTryCnt"] += targetCnt
            self.posData[upos]["lockTryCnt"] += targetCnt

        elif targetEvent == "UNLOCK":
            self.unlockEventCnt += 1
            self.posData[kpos]["unlockCnt"] += targetCnt
            self.posData[upos]["unlockCnt"] += targetCnt

        elif targetEvent == "HEAP_EXPAND":
            self.heapExpEventCnt += 1
            self.heapExpSize += targetCnt
            self.posData[kpos]["heapSize"] += targetCnt
            self.posData[upos]["heapSize"] += targetCnt

        elif targetEvent == "HEAP_REDUCE":
            self.posData[kpos]["heapSize"] += targetCnt
            self.posData[upos]["heapSize"] += targetCnt

        elif targetEvent == "SYSCALL":
            nrSyscall = targetArg[0]
            self.syscallCnt += 1

            try:
                self.syscallTable[nrSyscall] += 0
            except:
                self.syscallTable[nrSyscall] = 1

            self.posData[kpos]["syscallCnt"] += targetCnt
            self.posData[upos]["syscallCnt"] += targetCnt

        elif targetEvent == "CUSTOM":
            if targetCnt > 0:
                self.customTotal += 1
                self.customCnt += targetCnt

                self.posData[kpos]["customTotal"] += 1
                self.posData[upos]["customTotal"] += 1

                self.posData[kpos]["customCnt"] += targetCnt
                self.posData[upos]["customCnt"] += targetCnt

        else:
            pass

        # cut stacks by depth #
        if SysMgr.funcDepth > 0:
            ksize = len(self.nowCtx["kerStack"])
            if ksize >= SysMgr.funcDepth:
                self.nowCtx["kerLastPos"] = self.nowCtx["kerStack"][
                    -SysMgr.funcDepth
                ]
                self.nowCtx["kerStack"] = self.nowCtx["kerStack"][
                    -SysMgr.funcDepth + 1 :
                ]

            usize = len(self.nowCtx["userStack"])
            if usize >= SysMgr.funcDepth:
                self.nowCtx["userLastPos"] = self.nowCtx["userStack"][
                    -SysMgr.funcDepth
                ]
                self.nowCtx["userStack"] = self.nowCtx["userStack"][
                    -SysMgr.funcDepth + 1 :
                ]

            if SysMgr.funcDepth == 1:
                self.nowCtx["kerStack"] = []
                self.nowCtx["userStack"] = []

        try:
            # save both stacks #
            self.saveFullStack(
                self.nowCtx["kerLastPos"],
                self.nowCtx["kerStack"],
                self.nowCtx["userLastPos"],
                self.nowCtx["userStack"],
                targetEvent,
                targetCnt,
                targetArg,
            )
        except:
            SysMgr.printErr("failed to save full stacks", True)
            sys.exit(-1)

    def saveCallStack(self):
        nowCtx = self.nowCtx

        # stack of kernel thread #
        if (
            not SysMgr.userRecordEnable
            or nowCtx["prevMode"] != nowCtx["curMode"] == "kernel"
        ):
            if not nowCtx["userStack"] and len(nowCtx["kerStack"]) > 0:
                # Set userLastPos to None #
                self.nowCtx["userLastPos"] = "0"
                self.nowCtx["userStack"].append("0")
            if not nowCtx["kerStack"] and len(nowCtx["userStack"]) > 0:
                # Set kerLastPos to None #
                self.nowCtx["kerLastPos"] = "0"
                self.nowCtx["kerStack"].append("0")

        # complicated situation ;( #
        elif nowCtx["prevMode"] == nowCtx["curMode"]:
            # previous user stack loss or nested interval #
            if nowCtx["curMode"] == "kernel":
                # nested interval #
                if nowCtx["nowEvent"] == "CPU_TICK":
                    # Backup kernel stack #
                    self.nowCtx["prevKerLastPos"] = nowCtx["kerLastPos"]
                    self.nowCtx["prevKerStack"] = nowCtx["kerStack"]

                    # Initialize both stacks #
                    self.initStacks()
                # previous user stack loss #
                else:
                    # Set userLastPos to None #
                    self.nowCtx["userLastPos"] = "0"
                    self.nowCtx["userStack"].append("0")
            # nested interval #
            elif nowCtx["curMode"] == "user":
                """
                CORE/0 EVENT0
                CORE/0 <kernel>
                CORE/0 <user>

                CORE/0 EVENT1
                CORE/0 <kernel>
                    CORE/0 EVENT2
                    CORE/0 <kernel>
                    CORE/0 <user>
                CORE/0 <user>
                """
                # Swap nowEvent and savedEvent #
                self.swapEvents()

        """
        Save both stacks of previous event before
        starting to record new kernel stack #
        """
        if (len(nowCtx["userStack"]) > 0 and nowCtx["userLastPos"] != "") and (
            len(nowCtx["kerStack"]) > 0 and nowCtx["kerLastPos"] != ""
        ):
            # Remove pc in each stacks #
            del self.nowCtx["kerStack"][0], self.nowCtx["userStack"][0]

            # Check whether there is nested event or not #
            if nowCtx["nested"] > 0:
                """
                CORE/0 EVENT0
                CORE/0 <kernel>
                CORE/0 <user>

                CORE/0 EVENT1
                    CORE/0 EVENT2
                    CORE/0 <kernel>
                    CORE/0 <user>
                CORE/0 <kernel>
                CORE/0 <user>
                """
                targetEvent = nowCtx["nestedEvent"]
                targetCnt = nowCtx["nestedCnt"]
                targetArg = nowCtx["nestedArg"]

                # Swap nowEvent and savedEvent #
                self.swapEvents()
            else:
                targetEvent = nowCtx["savedEvent"]
                targetCnt = nowCtx["savedCnt"]
                targetArg = nowCtx["savedArg"]

            # Save full stack of previous event #
            self.saveEventStack(targetEvent, targetCnt, targetArg)

            # Recover previous kernel stack after handling nested event #
            if (
                nowCtx["prevMode"] == nowCtx["curMode"] == "user"
                and nowCtx["prevKerLastPos"] != "0"
            ):
                self.nowCtx["kerLastPos"] = nowCtx["prevKerLastPos"]
                self.nowCtx["kerStack"] = nowCtx["prevKerStack"]
                self.nowCtx["prevKerLastPos"] = "0"
                self.nowCtx["prevKerStack"] = []
            else:
                self.nowCtx["kerLastPos"] = ""
                self.nowCtx["kerStack"] = []

            # Initialize user stack #
            self.nowCtx["userLastPos"] = ""
            self.nowCtx["userStack"] = []
            self.nowCtx["nestedEvent"] = ""
            self.nowCtx["nestedCnt"] = 0

        # On stack recording switch #
        self.nowCtx["recStat"] = True

    def savePosData(self, pos, path, offset):
        if self.nowCtx["nested"] > 0:
            targetEvent = self.nowCtx["savedEvent"]
        else:
            targetEvent = self.nowCtx["nowEvent"]

        # Register pos #
        try:
            self.posData[pos]
            if (
                path
                and path[0] == "/"
                and path != self.posData[pos]["origBin"]
            ):
                self.duplicatedPos += 1
                """
                SysMgr.printWarn(
                    "duplicated address %s in both '%s' and '%s'" % \
                    (pos, path, self.posData[pos]['origBin']))
                """
        except:
            self.posData[pos] = dict(self.init_posData)

        # user mode #
        if self.nowCtx["curMode"] == "user":
            # Set path #
            if path:
                self.posData[pos]["origBin"] = path
                self.posData[pos]["binary"] = SysMgr.rootPath + path
                self.posData[pos]["binary"] = os.path.normpath(
                    self.posData[pos]["binary"]
                )

                # Set offset #
                if offset:
                    if ElfAnalyzer.isRelocFile(path):
                        self.posData[pos]["offset"] = offset

            # Save pos #
            if not self.nowCtx["userStack"]:
                self.nowCtx["userLastPos"] = pos

                if targetEvent == "CPU_TICK":
                    self.posData[pos]["posCnt"] += 1
                elif targetEvent == "LOCK_TRY":
                    self.posData[pos]["lockTryCnt"] += 1
                elif targetEvent == "UNLOCK":
                    self.posData[pos]["unlockCnt"] += 1

            self.nowCtx["userStack"].append(pos)
        # kernel mode #
        elif self.nowCtx["curMode"] == "kernel":
            # Save pos #
            if not self.nowCtx["kerStack"]:
                self.nowCtx["kerLastPos"] = pos

                if targetEvent == "CPU_TICK":
                    self.posData[pos]["posCnt"] += 1
                elif targetEvent == "LOCK_TRY":
                    self.posData[pos]["lockTryCnt"] += 1
                elif targetEvent == "UNLOCK":
                    self.posData[pos]["unlockCnt"] += 1

            # Skip pos because it is usercall or no symbol #
            elif not SysMgr.showAll and not path:
                return

            self.posData[pos]["symbol"] = path

            self.nowCtx["kerStack"].append(pos)

        # wrong mode #
        else:
            SysMgr.printWarn("wrong current mode %s" % self.nowCtx["curMode"])

        # Increase total call count #
        if self.nowEvent == "CPU_TICK":
            self.posData[pos]["totalCnt"] += 1

    def allocHeapSeg(self, tid, size):
        try:
            self.heapTable[tid + "-ready"]["size"] = size
            self.heapTable[tid + "-ready"]["tid"] = tid
            self.threadData[tid]["heapSize"] -= size
            SysMgr.printWarn(
                "overwrite heap segment of %s(%s) at %s"
                % (self.threadData[tid]["comm"], tid, SysMgr.dbgEventLine)
            )
        except:
            self.heapTable[tid + "-ready"] = dict(self.init_heapSegData)
            self.heapTable[tid + "-ready"]["size"] = size
            self.heapTable[tid + "-ready"]["tid"] = tid

    def freeHeapSeg(self, addr):
        try:
            self.heapRedEventCnt += 1
            self.heapRedSize += self.heapTable[addr]["size"]

            # get tid #
            try:
                tid = self.heapTable[addr]["tid"]
            except:
                return

            self.threadData[tid]["heapSize"] -= self.heapTable[addr]["size"]

            self.heapTable.pop(addr, None)
        except:
            SysMgr.printWarn(
                "failed to free heap segment %s of %s(%s) at %s"
                % (
                    addr,
                    self.threadData[tid]["comm"],
                    tid,
                    SysMgr.dbgEventLine,
                )
            )

    def setHeapSegAddr(self, tid, addr):
        try:
            self.heapTable[addr] = dict(self.heapTable["%s-ready" % tid])
            del self.heapTable["%s-ready" % tid]
        except:
            SysMgr.printWarn(
                "failed to set address of heap segment %s of %s(%s) at %s"
                % (
                    addr,
                    self.threadData[tid]["comm"],
                    tid,
                    SysMgr.dbgEventLine,
                )
            )

    def parseLines(self, lines, desc):
        curIdx = 0
        lastIdx = len(lines)

        # make custom event table #
        if SysMgr.customCmd:
            for cmd in SysMgr.customCmd:
                cmd = cmd.split(":")

                if len(cmd) > 1:
                    self.customEventTable[cmd[0]] = cmd[1]
                else:
                    self.customEventTable[cmd[0]] = None

        # make kernel event table #
        if SysMgr.kernelCmd:
            for cmd in SysMgr.kernelCmd:
                cmd = cmd.split(":")
                self.customEventTable[cmd[0] + "_enter"] = None
                self.customEventTable[cmd[0] + "_exit"] = None

        # make user event table #
        if SysMgr.userCmd:
            for cmd in SysMgr.userCmd:
                cmd = cmd.split(":")
                self.customEventTable[cmd[0] + "_enter"] = None
                self.customEventTable[cmd[0] + "_exit"] = None

        # get pid filter by comm in advance #
        plist = {}
        if SysMgr.groupProcEnable:
            for key, value in self.getTargetList(lines).items():
                for item in desc:
                    if item in value["comm"]:
                        plist[value["tgid"]] = 0

        # start parsing logs #
        for liter in lines:
            curIdx += 1
            SysMgr.logSize += len(liter)
            SysMgr.curLine += 1
            SysMgr.dbgEventLine += 1

            ret = self.parse(liter, desc, plist)

            UtilMgr.printProgress(curIdx, lastIdx)

            # Skip lines before first meaningful event #
            if not self.lastCore:
                continue

            # Set context of current core #
            self.nowCtx = self.coreCtx[self.lastCore]

            # Save full stack to callData table #
            if ret is True:
                self.saveCallStack()
            elif ret is False:
                """
                Ignore this log because its not event or
                stack info related to target thread #
                """
                self.nowCtx["recStat"] = False
                continue
            # Save pos into target stack #
            elif self.nowCtx["recStat"]:
                # decode return value #
                (pos, path, offset) = ret

                self.savePosData(pos, path, offset)

        if lines:
            UtilMgr.deleteProgress()

        # update finish time #
        if self.finishTime == "0":
            self.finishTime = self.lastTime

        # Save stack of last events per core #
        for idx in list(self.coreCtx):
            self.lastCore = idx
            self.nowCtx = self.coreCtx[idx]

            # Recover previous mode #
            if SysMgr.userEnable:
                self.nowCtx["prevMode"] = "user"
            self.nowCtx["curMode"] = "kernel"

            self.saveEventParam("IGNORE", 0, 0)
            self.nowCtx["nested"] -= 1
            self.saveCallStack()

        if self.duplicatedPos > 0:
            SysMgr.printWarn(
                "found %d addresses duplicated" % self.duplicatedPos
            )

    def getCustomEventValue(self, func, args, cond):
        if not cond:
            return 1

        # set condition #
        if ">" in cond:
            condVal = cond[cond.find(">") + 1 :]
            condOp = ">"
            condStr = cond[: cond.find(">")]
        elif "<" in cond:
            condVal = cond[cond.find("<") + 1 :]
            condOp = "<"
            condStr = cond[: cond.find("<")]
        elif "==" in cond:
            condVal = cond[cond.find("==") + 2 :]
            condOp = "=="
            condStr = cond[: cond.find("==")]
        else:
            condStr = cond
            condOp = None
            condVal = None

        m = re.match(r"^.+%s=(?P<value>\S+)" % condStr, args)
        if not m:
            return 0

        d = m.groupdict()

        value = d["value"]

        if not condOp and value:
            try:
                return long(value)
            except:
                return 0
        elif condOp == ">":
            try:
                if long(value) > long(condVal):
                    return long(value)
            except:
                pass

            return 0
        elif condOp == "<":
            try:
                if long(value) < long(condVal):
                    return long(value)
            except:
                pass

            return 0
        elif condOp == "==":
            if value == condVal:
                return 1
            else:
                return 0
        else:
            return 0

    def saveEventParam(self, event, count, arg):
        # save context #
        self.nowCtx["nestedEvent"] = self.nowCtx["savedEvent"]
        self.nowCtx["savedEvent"] = self.nowCtx["nowEvent"]
        self.nowCtx["nowEvent"] = event

        self.nowCtx["nestedCnt"] = self.nowCtx["savedCnt"]
        self.nowCtx["savedCnt"] = self.nowCtx["nowCnt"]
        self.nowCtx["nowCnt"] = count

        self.nowCtx["nestedArg"] = self.nowCtx["savedArg"]
        self.nowCtx["savedArg"] = self.nowCtx["nowArg"]
        self.nowCtx["nowArg"] = arg

        self.nowCtx["nested"] += 1

        if self.nowCtx["nested"] > 2:
            # self.printDbgInfo()
            SysMgr.printWarn(
                (
                    "failed to analyze stack data "
                    "because of corruption (overflow) at %s\n"
                    "\tso report the results may differ from actual"
                )
                % SysMgr.dbgEventLine,
                True,
            )

    def printDbgInfo(self):
        data = self.nowCtx

        print(
            "[%s]" % self.lastCore,
            "(now) %s/%s/%s"
            % (data["nowEvent"], data["nowCnt"], data["nowArg"]),
            "(saved) %s/%s/%s"
            % (data["savedEvent"], data["savedCnt"], data["savedArg"]),
            "(nested) %s/%s/%s"
            % (data["nestedEvent"], data["nestedCnt"], data["nestedArg"]),
            "(user) %s/%s" % (data["userLastPos"], len(data["userStack"])),
            "(kernel) %s/%s" % (data["kerLastPos"], len(data["kerStack"])),
            "(backup) %s/%s"
            % (data["prevKerLastPos"], len(data["prevKerStack"])),
            "at %s" % SysMgr.dbgEventLine,
        )

    def parseEventInfo(self, tid, func, args, time, core):
        # check core filter #
        if (
            SysMgr.perCoreList
            and long(core) not in SysMgr.perCoreList
            and func[0] != "<"
        ):
            self.saveEventParam("IGNORE", 0, func[:-1])
            return False

        # check fixed event list #
        if self.customEventTable and (
            func[:-1] in self.customEventTable
            or len(
                [
                    event
                    for event in self.customEventTable
                    if event.endswith(func[:-1])
                ]
            )
            > 0
        ):
            isFixedEvent = False
        else:
            isFixedEvent = True

        # CPU tick event #
        # TODO: find shorter periodic event for sampling #
        if isFixedEvent and func == "hrtimer_start:":
            if "tick_sched_timer" in args:
                self.cpuEnabled = True

                self.saveEventParam("CPU_TICK", 1, 0)
            else:
                self.saveEventParam("IGNORE", 0, func[:-1])

            return False

        # memory allocation event #
        elif isFixedEvent and func == "mm_page_alloc:":
            m = re.match(
                (
                    r"^\s*page=\s*(?P<page>\S+)\s+pfn=(?P<pfn>[0-9]+)\s+"
                    r"order=(?P<order>[0-9]+)\s+migratetype=(?P<mt>[0-9]+)\s+"
                    r"gfp_flags=(?P<flags>\S+)"
                ),
                args,
            )
            if m:
                d = m.groupdict()

                # check whether it is huge page #
                if d["page"] == "(null)":
                    page = "huge"
                else:
                    page = d["page"]

                pfn = long(d["pfn"])
                flags = d["flags"]
                pageCnt = pow(2, long(d["order"]))

                # Increase page count of thread #
                self.threadData[tid]["nrPages"] += pageCnt

                # Increase page counts of thread #
                pageType = None
                if (
                    "NOFS" in flags
                    or "GFP_WRITE" in flags
                    or "0x1000000" in flags
                ):
                    pageType = "CACHE"
                    self.threadData[tid]["cachePages"] += pageCnt
                elif "USER" in flags:
                    pageType = "USER"
                    self.threadData[tid]["userPages"] += pageCnt
                else:
                    pageType = "KERNEL"
                    self.threadData[tid]["kernelPages"] += pageCnt

                # Make PTE in page table #
                for cnt in xrange(pageCnt):
                    pfnv = pfn + cnt

                    try:
                        """
                        Decrease page count of it's owner \
                        because this page was already allocated but no free log
                        """

                        ownerTid = self.pageTable[pfnv]["tid"]
                        self.threadData[ownerTid]["nrPages"] -= 1

                        origPageType = self.pageTable[pfnv]["type"]
                        if origPageType == "USER":
                            self.threadData[ownerTid]["userPages"] -= 1
                        elif origPageType == "CACHE":
                            self.threadData[ownerTid]["cachePages"] -= 1
                        elif origPageType == "KERNEL":
                            self.threadData[ownerTid]["kernelPages"] -= 1
                    except:
                        self.pageTable[pfnv] = dict(self.init_pageData)

                    self.pageTable[pfnv]["tid"] = tid
                    self.pageTable[pfnv]["page"] = page
                    self.pageTable[pfnv]["flags"] = flags
                    self.pageTable[pfnv]["type"] = pageType
                    self.pageTable[pfnv]["time"] = time

                self.memEnabled = True

                self.saveEventParam(
                    "PAGE_ALLOC", pageCnt, [pageType, pfn, time]
                )
            else:
                self.saveEventParam("IGNORE", 0, func[:-1])

                SysMgr.printWarn(
                    "failed to recognize event %s at %d"
                    % (func[:-1], SysMgr.dbgEventLine)
                )

            return False

        # memory free event #
        elif isFixedEvent and (
            func == "mm_page_free:" or func == "mm_page_free_direct:"
        ):
            m = re.match(
                (
                    r"^\s*page=(?P<page>\S+)\s+pfn=(?P<pfn>[0-9]+)\s+"
                    r"order=(?P<order>[0-9]+)"
                ),
                args,
            )
            if m:
                d = m.groupdict()

                page = d["page"]
                pfn = long(d["pfn"])
                pageCnt = pow(2, long(d["order"]))

                # Update page table #
                origPageType = None
                for cnt in xrange(pageCnt):
                    pfnv = pfn + cnt

                    try:
                        owner = self.pageTable[pfnv]["tid"]
                        origPageType = self.pageTable[pfnv]["type"]

                        self.threadData[owner]["nrPages"] -= 1

                        if origPageType == "CACHE":
                            self.threadData[owner]["cachePages"] -= 1
                        elif origPageType == "USER":
                            self.threadData[owner]["userPages"] -= 1
                        elif origPageType == "KERNEL":
                            self.threadData[owner]["kernelPages"] -= 1

                        self.threadData[tid]["nrKnownFreePages"] += 1

                        self.pageTable.pop(pfnv)
                    except:
                        # this page was allocated before starting profile #

                        self.threadData[tid]["nrUnknownFreePages"] += 1
                        continue

                self.memEnabled = True

                self.saveEventParam(
                    "PAGE_FREE", pageCnt, [origPageType, pfn, time]
                )

                return False

            SysMgr.printWarn(
                "failed to recognize event %s at %d"
                % (func[:-1], SysMgr.dbgEventLine)
            )

            self.saveEventParam("IGNORE", 0, func[:-1])

            return False

        # syscall / heap / lock events #
        elif isFixedEvent and func == "sys_enter:":
            m = re.match(r"^\s*NR (?P<nr>[0-9]+) (?P<args>.+)", args)
            if m:
                b = m.groupdict()

                num = long(b["nr"])

                self.threadData[tid]["lastNrSyscall"] = num

                # syscall event #
                if SysMgr.sysEnable:
                    self.sysEnabled = True

                    syscallList = SysMgr.syscallList

                    if not syscallList or num in syscallList:
                        args = b["args"][1:-1]

                        self.threadData[tid]["nrSyscall"] += 1

                        # set syscall table #
                        if not self.threadData[tid]["syscallTable"]:
                            self.threadData[tid]["syscallTable"] = {}

                        try:
                            self.threadData[tid]["syscallTable"][num] += 1
                        except:
                            self.threadData[tid]["syscallTable"][num] = 1

                        self.saveEventParam(
                            "SYSCALL", 1, [num, args, time, core, tid]
                        )

                        return False

                # heap increasement event #
                elif num == ConfigMgr.getMmapId():
                    self.heapEnabled = True

                    try:
                        size = long(b["args"].split(",")[1], 16)

                        # just brk call to check data segment address #
                        if size == 0:
                            pass

                        self.threadData[tid]["heapSize"] += size
                    except:
                        self.saveEventParam("IGNORE", 0, func[:-1])

                        return False

                    # make heap segment tid-ready #
                    self.allocHeapSeg(tid, size)

                    self.saveEventParam("IGNORE", 0, func[:-1])

                    return False

                # heap decreasement event #
                elif num == SysMgr.getNrSyscall("sys_munmap"):
                    self.heapEnabled = True

                    try:
                        addr = long(b["args"][1:].split(",")[0], 16)
                        size = self.heapTable[addr]["size"]

                        # remove heap segment #
                        self.freeHeapSeg(addr)

                        self.saveEventParam(
                            "HEAP_REDUCE", size, [addr, time, core, tid]
                        )

                        return False
                    except:
                        pass

                # lock event #
                elif num == SysMgr.getNrSyscall("sys_futex"):
                    n = re.match(
                        (
                            r"^\s*(?P<uaddr>\S+), (?P<op>\S+), "
                            r"(?P<val>\S+), (?P<timer>\S+),"
                        ),
                        b["args"],
                    )
                    if n:
                        l = n.groupdict()

                        FUTEX_CMD_MASK = ~(128 | 256)
                        # FUTEX_PRIVATE_FLAG: 128, FUTEX_CLOCK_REALTIME: 256 #
                        maskedOp = long(l["op"], base=16) & FUTEX_CMD_MASK

                        addr = l["uaddr"][1:]

                        try:
                            event = ConfigMgr.FUTEX_TYPE[maskedOp]
                        except:
                            event = "LOCK"

                        # lock_pi #
                        if event in ("FUTEX_LOCK_PI", "FUTEX_TRYLOCK_PI"):
                            self.lockEnabled = True
                            self.threadData[tid]["nrLockTry"] += 1
                            self.saveEventParam(
                                "LOCK_TRY", 1, [event, addr, time, core, tid]
                            )
                            return False
                        # wait #
                        elif event in (
                            "FUTEX_WAIT",
                            "FUTEX_WAIT_REQUEUE_PI",
                            "FUTEX_WAIT_BITSET",
                        ):
                            self.lockEnabled = True
                            self.threadData[tid]["nrLockTry"] += 1
                            self.saveEventParam(
                                "LOCK_TRY", 1, [event, addr, time, core, tid]
                            )
                            return False
                        # unlock #
                        elif event == "FUTEX_UNLOCK_PI":
                            self.lockEnabled = True
                            self.threadData[tid]["nrUnlock"] += 1
                            self.saveEventParam(
                                "UNLOCK", 1, [event, addr, time, core, tid]
                            )
                            return False

            else:
                SysMgr.printWarn(
                    "failed to recognize event %s at %d"
                    % (func[:-1], SysMgr.dbgEventLine)
                )

            self.saveEventParam("IGNORE", 0, func[:-1])

            return False

        # syscall / heap events #
        elif isFixedEvent and func == "sys_exit:":
            m = re.match(r"^\s*NR (?P<nr>\S+) = (?P<ret>.+)", args)
            if m:
                b = m.groupdict()

                nr = long(b["nr"])

                # handle wrong syscall number #
                if nr < 0:
                    if self.threadData[tid]["lastNrSyscall"] >= 0:
                        nr = self.threadData[tid]["lastNrSyscall"]

                # heap increasement event #
                if nr == ConfigMgr.getMmapId():
                    self.heapEnabled = True

                    addr = long(b["ret"])

                    # rename heap segment from tid-ready to addr #
                    self.setHeapSegAddr(tid, addr)

                    try:
                        size = self.heapTable[addr]["size"]

                        self.saveEventParam(
                            "HEAP_EXPAND", size, [addr, time, core, tid]
                        )

                        return False
                    except:
                        pass

                # heap decreasement event #
                elif nr == SysMgr.getNrSyscall("sys_brk"):
                    self.heapEnabled = True

                    addr = long(b["ret"])

                    try:
                        pid = self.threadData[tid]["tgid"]
                        if pid.startswith("-"):
                            pid = SysMgr.savedProcTree[tid]
                        self.threadData[pid]
                    except:
                        pid = tid

                    try:
                        self.threadData[pid]["lastBrk"]

                        if addr > self.threadData[pid]["lastBrk"]:
                            size = addr - self.threadData[pid]["lastBrk"]

                            self.threadData[pid]["heapSize"] += size

                            self.saveEventParam(
                                "HEAP_EXPAND", size, [addr, time, core, tid]
                            )

                            return False
                    except:
                        self.threadData[pid]["lastBrk"] = addr
            else:
                SysMgr.printWarn(
                    "failed to recognize event %s at %d"
                    % (func[:-1], SysMgr.dbgEventLine)
                )

            self.saveEventParam("IGNORE", 0, func[:-1])

            return False

        # block request event #
        elif isFixedEvent and func == "block_bio_queue:":
            m = re.match(
                (
                    r"^\s*(?P<major>[0-9]+),(?P<minor>[0-9]+)\s*"
                    r"(?P<operation>\S+)\s*(?P<address>\S+)\s+\+\s+"
                    r"(?P<size>[0-9]+)"
                ),
                args,
            )
            if m:
                b = m.groupdict()

                """
                The operation to specific virtual devices such like
                device-mapper is remapped to another device by block_bio_queue
                event. It will probably make the workload look multiple times.
                """

                opt = b["operation"]

                if opt[0] == "R":
                    self.breadEnabled = True

                    blockRdCnt = long(b["size"])
                    self.threadData[tid]["nrRdBlocks"] += blockRdCnt

                    self.saveEventParam("BLK_READ", blockRdCnt, 0)

                    return False
                elif opt == "WS":
                    self.bwriteEnabled = True

                    blockWrCnt = long(b["size"])
                    self.threadData[tid]["nrWrBlocks"] += blockWrCnt

                    self.saveEventParam("BLK_WRITE", blockWrCnt, 0)

                    return False

            SysMgr.printWarn(
                "failed to recognize event %s at %d"
                % (func[:-1], SysMgr.dbgEventLine)
            )

            self.saveEventParam("IGNORE", 0, func[:-1])

            return False

        # block write request event #
        elif isFixedEvent and func == "writeback_dirty_page:":
            m = re.match(
                (
                    r"^\s*bdi\s+(?P<major>[0-9]+):(?P<minor>[0-9]+):\s*"
                    r"ino=(?P<ino>\S+)\s+index=(?P<index>\S+)"
                ),
                args,
            )
            if m:
                b = m.groupdict()
                self.bwriteEnabled = True

                self.threadData[tid]["nrWrBlocks"] += 8

                self.saveEventParam("BLK_WRITE", 8, 0)

                return False

            self.saveEventParam("IGNORE", 0, func[:-1])

            return False

        # block write request event #
        elif isFixedEvent and func == "wbc_writepage:":
            m = re.match(
                (
                    r"^\s*bdi\s+(?P<major>[0-9]+):(?P<minor>[0-9]+):\s*"
                    r"towrt=(?P<towrt>\S+)\s+skip=(?P<skip>\S+)"
                ),
                args,
            )
            if m:
                d = m.groupdict()

                if d["skip"] == "0":
                    self.bwriteEnabled = True

                    self.threadData[tid]["nrWrBlocks"] += 8

                    self.saveEventParam("BLK_WRITE", 8, 0)

                    return False

            self.saveEventParam("IGNORE", 0, func[:-1])

            return False

        # segmentation fault generation event #
        elif isFixedEvent and func == "signal_generate:":
            m = re.match(
                (
                    r"^\s*sig=(?P<sig>[0-9]+) errno=(?P<err>[0-9]+) "
                    r"code=(?P<code>.*) comm=(?P<comm>.*) "
                    r"pid=(?P<pid>[0-9]+)"
                ),
                args,
            )
            if m:
                b = m.groupdict()

                if b["sig"] == str(signal.SIGSEGV):
                    self.sigEnabled = True

                    self.saveEventParam("SIGSEGV_GEN", 0, 0)

                    return False

            SysMgr.printWarn(
                "failed to recognize event %s at %d"
                % (func[:-1], SysMgr.dbgEventLine)
            )

            self.saveEventParam("IGNORE", 0, func[:-1])

            return False

        elif isFixedEvent and func == "signal_deliver:":
            m = re.match(
                (
                    r"^\s*sig=(?P<sig>[0-9]+) errno=(?P<err>[0-9]+) "
                    r"code=(?P<code>.*) sa_handler=(?P<handler>.*) "
                    r"sa_flags=(?P<flags>.*)"
                ),
                args,
            )
            if m:
                b = m.groupdict()

                if b["sig"] == str(signal.SIGSEGV):
                    self.sigEnabled = True

                    self.saveEventParam("SIGSEGV_DLV", 0, 0)
                else:
                    self.saveEventParam("IGNORE", 0, func[:-1])
            else:
                self.saveEventParam("IGNORE", 0, func[:-1])

            return False

        elif isFixedEvent and func == "locks_get_lock_context:":
            m = re.match(
                (
                    r"^\s*dev=(?P<dev>.+)\s+ino=(?P<ino>.+)"
                    r"\s+type=(?P<type>.+)\s+ctx=(?P<ctx>.+)"
                ),
                args,
            )
            if m:
                d = m.groupdict()
                if d["type"] == "F_UNLCK":
                    self.saveEventParam("IGNORE", 0, func[:-1])
                else:
                    self.lockEnabled = True

                    self.threadData[tid]["nrLockTry"] += 1

                    self.saveEventParam(
                        "LOCK_TRY", 1, ["FLOCK", d["ino"], time, core, tid]
                    )
            else:
                self.saveEventParam("IGNORE", 0, func[:-1])

            return False

        # Start to record user stack #
        elif func == "<user":
            self.nowCtx["prevMode"] = self.nowCtx["curMode"]
            self.nowCtx["curMode"] = "user"

            return True

        # Start to record kernel stack #
        elif func == "<stack":
            self.nowCtx["prevMode"] = self.nowCtx["curMode"]
            self.nowCtx["curMode"] = "kernel"
            self.nowCtx["nested"] -= 1

            if self.nowCtx["nested"] < 0:
                # self.printDbgInfo()
                SysMgr.printWarn(
                    (
                        "failed to analyze stack data "
                        "because of corruption (underflow) at %s\n"
                        "\tso report the results may differ from actual"
                    )
                    % SysMgr.dbgEventLine,
                    True,
                )

            return True

        # custom event #
        elif not isFixedEvent:
            try:
                if not [
                    event
                    for event in self.customEventTable
                    if event.endswith(func[:-1])
                ]:
                    cond = self.customEventTable[func[:-1]] = None
                else:
                    cond = self.customEventTable[func[:-1]]

                # set event filter #
                customCnt = self.getCustomEventValue(func, args, cond)

                if customCnt > 0:
                    self.threadData[tid]["customTotal"] += customCnt

                self.saveEventParam(
                    "CUSTOM", customCnt, [func[:-1], [args, time, core, tid]]
                )
            except:
                self.saveEventParam("IGNORE", 0, func[:-1])

            return False

        # Ignore event #
        else:
            self.saveEventParam("IGNORE", 0, func[:-1])

            return False

    def getTargetList(self, tlist):
        threadData = {}

        for liter in tlist:
            m = SysMgr.getTraceItem(liter)
            if m:
                d = m.groupdict()

                # Make thread entity #
                thread = d["thread"]
                try:
                    threadData[thread]["comm"] = d["comm"]
                except:
                    threadData[thread] = {}
                    threadData[thread]["comm"] = d["comm"]

                # set tgid #
                try:
                    threadData[thread]["tgid"] = d["tgid"]
                except:
                    try:
                        threadData[thread]["tgid"] = SysMgr.savedProcTree[
                            thread
                        ]
                    except:
                        pass

        return threadData

    def parse(self, string, desc, plist=[]):
        m = SysMgr.getTraceItem(string)
        if m:
            d = m.groupdict()

            self.lastTime = d["time"]

            if (
                SysMgr.countEnable
                and SysMgr.repeatCount * SysMgr.intervalEnable
                <= float(d["time"]) - float(SysMgr.startTime)
            ):
                self.lastCore = None
                return False

            # Make thread entity #
            thread = d["thread"]
            try:
                self.threadData[thread]["comm"] = d["comm"]
            except:
                self.threadData[thread] = dict(self.init_threadData)
                self.threadData[thread]["comm"] = d["comm"]

            # set tgid #
            try:
                if d["tgid"].startswith("-"):
                    raise Exception("no tgid")
                self.threadData[thread]["tgid"] = d["tgid"]
            except:
                try:
                    self.threadData[thread]["tgid"] = SysMgr.savedProcTree[
                        thread
                    ]
                except:
                    pass

            # increase event count #
            self.threadData[thread]["eventCnt"] += 1

            # set current core #
            self.lastCore = d["core"]

            # Make core entity #
            try:
                self.coreCtx[self.lastCore]
            except:
                self.coreCtx[self.lastCore] = dict(self.init_ctxData)
                self.coreCtx[self.lastCore]["userStack"] = []
                self.coreCtx[self.lastCore]["kerStack"] = []
                self.coreCtx[self.lastCore]["prevKerStack"] = []

            # set context of current core #
            self.nowCtx = self.coreCtx[self.lastCore]

            # Check core filter #
            if (
                SysMgr.perCoreList
                and long(d["core"]) not in SysMgr.perCoreList
                and not d["func"].startswith("tracing_mark_write")
                and d["func"] != "0:"
            ):
                pass

            # Calculate a total of CPU usage #
            elif (
                d["func"] == "hrtimer_start:"
                and "tick_sched_timer" in d["etc"]
            ):
                self.totalTick += 1
                self.threadData[thread]["cpuTick"] += 1

                # Set global interval #
                if self.nowCtx["prevTid"]:
                    diff = float(d["time"]) - float(self.nowCtx["prevTime"])
                    self.periodicEventInterval += diff
                    self.periodicContEventCnt += 1

                self.nowCtx["prevTid"] = thread
                self.nowCtx["prevTime"] = d["time"]

                # Set max core to calculate CPU usage of thread #
                if SysMgr.maxCore < long(d["core"]):
                    SysMgr.maxCore = long(d["core"])

            # Mark die flag of thread that is not able to be profiled #
            elif d["func"] == "sched_process_exit:":
                m = re.match(
                    r"^\s*comm=(?P<comm>.*)\s+pid=(?P<pid>[0-9]+)", d["etc"]
                )
                if m:
                    p = m.groupdict()

                    pid = p["pid"]

                    try:
                        self.threadData[pid]
                    except:
                        self.threadData[pid] = dict(self.init_threadData)
                        self.threadData[pid]["comm"] = p["comm"]

                    self.threadData[pid]["die"] = True

            # Make thread name #
            elif d["func"] == "sched_process_fork:":
                m = re.match(
                    (
                        r"^\s*comm=(?P<comm>.*)\s+pid=(?P<pid>[0-9]+)\s+"
                        r"child_comm=(?P<child_comm>.*)\s+"
                        r"child_pid=(?P<child_pid>[0-9]+)"
                    ),
                    d["etc"],
                )
                if m:
                    p = m.groupdict()

                    cpid = p["child_pid"]
                    ccomm = p["child_comm"]

                    try:
                        self.threadData[cpid]
                    except:
                        self.threadData[cpid] = dict(self.init_threadData)
                        self.threadData[cpid]["comm"] = ccomm
                        self.threadData[cpid]["new"] = True
                        self.threadData[cpid]["ptid"] = thread

            # Make thread name #
            elif d["func"] == "task_newtask:":
                m = re.match(
                    r"^\s*pid=(?P<pid>[0-9]+)\s+comm=(?P<comm>\S+)", d["etc"]
                )
                if m:
                    p = m.groupdict()

                    pid = p["pid"]

                    try:
                        self.threadData[pid]
                    except:
                        self.threadData[pid] = dict(self.init_threadData)
                        self.threadData[pid]["comm"] = p["comm"]
                        self.threadData[pid]["new"] = True
                        self.threadData[pid]["ptid"] = thread

            # Save user event #
            elif (
                d["func"].startswith("tracing_mark_write") or d["func"] == "0:"
            ):
                m = re.match(r"^.+EVENT_(?P<event>\S+)", d["etc"])
                if m:
                    gd = m.groupdict()

                    EventAnalyzer.addEvent(d["time"], gd["event"])

                    if gd["event"] == "STOP":
                        self.finishTime = float(d["time"])

                # Return False because no stack data with this event #
                return False

            # apply filter #
            if SysMgr.isExceptTarget(thread, self.threadData, plist=plist):
                return False
            else:
                self.threadData[thread]["target"] = True

            return self.parseEventInfo(
                thread, d["func"], d["etc"], d["time"], d["core"]
            )

        # Parse call stack #
        else:
            # exist path, offset, pos #
            m = re.match(
                (
                    r" => (?P<path>.+)\[\+0x(?P<offset>.\S*)\] "
                    r"\<(?P<pos>.\S+)\>"
                ),
                string,
            )
            if m:
                d = m.groupdict()
                return (d["pos"], d["path"], hex(long(d["offset"], 16)))

            # exist only pos #
            pos = string.find("=>  <")
            if pos > -1:
                return (string[pos + 5 : len(string) - 2], None, None)

            # no user stack tracing supported #
            if "??" in string:
                if SysMgr.userEnable and SysMgr.userEnableWarn:
                    SysMgr.printWarn(
                        (
                            "enable CONFIG_USER_STACKTRACE_SUPPORT kernel"
                            " option if it is not enabled"
                        ),
                        True,
                    )
                    SysMgr.userEnableWarn = False
                return ("0", None, None)

            # exist symbol, pos #
            m = re.match(r" => (?P<symbol>.+) \<(?P<pos>.\S+)\>", string)
            if m:
                d = m.groupdict()
                return (d["pos"], d["symbol"], None)

            # garbage log #
            return False

    def getBinInfo(self, addr):
        for data in self.mapData:
            if long(data["startAddr"], 16) <= long(addr, 16) and long(
                data["endAddr"], 16
            ) >= long(addr, 16):
                if ElfAnalyzer.isRelocFile(data["binName"]):
                    # Return full path and offset in mapping table #
                    return SysMgr.rootPath + data["binName"], hex(
                        long(addr, 16) - long(data["startAddr"], 16)
                    )
                else:
                    return SysMgr.rootPath + data["binName"], hex(
                        long(addr, 16)
                    )
        SysMgr.printWarn(
            "failed to get the binary info of %s in mapping table" % addr
        )

    def printSyscallSummary(self):
        # no effective syscall event #
        if self.syscallCnt == 0:
            return

        convNum = UtilMgr.convNum

        SysMgr.clearPrint()
        SysMgr.printPipe(
            "[Function Syscall Info] [Cnt: %s]\n%s"
            % (convNum(self.syscallCnt), twoLine)
        )
        SysMgr.printPipe(
            "{0:>16}({1:>7}/{2:>7}) {3:>30}({4:>3}) {5:>12}\n{6:1}".format(
                "Name", "TID", "PID", "Syscall", "SID", "Count", twoLine
            )
        )

        outputCnt = 0
        for key, value in sorted(
            self.threadData.items(),
            key=lambda e: e[1]["nrSyscall"],
            reverse=True,
        ):
            threadInfo = ""
            syscallInfo = ""

            if key.startswith("0["):
                continue

            try:
                if value["syscallTable"]:
                    threadInfo = "%16s(%7s/%7s)" % (
                        value["comm"],
                        key,
                        value["tgid"],
                    )
                else:
                    continue
            except:
                continue

            for sysId, val in sorted(
                value["syscallTable"].items(), key=lambda e: e[1], reverse=True
            ):
                if val == 0:
                    continue

                try:
                    syscall = ConfigMgr.sysList[sysId][4:]
                except:
                    SysMgr.printErr(
                        "failed to get syscall name by number %s" % sysId
                    )
                    syscall = sysId

                syscallInfo = ("{0:1} {1:>30}({2:>3}) {3:>12}\n").format(
                    syscallInfo + (" " * len(threadInfo)),
                    syscall,
                    sysId,
                    convNum(val),
                )

            if syscallInfo != "":
                outputCnt += 1
                SysMgr.printPipe(threadInfo)
                SysMgr.printPipe(syscallInfo + oneLine)

        if outputCnt == 0:
            SysMgr.printPipe("\tNone\n%s" % oneLine)

        SysMgr.printPipe("\n\n")

    def printUsage(self):
        targetCnt = 0
        self.totalTime = float(self.finishTime) - float(SysMgr.startTime)

        convSize = UtilMgr.convSize2Unit
        convNum = UtilMgr.convNum

        SysMgr.printLogo(big=True)

        # print system information #
        SysMgr.printInfoBuffer()

        # choose syscall / heap menu in table #
        if self.sysEnabled:
            cmenu = "SYSTEM"
            cmenu2 = "CALLS"
        else:
            cmenu = "HEAP"
            cmenu2 = "EVENTS"

        # Print thread list #
        SysMgr.printPipe(
            "[%s] [%s: %0.3f] [%s: %0.3f] [Threads: %d] [LogSize: %s]\n%s"
            % (
                "Function Thread Info",
                "Elapsed",
                round(self.totalTime, 7),
                "Start",
                round(float(SysMgr.startTime), 7),
                len(self.threadData),
                convSize(SysMgr.logSize),
                twoLine,
            )
        )
        SysMgr.printPipe(
            (
                "{0:_^46}|{1:_^7}|{2:_^54}|{3:_^8}|"
                "{4:_^18}|{5:_^6}|{6:_^8}|"
            ).format("Thread", "CPU", "PAGE", cmenu, "BLOCK", "LOCK", "CUSTOM")
        )
        SysMgr.printPipe(
            (
                "{0:^16}|{0:^7}|{0:^7}|{0:^6}|{0:^6}|{0:^7}|"
                "{0:^9}{0:^8}{0:^8}{0:^12}|{0:^8}|{0:^7}|{0:^8}|"
                "{0:^8}|{0:^9}|{0:^6}|{0:^8}|"
            ).format(" ")
        )

        SysMgr.printPipe(
            (
                "{0:_^16}|{1:_^7}|{2:_^7}|{3:_^6}|{4:_^6}|"
                "{5:_^7}|{6:_^9}({7:_^8}/{8:_^8}/{9:_^8})|{10:_^8}|"
                "{11:_^7}|{12:_^8}|{13:_^8}|{14:_^9}|{15:_^6}|{16:_^8}|"
            ).format(
                "Name",
                "TID",
                "PID",
                "PICK",
                "LIFE",
                "PER",
                "ALLOC",
                "USER",
                "BUF",
                "KERN",
                "FREE",
                "UFREE",
                cmenu2,
                "READ",
                "WRITE",
                "TRY",
                "EVENTS",
            )
        )
        SysMgr.printPipe(twoLine)

        # set sort value #
        if SysMgr.sort == "m":
            sortedThreadData = sorted(
                self.threadData.items(),
                key=lambda e: e[1]["nrPages"],
                reverse=True,
            )
        elif SysMgr.sort == "b":
            sortedThreadData = sorted(
                self.threadData.items(),
                key=lambda e: e[1]["nrRdBlocks"],
                reverse=True,
            )
        elif SysMgr.sort == "L":
            sortedThreadData = sorted(
                self.threadData.items(),
                key=lambda e: e[1]["nrLockTry"],
                reverse=True,
            )
        elif SysMgr.sort == "h":
            sortedThreadData = sorted(
                self.threadData.items(),
                key=lambda e: e[1]["heapSize"],
                reverse=True,
            )
        elif SysMgr.sort == "s":
            sortedThreadData = sorted(
                self.threadData.items(),
                key=lambda e: e[1]["nrSyscall"],
                reverse=True,
            )
        else:
            # set CPU usage as default #
            sortedThreadData = sorted(
                self.threadData.items(),
                key=lambda e: e[1]["cpuTick"],
                reverse=True,
            )

        for idx, value in sortedThreadData:
            targetMark = ""

            # skip no event count thread #
            if value["eventCnt"] == 0:
                continue

            # check target thread #
            if value["target"]:
                targetCnt += 1
                if targetCnt == 2:
                    SysMgr.printWarn("multiple target threads are selected")
                targetMark = "*"

            # get CPU usage #
            if self.totalTick > 0:
                cpuPer = "%.1f%%" % (
                    float(value["cpuTick"]) / float(self.totalTick) * 100
                )
            else:
                cpuPer = "0.0%%"

            # set break condition #
            if SysMgr.sort == "m":
                breakCond = value["nrPages"]
            elif SysMgr.sort == "b":
                breakCond = value["nrRdBlocks"]
            else:
                breakCond = long(cpuPer[: cpuPer.rfind(".")])

            # check condition for stop #
            if breakCond < 1 and not SysMgr.showAll:
                pass

            # set lifecycle flags #
            if value["new"]:
                life = "N"
            else:
                life = " "
            if value["die"]:
                life = "%sD" % life

            if self.cpuEnabled:
                # remove percentage if no tick #
                if float(value["cpuTick"]) == 0:
                    cpuPer = "-"
                else:
                    cpuPer = cpuPer
            else:
                cpuPer = "-"

            if self.sysEnabled:
                cval = "%s" % convNum(value["nrSyscall"])
            elif self.heapEnabled:
                cval = "%s" % convSize(value["heapSize"])
            else:
                cval = "-"

            if self.memEnabled:
                allocMem = "%s" % convSize(value["nrPages"] << 12)
                userMem = "%s" % convSize(value["userPages"] << 12)
                cacheMem = "%s" % convSize(value["cachePages"] << 12)
                kernelMem = "%s" % convSize(value["kernelPages"] << 12)
                knownFreeMem = "%s" % convSize(value["nrKnownFreePages"] << 12)
                unknownFreeMem = "%s" % convSize(
                    value["nrUnknownFreePages"] << 12
                )
            else:
                allocMem = "-"
                userMem = "-"
                cacheMem = "-"
                kernelMem = "-"
                knownFreeMem = "-"
                unknownFreeMem = "-"

            if self.breadEnabled:
                readBlock = "%s" % convSize(value["nrRdBlocks"] << 9)
            else:
                readBlock = "-"

            if self.bwriteEnabled:
                writeBlock = "%s" % convSize(value["nrWrBlocks"] << 9)
            else:
                writeBlock = "-"

            if self.lockEnabled:
                nrLock = convNum(value["nrLockTry"])
            else:
                nrLock = "-"

            if self.customTotal > 0:
                nrCustom = convNum(value["customTotal"])
            else:
                nrCustom = "-"

            # update comm #
            if value["comm"] == "<...>" and idx in SysMgr.commCache:
                comm = SysMgr.commCache[idx]
            else:
                comm = value["comm"]

            SysMgr.printPipe(
                (
                    "{0:>16}|{1:>7}|{2:>7}|{3:^6}|{4:^6}|"
                    "{5:>7}|{6:>9}({7:>8}/{8:>8}/{9:>8})|{10:>7}|{11:>8}|"
                    "{12:>8}|{13:>8}|{14:>9}|{15:>6}|{16:>8}|"
                ).format(
                    comm[:16],
                    idx,
                    value["tgid"],
                    targetMark,
                    life,
                    cpuPer,
                    allocMem,
                    userMem,
                    cacheMem,
                    kernelMem,
                    knownFreeMem,
                    unknownFreeMem,
                    cval,
                    readBlock,
                    writeBlock,
                    nrLock,
                    nrCustom,
                )
            )

        if targetCnt == 0:
            SysMgr.printPipe("\tNone")

        SysMgr.printPipe("%s\n\n\n" % oneLine)

        # Exit because of no target #
        if not self.target:
            SysMgr.printWarn(
                "no specific thread targeted, input value for TID"
            )

        # Print syscall usage of threads #
        self.printSyscallSummary()

        # Print resource usage of functions #
        self.printCpuUsage()
        self.printMemUsage()
        self.printHeapUsage()
        self.printBlockRdUsage()
        self.printBlockWrUsage()
        self.printLockUsage()
        self.printSyscallUsage()
        self.printCustomUsage()

    def makeKernelSymList(self, subStack, ilen):
        symbolStack = ""
        stackIdx = 0
        appliedilen = ilen

        if not subStack:
            return " None"

        try:
            for pos in subStack:
                if self.posData[pos]["symbol"] == "":
                    symbolSet = " <- %s" % hex(long(pos, 16))
                elif not self.posData[pos]["symbol"] and SysMgr.showAll:
                    symbolSet = " <- %s" % hex(long(pos, 16))
                else:
                    symbolSet = " <- %s" % str(self.posData[pos]["symbol"])

                lpos = (
                    appliedilen + len(symbolStack[stackIdx:]) + len(symbolSet)
                )
                if symbolStack != "" and lpos > SysMgr.lineLength:
                    stackIdx = len(symbolStack)
                    symbolStack = "%s\n%s" % (symbolStack, " " * ilen)
                    appliedilen = 0

                symbolStack += symbolSet
        except SystemExit:
            sys.exit(0)
        except:
            pass

        return symbolStack

    def makeUserSymList(self, subStack, ilen):
        symbolStack = ""
        stackIdx = 0
        appliedilen = ilen

        if self.sort == "sym":
            for sym in subStack:
                if not sym or sym == "0":
                    symbolSet = ""
                elif self.userSymData[sym]["origBin"] == "??":
                    symbolSet = " <- %s" % sym
                else:
                    symbolSet = " <- %s [%s]" % (
                        sym,
                        self.userSymData[sym]["origBin"],
                    )

                lpos = (
                    appliedilen + len(symbolStack[stackIdx:]) + len(symbolSet)
                )
                if symbolStack != "" and lpos > SysMgr.lineLength:
                    stackIdx = len(symbolStack)
                    symbolStack = "%s\n%s" % (symbolStack, " " * ilen)
                    appliedilen = 0

                symbolStack += symbolSet
        elif self.sort == "pos":
            for pos in subStack:
                if not pos:
                    symbolStack += " <- None"
                # No symbol so that just print pos #
                elif self.posData[pos]["symbol"] == "":
                    symbolStack = "%s <- %s [%s]" % (
                        symbolStack,
                        hex(long(pos, 16)),
                        self.posData[pos]["origBin"],
                    )
                # Print symbol #
                else:
                    symbolStack = "%s <- %s [%s]" % (
                        symbolStack,
                        self.posData[pos]["symbol"],
                        self.posData[pos]["origBin"],
                    )

        if not symbolStack:
            return "\tNone"
        else:
            return symbolStack

    def printSyscallUsage(self):
        # no effective syscall event #
        if self.syscallCnt == 0 or not SysMgr.userEnable:
            return

        subStackIndex = FunctionAnalyzer.symStackIdxTable.index("STACK")
        eventIndex = FunctionAnalyzer.symStackIdxTable.index("SYSCALL")
        convNum = UtilMgr.convNum

        # Print syscall event #
        SysMgr.clearPrint()
        SysMgr.printPipe(
            "[Function Syscall Info] [Cnt: %s] (USER)\n%s"
            % (convNum(self.syscallCnt), twoLine)
        )

        SysMgr.printPipe(
            "{0:_^9}|{1:_^47}|{2:_^49}|{3:_^46}\n{4:1}".format(
                "Usage", "Function", "Binary", "Source", twoLine
            )
        )

        for idx, value in sorted(
            self.userSymData.items(),
            key=lambda e: e[1]["syscallCnt"],
            reverse=True,
        ):

            if value["syscallCnt"] == 0:
                break

            SysMgr.printPipe(
                "{0:>7}  |{1:^47}| {2:48}| {3:37}".format(
                    convNum(value["syscallCnt"]),
                    idx,
                    self.posData[value["pos"]]["origBin"],
                    self.posData[value["pos"]]["src"],
                )
            )

            # Set target stack #
            targetStack = self.getTargetStack(value, eventIndex)

            # Merge and Print symbols in stack #
            for stack in targetStack:
                eventCnt = stack[eventIndex]
                subStack = list(stack[subStackIndex])

                if eventCnt == 0:
                    break

                if not subStack:
                    continue
                else:
                    ilen = len("\t" * 4 * 4) + 3
                    symbolStack = self.makeUserSymList(subStack, ilen)

                SysMgr.printPipe(
                    "\t\t +{0:>7} |{1:32}".format(
                        convNum(eventCnt), symbolStack
                    )
                )

            SysMgr.printPipe(oneLine)

        SysMgr.printPipe()

        # Print syscall file #
        SysMgr.printPipe(
            "[Function Syscall File Info] [Cnt: %s] (USER)\n%s"
            % (twoLine, convNum(self.syscallCnt))
        )

        SysMgr.printPipe(
            "{0:_^9}|{1:_^144}\n{2:1}".format("Usage", "Binary", twoLine)
        )

        for idx, value in sorted(
            self.userFileData.items(),
            key=lambda e: e[1]["syscallCnt"],
            reverse=True,
        ):

            if value["syscallCnt"] == 0:
                break

            SysMgr.printPipe(
                "{0:>8} | {1:<142}\n{2:1}".format(
                    convNum(value["syscallCnt"]), idx, oneLine
                )
            )

        if self.periodicEventCnt == 0:
            SysMgr.printPipe("\tNone\n%s" % oneLine)

        SysMgr.printPipe()

        # Print syscall history #
        if not SysMgr.showAll or not self.sysCallData:
            SysMgr.printPipe("\n\n")
            return

        SysMgr.clearPrint()
        SysMgr.printPipe(
            "[Function Syscall History] [Cnt: %s]\n%s"
            % (convNum(self.syscallCnt), twoLine)
        )

        SysMgr.printPipe(
            "{0:_^32}|{1:_^17}({2:_^7})|{3:_^8}|{4:_^17}|\n{5:1}".format(
                "Event", "COMM", "TID", "CORE", "TIME", twoLine
            )
        )

        # sort by time #
        for call in self.sysCallData:
            event = ConfigMgr.sysList[call[0]][4:]
            args = call[1][0]
            time = call[1][1]
            core = call[1][2]
            tid = call[1][3]

            title = "{0:^32}| {1:>16}({2:>7})| {3:>6} | {4:>15} |".format(
                event, self.threadData[tid]["comm"], tid, core, time
            )
            SysMgr.printPipe("%s\n%s" % (title, len(title) * "-"))

            # Make argument info #
            argsInfo = " %s" % args

            # Make user call info #
            ilen = 32
            nowLen = ilen
            try:
                last = call[2][0]
                stack = call[2][1]
                userCall = " %s[%s]" % (
                    self.posData[last]["symbol"],
                    self.posData[last]["binary"],
                )
                nowLen += len(userCall)
                for subcall in stack:
                    try:
                        symbol = self.posData[subcall]["symbol"]
                        binary = self.posData[subcall]["binary"]
                        nextCall = " <- %s[%s]" % (symbol, binary)
                        if SysMgr.lineLength > nowLen + len(nextCall):
                            userCall += nextCall
                            nowLen += len(nextCall)
                        else:
                            userCall = "%s\n%s %s" % (
                                userCall,
                                " " * ilen,
                                nextCall,
                            )
                            nowLen = ilen + len(nextCall)
                    except:
                        pass
            except SystemExit:
                sys.exit(0)
            except:
                pass

            SysMgr.printPipe(
                "{0:>32}| {1:<121}".format("[Args] ", argsInfo.strip())
            )
            SysMgr.printPipe(
                "{0:>32}|{1:<121}\n{2:1}".format("[User] ", userCall, oneLine)
            )

        SysMgr.printPipe("\n\n")

    def printCustomUsage(self):
        # no effective custom event #
        if self.customTotal == 0:
            return

        subStackIndex = FunctionAnalyzer.symStackIdxTable.index("STACK")
        eventIndex = FunctionAnalyzer.symStackIdxTable.index("CUSTOM")
        convNum = UtilMgr.convNum

        # Make custom event list #
        customList = ", ".join(list(self.customEventTable))

        # Print custom event in user space #
        if SysMgr.userEnable:
            SysMgr.clearPrint()
            SysMgr.printPipe(
                "[Function %s Info] [Cnt: %s] [Total: %s] (USER)\n%s"
                % (
                    customList,
                    convNum(self.customTotal),
                    convNum(self.customCnt),
                    twoLine,
                )
            )

            SysMgr.printPipe(
                "{0:_^9}|{1:_^47}|{2:_^49}|{3:_^46}\n{4:1}".format(
                    "Usage", "Function", "Binary", "Source", twoLine
                )
            )

            for idx, value in sorted(
                self.userSymData.items(),
                key=lambda e: e[1]["customCnt"],
                reverse=True,
            ):

                if value["customCnt"] == 0:
                    break

                SysMgr.printPipe(
                    "{0:>7}  |{1:^47}| {2:48}| {3:37}".format(
                        convNum(value["customCnt"]),
                        idx,
                        self.posData[value["pos"]]["origBin"],
                        self.posData[value["pos"]]["src"],
                    )
                )

                # Set target stack #
                targetStack = self.getTargetStack(value, eventIndex)

                # Merge and Print symbols in stack #
                for stack in targetStack:
                    eventCnt = stack[eventIndex]
                    subStack = list(stack[subStackIndex])

                    if eventCnt == 0:
                        break

                    if not subStack:
                        continue
                    else:
                        ilen = len("\t" * 4 * 4) + 3
                        symbolStack = self.makeUserSymList(subStack, ilen)

                    SysMgr.printPipe(
                        "\t\t +{0:>7} |{1:32}".format(
                            convNum(eventCnt), symbolStack
                        )
                    )

                SysMgr.printPipe(oneLine)

            SysMgr.printPipe()

            # Print custom event file in user space #
            SysMgr.printPipe(
                "[Function %s File Info] [Cnt: %s] [Total: %s] (USER)\n%s"
                % (
                    customList,
                    convNum(self.customTotal),
                    convNum(self.customCnt),
                    twoLine,
                )
            )

            SysMgr.printPipe(
                "{0:_^9}|{1:_^144}\n{2:1}".format("Usage", "Binary", twoLine)
            )

            for idx, value in sorted(
                self.userFileData.items(),
                key=lambda e: e[1]["customCnt"],
                reverse=True,
            ):

                if value["customCnt"] == 0:
                    break

                SysMgr.printPipe(
                    "{0:>8} | {1:<142}\n{2:1}".format(
                        convNum(value["customCnt"]), idx, oneLine
                    )
                )

            if self.periodicEventCnt == 0:
                SysMgr.printPipe("\tNone\n%s" % oneLine)

            SysMgr.printPipe()

        # Print custom event in kernel space #
        SysMgr.clearPrint()
        SysMgr.printPipe(
            "[Function %s Info] [Cnt: %s] [Total: %s] (KERNEL)\n%s"
            % (
                customList,
                convNum(self.customTotal),
                convNum(self.customCnt),
                twoLine,
            )
        )

        SysMgr.printPipe(
            "{0:_^9}|{1:_^144}\n{2:1}".format("Usage", "Function", twoLine)
        )

        # Print custom usage of stacks #
        for idx, value in sorted(
            self.kerSymData.items(),
            key=lambda e: e[1]["customCnt"],
            reverse=True,
        ):

            if value["customCnt"] == 0:
                break

            SysMgr.printPipe(
                "{0:>7}  |{1:^134}".format(convNum(value["customCnt"]), idx)
            )

            # Sort stacks by usage #
            value["stack"] = sorted(
                value["stack"], key=lambda x: x[eventIndex], reverse=True
            )

            # Print stacks by symbol #
            for stack in value["stack"]:
                eventCnt = stack[eventIndex]
                subStack = list(stack[subStackIndex])

                if eventCnt == 0:
                    break

                if not subStack:
                    continue
                elif (
                    len(subStack) == 1
                    and not SysMgr.showAll
                    and (
                        not self.posData[subStack[0]]["symbol"]
                        or self.posData[subStack[0]]["symbol"] == "NoFile"
                    )
                ):
                    # Pass unmeaningful part #
                    continue
                else:
                    ilen = len("\t" * 4 * 4) + 3
                    symbolStack = self.makeKernelSymList(subStack, ilen)

                SysMgr.printPipe(
                    "\t\t +{0:>7} |{1:32}".format(
                        convNum(eventCnt), symbolStack
                    )
                )

            SysMgr.printPipe(oneLine)

            SysMgr.printPipe()

        # Print custom call history #
        if not SysMgr.showAll or not self.customCallData:
            SysMgr.printPipe("\n\n")
            return

        SysMgr.clearPrint()
        SysMgr.printPipe(
            "[Function %s History] [Cnt: %s] [Total: %s]\n%s"
            % (
                customList,
                convNum(self.customTotal),
                convNum(self.customCnt),
                twoLine,
            )
        )

        SysMgr.printPipe(
            "{0:_^32}|{1:_^17}({2:_^7})|{3:_^8}|{4:_^17}|\n{5:1}".format(
                "Event", "COMM", "TID", "CORE", "TIME", twoLine
            )
        )

        # sort by time #
        for call in sorted(self.customCallData, key=lambda e: e[1][1]):
            event = call[0]
            args = call[1][0]
            time = call[1][1]
            core = call[1][2]
            tid = call[1][3]

            title = "{0:^32}| {1:>16}({2:>7})| {3:>6} | {4:>15} |".format(
                event, self.threadData[tid]["comm"], tid, core, time
            )
            SysMgr.printPipe("%s\n%s" % (title, len(title) * "-"))

            # Make argument info #
            argsInfo = " %s" % args

            # Make user call info #
            ilen = 32
            nowLen = ilen
            try:
                last = call[2][0]
                stack = call[2][1]
                userCall = " %s[%s]" % (
                    self.posData[last]["symbol"],
                    self.posData[last]["binary"],
                )
                nowLen += len(userCall)
                for subcall in stack:
                    try:
                        symbol = self.posData[subcall]["symbol"]
                        binary = self.posData[subcall]["binary"]
                        nextCall = " <- %s[%s]" % (symbol, binary)
                        if SysMgr.lineLength > nowLen + len(nextCall):
                            userCall += nextCall
                            nowLen += len(nextCall)
                        else:
                            userCall = "%s\n%s %s" % (
                                userCall,
                                " " * ilen,
                                nextCall,
                            )
                            nowLen = ilen + len(nextCall)
                    except:
                        pass
            except SystemExit:
                sys.exit(0)
            except:
                pass

            # Make kernel call info #
            ilen = 32
            nowLen = ilen
            try:
                last = call[3][0]
                stack = call[3][1]
                kernelCall = " %s" % (self.posData[last]["symbol"])
                nowLen += len(kernelCall)
                for subcall in stack:
                    try:
                        nextCall = " <- %s" % (self.posData[subcall]["symbol"])
                        if SysMgr.lineLength > nowLen + len(nextCall):
                            kernelCall += nextCall
                            nowLen += len(nextCall)
                        else:
                            kernelCall = "%s\n%s %s" % (
                                kernelCall,
                                " " * ilen,
                                nextCall,
                            )
                            nowLen = ilen + len(nextCall)
                    except:
                        pass
            except SystemExit:
                sys.exit(0)
            except:
                pass

            SysMgr.printPipe(
                "{0:>32}| {1:<121}".format("[Args] ", argsInfo.strip())
            )
            SysMgr.printPipe("{0:>32}|{1:<121}".format("[User] ", userCall))
            SysMgr.printPipe(
                "{0:>32}|{1:<121}\n{2:1}".format(
                    "[Kernel] ", kernelCall, oneLine
                )
            )

        SysMgr.printPipe("\n\n")

    def printCpuUsage(self):
        # no CPU event #
        if not self.cpuEnabled or self.periodicEventCnt == 0:
            return

        subStackIndex = FunctionAnalyzer.symStackIdxTable.index("STACK")
        cpuTickIndex = FunctionAnalyzer.symStackIdxTable.index("CPU_TICK")
        tCnt = UtilMgr.convNum(self.periodicEventCnt)

        # average tick interval #
        if self.periodicContEventCnt > 0:
            self.periodicEventInterval /= self.periodicContEventCnt

        # Print CPU usage in user space #
        if SysMgr.userEnable:
            SysMgr.clearPrint()
            title = "Function CPU-Tick Info"
            SysMgr.printPipe(
                "[%s] [Cnt: %s] [Interval: %dms] (USER)"
                % (title, tCnt, self.periodicEventInterval * 1000)
            )

            # Print call stack #
            SysMgr.printPipe(
                "{3:1}\n{0:_^9}|{1:_^47}|{2:_^96}\n{3:1}".format(
                    "Usage", "Function", "Binary", twoLine
                )
            )

            for idx, value in sorted(
                self.userSymData.items(),
                key=lambda e: e[1]["tickCnt"],
                reverse=True,
            ):

                if value["tickCnt"] == 0:
                    break

                cpuPer = value["tickCnt"] / float(self.periodicEventCnt) * 100
                if cpuPer < 1 and not SysMgr.showAll:
                    break

                SysMgr.printPipe(
                    "{0:7.1f}% |{1:^47}| {2:48}".format(
                        cpuPer, idx, self.posData[value["pos"]]["origBin"]
                    )
                )

                # Increase total CPU usage per symbol #
                value["totalTickCnt"] += value["tickCnt"]

                # Set target stack #
                targetStack = self.getTargetStack(value)

                # Merge and Print symbols in stack #
                for stack in targetStack:
                    cpuCnt = stack[cpuTickIndex]
                    subStack = list(stack[subStackIndex])

                    if cpuCnt == 0:
                        break

                    if not subStack:
                        continue
                    else:
                        # Increase total tick count of symbols in stack #
                        for sym in subStack:
                            self.userSymData[sym]["totalTickCnt"] += 1

                        cpuPer = cpuCnt / float(value["tickCnt"]) * 100
                        if cpuPer < 1 and not SysMgr.showAll:
                            break

                        ilen = len("\t" * 4 * 4)
                        symbolStack = self.makeUserSymList(subStack, ilen)

                    SysMgr.printPipe(
                        "\t +{0:7.1f}% |{1:32}".format(cpuPer, symbolStack)
                    )

                SysMgr.printPipe(oneLine)

            if self.periodicEventCnt == 0:
                SysMgr.printPipe("\tNone\n%s" % oneLine)

            SysMgr.printPipe("\n")

            # Print per-symbol #
            title = "Function CPU-Tick Symbol Info"
            SysMgr.printPipe(
                "[%s] [Cnt: %s] [Interval: %dms] (USER)\n%s"
                % (title, tCnt, self.periodicEventInterval * 1000, twoLine)
            )

            SysMgr.printPipe(
                "{0:_^9}|{1:_^47}|{2:_^96}\n{3:1}".format(
                    "Usage", "Function", "Binary", twoLine
                )
            )

            for idx, value in sorted(
                self.userSymData.items(),
                key=lambda e: e[1]["totalTickCnt"],
                reverse=True,
            ):

                if value["totalTickCnt"] == 0:
                    break

                cpuPer = (
                    value["totalTickCnt"] / float(self.periodicEventCnt) * 100
                )
                if cpuPer < 1 and not SysMgr.showAll:
                    break

                SysMgr.printPipe(
                    "{0:7.1f}% |{1:^47}| {2:48}\n{3:1}".format(
                        cpuPer,
                        idx,
                        self.posData[value["pos"]]["origBin"],
                        oneLine,
                    )
                )

            if self.periodicEventCnt == 0:
                SysMgr.printPipe("\tNone\n%s" % oneLine)

            SysMgr.printPipe("\n")

            # Print tick per-file #
            title = "Function CPU-Tick File Info"
            SysMgr.printPipe(
                "[%s] [Cnt: %s] [Interval: %dms] (USER)\n%s"
                % (title, tCnt, self.periodicEventInterval * 1000, twoLine)
            )

            SysMgr.printPipe(
                "{0:_^9}|{1:_^144}\n{2:1}".format("Usage", "Binary", twoLine)
            )

            for idx, value in sorted(
                self.userFileData.items(),
                key=lambda e: e[1]["tickCnt"],
                reverse=True,
            ):

                if value["tickCnt"] == 0:
                    break

                cpuPer = value["tickCnt"] / float(self.periodicEventCnt) * 100
                if cpuPer < 1 and not SysMgr.showAll:
                    break

                SysMgr.printPipe(
                    "{0:7.1f}% | {1:<142}\n{2:1}".format(cpuPer, idx, oneLine)
                )

            if self.periodicEventCnt == 0:
                SysMgr.printPipe("\tNone\n%s" % oneLine)

            SysMgr.printPipe("\n")

        # Print CPU usage in kernel space #
        title = "Function CPU-Tick Info"
        SysMgr.clearPrint()
        titleStr = "[%s] [Cnt: %s] [Interval: %dms] (KERNEL)" % (
            title,
            tCnt,
            self.periodicEventInterval * 1000,
        )
        SysMgr.printPipe(
            "{3:1}\n{2:1}\n{0:_^9}|{1:_^144}\n{2:1}".format(
                "Usage", "Function", twoLine, titleStr
            )
        )

        # Make exception list to remove a redundant part of stack #
        exceptList = {}
        for pos, value in self.posData.items():
            if (
                value["symbol"] == "__irq_usr"
                or value["symbol"] == "__irq_svc"
                or value["symbol"] == "el1_irq"
                or value["symbol"] == "gic_handle_irq"
                or value["symbol"] == "apic_timer_interrupt"
            ):
                exceptList.setdefault(pos, {})

        # Print CPU usage of stacks #
        for idx, value in sorted(
            self.kerSymData.items(),
            key=lambda e: e[1]["tickCnt"],
            reverse=True,
        ):

            if value["tickCnt"] == 0:
                break

            """
            disable to print last symbol because it is only one

            tickCnt = float(value['tickCnt'])
            eventCnt = float(self.periodicEventCnt)
            cpuPer = round(tickCnt / eventCnt * 100, 1)

            if cpuPer < 1 and not SysMgr.showAll:
                break

            SysMgr.printPipe("{0:7}% |{1:^134}".format(cpuPer, idx))
            """

            # Sort stacks by usage #
            value["stack"].sort(reverse=True)

            # Define merge list #
            mergedSymbolChain = {}

            # Merge by symbol chain #
            for stack in value["stack"]:
                cpuCnt = stack[cpuTickIndex]
                subStack = list(stack[subStackIndex])

                if cpuCnt == 0:
                    break
                else:
                    # Find index of the backmost exception value #
                    maxIdx = -1
                    for pos in list(exceptList):
                        try:
                            ridx = subStack.index(pos)
                            if ridx >= 0 and ridx > maxIdx:
                                maxIdx = ridx
                        except:
                            pass

                    # Remove a redundant part #
                    if maxIdx >= 0:
                        maxIdx += 1
                        if maxIdx == len(subStack):
                            subStack = []
                        else:
                            subStack = subStack[maxIdx:]

                if not subStack:
                    symbolStack = " <- USER"
                elif (
                    len(subStack) == 1
                    and not SysMgr.showAll
                    and (
                        not self.posData[subStack[0]]["symbol"]
                        or self.posData[subStack[0]]["symbol"] == "NoFile"
                    )
                ):
                    # Pass unmeaningful part #
                    continue
                else:
                    ilen = 10
                    symbolStack = self.makeKernelSymList(subStack, ilen)

                try:
                    mergedSymbolChain[symbolStack] += cpuCnt
                except:
                    mergedSymbolChain[symbolStack] = cpuCnt

            # define sample list for flame graph #
            if "DRAWFLAME" in SysMgr.environList:
                drawflame = True
                callList = {}
            else:
                drawflame = False

            # Print stacks by symbol #
            for chain, tick in sorted(
                mergedSymbolChain.items(), key=lambda e: e[1], reverse=True
            ):
                cpuPer = tick / float(value["tickCnt"]) * 100
                if cpuPer < 1 and not SysMgr.showAll:
                    break

                # add a sample for flame graph #
                if drawflame:
                    callList[chain.lstrip("<- ")] = tick

                SysMgr.printPipe("{0:7.1f}% |{1:32}".format(cpuPer, chain))

            SysMgr.printPipe(oneLine)

            if self.periodicEventCnt == 0:
                SysMgr.printPipe("\tNone\n%s" % oneLine)

            # draw flame graph #
            if drawflame:
                Debugger.drawFlame(
                    callList=callList,
                    title=titleStr,
                    outFile=SysMgr.outPath + ".cpu.kernel",
                )

        SysMgr.printPipe("\n\n")

    def printUnknownMemFreeInfo(self):
        # check memory event #
        if not self.memEnabled:
            return

        SysMgr.printPipe("\n")

        title = "Function Free-Only-Page Info"
        subStackIndex = FunctionAnalyzer.symStackIdxTable.index("STACK")
        pageFreeIndex = FunctionAnalyzer.symStackIdxTable.index("PAGE_FREE")
        convSize = UtilMgr.convSize2Unit
        size = convSize(self.pageUnknownFreeCnt << 12)

        if SysMgr.userEnable:
            # Print memory reduce by page free in user space #
            SysMgr.clearPrint()
            SysMgr.printPipe(
                "[%s] [Size: %s] (USER)\n%s" % (title, size, twoLine)
            )

            SysMgr.printPipe(
                "{0:_^9}|{1:_^47}|{2:_^49}|{3:_^46}\n{4:1}".format(
                    "Free", "Function", "Binary", "Source", twoLine
                )
            )

            for idx, value in sorted(
                self.userSymData.items(),
                key=lambda e: e[1]["unknownPageFreeCnt"],
                reverse=True,
            ):
                if value["unknownPageFreeCnt"] == 0:
                    break

                SysMgr.printPipe(
                    "{0:>8} |{1:^47}| {2:48}| {3:37}".format(
                        convSize(value["unknownPageFreeCnt"] << 12),
                        idx,
                        self.posData[value["pos"]]["origBin"],
                        self.posData[value["pos"]]["src"],
                    )
                )

                # Set target stack #
                targetStack = self.getTargetStack(value, pageFreeIndex)

                # Merge and Print symbols in stack #
                for stack in targetStack:
                    pageFreeCnt = stack[pageFreeIndex]
                    subStack = list(stack[subStackIndex])

                    if pageFreeCnt == 0:
                        break

                    if not subStack:
                        continue
                    else:
                        ilen = len("\t" * 4 * 4)
                        symbolStack = self.makeUserSymList(subStack, ilen)

                    SysMgr.printPipe(
                        "\t+ {0:>8} |{1:32}".format(
                            convSize(pageFreeCnt << 12), symbolStack
                        )
                    )

                SysMgr.printPipe(oneLine)

            if self.pageUnknownFreeCnt == 0:
                SysMgr.printPipe("\tNone\n%s" % oneLine)

            SysMgr.printPipe("\n")

        # Print memory reduce by page free in kernel space #
        SysMgr.clearPrint()
        SysMgr.printPipe(
            "[%s] [Size: %s] (KERNEL)\n%s" % (title, size, twoLine)
        )

        SysMgr.printPipe(
            "{0:_^9}|{1:_^144}\n{2:1}".format("FREE", "Function", twoLine)
        )

        for idx, value in sorted(
            self.kerSymData.items(),
            key=lambda e: e[1]["unknownPageFreeCnt"],
            reverse=True,
        ):

            if value["unknownPageFreeCnt"] == 0:
                break

            SysMgr.printPipe(
                "{0:>8} |{1:^144}".format(
                    convSize(value["unknownPageFreeCnt"] << 12), idx
                )
            )

            # Sort stacks by usage #
            value["stack"] = sorted(
                value["stack"], key=lambda x: x[pageFreeIndex], reverse=True
            )

            # Print stacks by symbol #
            for stack in value["stack"]:
                pageFreeCnt = stack[pageFreeIndex]
                subStack = list(stack[subStackIndex])

                if pageFreeCnt == 0:
                    continue

                if not subStack:
                    symbolStack = "\tNone"
                else:
                    ilen = len("\t" * 4 * 4)
                    symbolStack = self.makeKernelSymList(subStack, ilen)

                SysMgr.printPipe(
                    "\t+ {0:>8} |{1:32}".format(
                        convSize(pageFreeCnt << 12), symbolStack
                    )
                )

            SysMgr.printPipe(oneLine)

        if self.pageUnknownFreeCnt == 0:
            SysMgr.printPipe("\tNone\n%s" % oneLine)

    def printKnownMemFreeInfo(self):
        title = "Function Alloc-Free-Page Info"
        lineLength = SysMgr.lineLength
        diff = self.pageAllocCnt - self.pageUsageCnt
        convSize = UtilMgr.convSize2Unit
        size = convSize(diff << 12)

        # Print page alloc-free pair in user space #
        if SysMgr.userEnable:
            SysMgr.clearPrint()
            SysMgr.printPipe(
                "[%s] [Total: %s] (USER)\n%s" % (title, size, twoLine)
            )

            SysMgr.printPipe(
                (
                    "{0:^7}({1:^6}/{2:^6}/{3:^6})|"
                    "{4:_^47}|{5:_^40}|{6:_^35}\n{7:1}"
                ).format(
                    "Usage",
                    "Usr",
                    "Buf",
                    "Ker",
                    "Function",
                    "LifeTime",
                    "Binary",
                    twoLine,
                )
            )

            for idx, value in sorted(
                self.userSymData.items(),
                key=lambda e: e[1]["pagePairCnt"],
                reverse=True,
            ):

                if value["pagePairCnt"] == 0:
                    break

                typeList = {"USER": 0, "KERNEL": 0, "CACHE": 0}

                for pairId, item in value["pagePair"].items():
                    for ptype, cnt in item["valueList"].items():
                        try:
                            typeList[ptype] += cnt
                        except:
                            pass

                try:
                    avrTime = float(
                        value["pagePairTotal"] / value["pagePairCnt"]
                    )
                except:
                    avrTime = 0

                lifeTime = " AVR: %.3f / MIN: %.3f / MAX: %.3f" % (
                    avrTime,
                    value["pagePairMin"],
                    value["pagePairMax"],
                )

                SysMgr.printPipe(
                    (
                        "{0:>7}({1:>6}/{2:>6}/{3:>6})|{4:^47}|{5:40}| {6:1}"
                    ).format(
                        convSize(value["pagePairCnt"] << 12),
                        convSize(typeList["USER"] << 12),
                        convSize(typeList["CACHE"] << 12),
                        convSize(typeList["KERNEL"] << 12),
                        idx,
                        lifeTime,
                        self.posData[value["pos"]]["origBin"],
                    )
                )

                for pairId, item in sorted(
                    value["pagePair"].items(),
                    key=lambda e: e[1]["size"],
                    reverse=True,
                ):
                    try:
                        userPages = item["valueList"]["USER"]
                    except:
                        userPages = 0
                    try:
                        cachePages = item["valueList"]["CACHE"]
                    except:
                        cachePages = 0
                    try:
                        kernelPages = item["valueList"]["KERNEL"]
                    except:
                        kernelPages = 0

                    # get user alloc and free call #
                    allocCall, freeCall = pairId.split("#")

                    printBuf = "{0:4}+ {1:>7}({2:>6}/{3:>6}/{4:>6})| ".format(
                        " ",
                        convSize(item["size"] << 12),
                        convSize(userPages << 12),
                        convSize(cachePages << 12),
                        convSize(kernelPages << 12),
                    )

                    ilen = len(printBuf)
                    appliedilen = ilen

                    for seq, call in enumerate(allocCall.split(" <- ")):
                        if seq > 0 and appliedilen + len(call) > lineLength:
                            printBuf = "%s\n%s" % (printBuf, " " * ilen)
                            appliedilen = ilen
                        printBuf = "%s<- %s " % (printBuf, call)
                        appliedilen += len(call) + 4

                    SysMgr.printPipe(printBuf)

                    printBuf = "{0:5}{1:>30}|".format(" ", "[FREE]")
                    ilen = len(printBuf)
                    appliedilen = ilen

                    for index, call in enumerate(freeCall.split(" <- ")):
                        clen = len(call) + 4

                        if index == 0:
                            clen -= 4

                        if index > 0 and appliedilen + clen > lineLength:
                            printBuf = "%s\n%s" % (printBuf, " " * ilen)
                            appliedilen = ilen

                        if index == 0:
                            printBuf = "%s %s" % (printBuf, call)
                        else:
                            printBuf = "%s <- %s" % (printBuf, call)

                        appliedilen += clen

                    SysMgr.printPipe(printBuf)

                SysMgr.printPipe(oneLine)

            if self.pageAllocCnt - self.pageUsageCnt <= 0:
                SysMgr.printPipe("\tNone\n%s" % oneLine)

            SysMgr.printPipe("\n")

        # Print page alloc-free pair in kernel space #
        SysMgr.clearPrint()
        SysMgr.printPipe(
            "[%s] [Total: %s] (KERNEL)\n%s" % (title, size, twoLine)
        )

        SysMgr.printPipe(
            "{0:^7}({1:^6}/{2:^6}/{3:^6})|{4:_^47}|{5:_^76}\n{6:1}".format(
                "Usage", "Usr", "Buf", "Ker", "Function", "LifeTime", twoLine
            )
        )

        # Print mem usage of stacks #
        for idx, value in sorted(
            self.kerSymData.items(),
            key=lambda e: e[1]["pagePairCnt"],
            reverse=True,
        ):

            if value["pagePairCnt"] == 0:
                break

            typeList = {"USER": 0, "KERNEL": 0, "CACHE": 0}

            for pairId, item in value["pagePair"].items():
                for ptype, cnt in item["valueList"].items():
                    try:
                        typeList[ptype] += cnt
                    except:
                        pass

            try:
                avrTime = float(value["pagePairTotal"] / value["pagePairCnt"])
            except:
                avrTime = 0

            lifeTime = " AVR: %.3f / MIN: %.3f / MAX: %.3f" % (
                avrTime,
                value["pagePairMin"],
                value["pagePairMax"],
            )

            SysMgr.printPipe(
                "{0:>7}({1:>6}/{2:>6}/{3:>6})|{4:^47}|{5:^75}".format(
                    convSize(value["pagePairCnt"] << 12),
                    convSize(typeList["USER"] << 12),
                    convSize(typeList["CACHE"] << 12),
                    convSize(typeList["KERNEL"] << 12),
                    idx,
                    lifeTime,
                )
            )

            for pairId, item in sorted(
                value["pagePair"].items(),
                key=lambda e: e[1]["size"],
                reverse=True,
            ):
                try:
                    userPages = item["valueList"]["USER"]
                except:
                    userPages = 0
                try:
                    cachePages = item["valueList"]["CACHE"]
                except:
                    cachePages = 0
                try:
                    kernelPages = item["valueList"]["KERNEL"]
                except:
                    kernelPages = 0

                # get kernel alloc and free call #
                allocCall, freeCall = pairId.split("#")

                printBuf = "{0:4}+ {1:>7}({2:>6}/{3:>6}/{4:>6})| ".format(
                    " ",
                    convSize(item["size"] << 12),
                    convSize(userPages << 12),
                    convSize(cachePages << 12),
                    convSize(kernelPages << 12),
                )

                ilen = len(printBuf)
                appliedilen = ilen

                for seq, call in enumerate(allocCall.split(" <- ")):
                    if seq > 0 and appliedilen + len(call) > lineLength:
                        printBuf = "%s\n%s" % (printBuf, " " * ilen)
                        appliedilen = ilen
                    printBuf = "%s<- %s " % (printBuf, call)
                    appliedilen += len(call) + 4

                SysMgr.printPipe(printBuf)

                printBuf = "{0:5}{1:>30}|".format(" ", "[FREE]")
                ilen = len(printBuf)
                appliedilen = ilen

                for index, call in enumerate(freeCall.split(" <- ")):
                    clen = len(call) + 4

                    if index == 0:
                        clen -= 4

                    if index > 0 and appliedilen + clen > lineLength:
                        printBuf = "%s\n%s" % (printBuf, " " * ilen)
                        appliedilen = ilen

                    if index == 0:
                        printBuf = "%s %s" % (printBuf, call)
                    else:
                        printBuf = "%s <- %s" % (printBuf, call)

                    appliedilen += clen

                SysMgr.printPipe(printBuf)

            SysMgr.printPipe(oneLine)

        if self.pageAllocCnt - self.pageUsageCnt <= 0:
            SysMgr.printPipe("\tNone\n%s" % oneLine)

        SysMgr.printPipe()

    def printMemUsage(self):
        # check memory event #
        if not self.memEnabled:
            return

        title = "Function Alloc-Only-Page Info"
        subStackIndex = FunctionAnalyzer.symStackIdxTable.index("STACK")
        pageAllocIndex = FunctionAnalyzer.symStackIdxTable.index("PAGE_ALLOC")
        argIndex = FunctionAnalyzer.symStackIdxTable.index("ARGUMENT")

        convSize = UtilMgr.convSize2Unit
        userSize = convSize(self.pageUsageCnt << 12)
        allocSize = convSize(self.pageAllocCnt << 12)
        freeSize = convSize(self.pageFreeCnt << 12)
        allocCnt = UtilMgr.convNum(self.pageAllocEventCnt)
        freeCnt = UtilMgr.convNum(self.pageFreeEventCnt)

        # Calculate page lifetime #
        for pfn, item in self.pageTable.items():
            if not item:
                continue

            # calculate time #
            time = float(item["time"])
            if time > 0:
                lifeTime = float(self.finishTime) - time
            else:
                lifeTime = 0

            # Set user page lifetime #
            self.userSymData[item["sym"]]["pageRemainTotal"] += lifeTime
            if (
                self.userSymData[item["sym"]]["pageRemainMin"] == 0
                or self.userSymData[item["sym"]]["pageRemainMin"] > lifeTime
            ):
                self.userSymData[item["sym"]]["pageRemainMin"] = lifeTime
            if self.userSymData[item["sym"]]["pageRemainMax"] < lifeTime:
                self.userSymData[item["sym"]]["pageRemainMax"] = lifeTime

            # Set kernel page lifetime #
            self.kerSymData[item["ksym"]]["pageRemainTotal"] += lifeTime
            if (
                self.kerSymData[item["ksym"]]["pageRemainMin"] == 0
                or self.kerSymData[item["ksym"]]["pageRemainMin"] > lifeTime
            ):
                self.kerSymData[item["ksym"]]["pageRemainMin"] = lifeTime
            if self.kerSymData[item["ksym"]]["pageRemainMax"] < lifeTime:
                self.kerSymData[item["ksym"]]["pageRemainMax"] = lifeTime

        # Print memory usage by page allocation in user space #
        if SysMgr.userEnable:
            SysMgr.clearPrint()
            SysMgr.printPipe(
                "[%s] [Total: %s] [Alloc: %s(%s)] [Free: %s(%s)] (USER)\n%s"
                % (
                    title,
                    userSize,
                    allocSize,
                    allocCnt,
                    freeSize,
                    freeCnt,
                    twoLine,
                )
            )

            SysMgr.printPipe(
                (
                    "{0:^7}({1:^6}/{2:^6}/{3:^6})|"
                    "{4:_^47}|{5:_^40}|{6:_^35}\n{7:1}"
                ).format(
                    "Usage",
                    "Usr",
                    "Buf",
                    "Ker",
                    "Function",
                    "LifeTime",
                    "Binary",
                    twoLine,
                )
            )

            for idx, value in sorted(
                self.userSymData.items(),
                key=lambda e: e[1]["pageCnt"],
                reverse=True,
            ):

                if value["pageCnt"] == 0:
                    break

                try:
                    avrTime = float(
                        value["pageRemainTotal"] / value["pageCnt"]
                    )
                except:
                    avrTime = 0

                lifeTime = " AVR: %.3f / MIN: %.3f / MAX: %.3f" % (
                    avrTime,
                    value["pageRemainMin"],
                    value["pageRemainMax"],
                )

                SysMgr.printPipe(
                    (
                        "{0:>7}({1:>6}/{2:>6}/{3:>6})|{4:^47}|{5:40}| {6:1}"
                    ).format(
                        convSize(value["pageCnt"] << 12),
                        convSize(value["userPageCnt"] << 12),
                        convSize(value["cachePageCnt"] << 12),
                        convSize(value["kernelPageCnt"] << 12),
                        idx,
                        lifeTime,
                        self.posData[value["pos"]]["origBin"],
                    )
                )

                # Set target stack #
                targetStack = self.getTargetStack(value, pageAllocIndex)

                # Merge and Print symbols in stack #
                for stack in targetStack:
                    subStack = list(stack[subStackIndex])
                    pageCnt = stack[pageAllocIndex]
                    userPageCnt = stack[argIndex][0]
                    cachePageCnt = stack[argIndex][1]
                    kernelPageCnt = stack[argIndex][2]

                    if pageCnt == 0:
                        break

                    if not subStack:
                        continue
                    else:
                        ilen = len("\t" * 4 * 9)
                        symbolStack = self.makeUserSymList(subStack, ilen)

                    SysMgr.printPipe(
                        "\t+ {0:>7}({1:>6}/{2:>6}/{3:>6})|{4:32}".format(
                            convSize(pageCnt << 12),
                            convSize(userPageCnt << 12),
                            convSize(cachePageCnt << 12),
                            convSize(kernelPageCnt << 12),
                            symbolStack,
                        )
                    )

                SysMgr.printPipe(oneLine)

            if self.pageUsageCnt == 0:
                SysMgr.printPipe("\tNone\n%s" % oneLine)

            SysMgr.printPipe("\n")

        # Print memory usage by page allocation in kernel space #
        SysMgr.clearPrint()
        SysMgr.printPipe(
            "[%s] [Total: %s] [Alloc: %s(%s)] [Free: %s(%s)] (KERNEL)\n%s"
            % (
                title,
                userSize,
                allocSize,
                allocCnt,
                freeSize,
                freeCnt,
                twoLine,
            )
        )

        SysMgr.printPipe(
            "{0:^7}({1:^6}/{2:^6}/{3:^6})|{4:_^47}|{5:_^76}\n{6:1}".format(
                "Usage", "Usr", "Buf", "Ker", "Function", "LifeTime", twoLine
            )
        )

        # Print mem usage of stacks #
        for idx, value in sorted(
            self.kerSymData.items(),
            key=lambda e: e[1]["pageCnt"],
            reverse=True,
        ):

            if value["pageCnt"] == 0:
                break

            try:
                avrTime = float(value["pageRemainTotal"] / value["pageCnt"])
            except:
                avrTime = 0

            lifeTime = " AVR: %.3f / MIN: %.3f / MAX: %.3f" % (
                avrTime,
                value["pageRemainMin"],
                value["pageRemainMax"],
            )

            SysMgr.printPipe(
                "{0:>7}({1:>6}/{2:>6}/{3:>6})|{4:^47}|{5:^76}".format(
                    convSize(value["pageCnt"] << 12),
                    convSize(value["userPageCnt"] << 12),
                    convSize(value["cachePageCnt"] << 12),
                    convSize(value["kernelPageCnt"] << 12),
                    idx,
                    lifeTime,
                )
            )

            # Sort stacks by usage #
            value["stack"] = sorted(
                value["stack"], key=lambda x: x[pageAllocIndex], reverse=True
            )

            # Print stacks by symbol #
            for stack in value["stack"]:
                subStack = list(stack[subStackIndex])
                pageCnt = stack[pageAllocIndex]
                userPageCnt = stack[argIndex][0]
                cachePageCnt = stack[argIndex][1]
                kernelPageCnt = stack[argIndex][2]

                if pageCnt == 0:
                    continue

                if not subStack:
                    continue
                else:
                    ilen = len("\t" * 4 * 9)
                    symbolStack = self.makeKernelSymList(subStack, ilen)

                SysMgr.printPipe(
                    "\t+ {0:>7}({1:>6}/{2:>6}/{3:>6})|{4:32}".format(
                        convSize(pageCnt << 12),
                        convSize(userPageCnt << 12),
                        convSize(cachePageCnt << 12),
                        convSize(kernelPageCnt << 12),
                        symbolStack,
                    )
                )

            SysMgr.printPipe(oneLine)

        if self.pageUsageCnt == 0:
            SysMgr.printPipe("\tNone\n%s" % oneLine)

        SysMgr.printPipe("\n")

        self.printKnownMemFreeInfo()

        self.printUnknownMemFreeInfo()

        SysMgr.printPipe("\n\n")

    def printHeapUsage(self):
        # check heap memory event #
        if not self.heapEnabled or not SysMgr.userEnable:
            return

        title = "Function Expand-Heap"
        subStackIndex = FunctionAnalyzer.symStackIdxTable.index("STACK")
        heapExpIndex = FunctionAnalyzer.symStackIdxTable.index("HEAP_EXPAND")
        convSize = UtilMgr.convSize2Unit

        # Print heap usage in user space #
        SysMgr.clearPrint()
        SysMgr.printPipe(
            "[%s Info] [Total: %s] [Alloc: %s(%s)] [Free: %s(%s)] (USER)%s\n"
            % (
                title,
                convSize(self.heapExpSize - self.heapRedSize),
                convSize(self.heapExpSize),
                UtilMgr.convNum(self.heapExpEventCnt),
                convSize(self.heapRedSize),
                UtilMgr.convNum(self.heapRedEventCnt),
                twoLine,
            )
        )

        SysMgr.printPipe(
            "{0:_^9}|{1:_^47}|{2:_^49}|{3:_^46}\n{4:1}".format(
                "Usage", "Function", "Binary", "Source", twoLine
            )
        )

        for idx, value in sorted(
            self.userSymData.items(),
            key=lambda e: e[1]["heapSize"],
            reverse=True,
        ):

            if value["heapSize"] == 0:
                break

            binary = self.posData[value["pos"]]["origBin"]
            source = self.posData[value["pos"]]["src"]
            SysMgr.printPipe(
                "{0:>8} |{1:^47}| {2:48}| {3:37}".format(
                    convSize(value["heapSize"]), idx, binary, source
                )
            )

            if idx == value["pos"]:
                SysMgr.printPipe(oneLine)
                continue

            # Set target stack #
            targetStack = self.getTargetStack(value, heapExpIndex)

            # Merge and Print symbols in stack #
            for stack in targetStack:
                heapSize = stack[heapExpIndex]
                subStack = list(stack[subStackIndex])

                if heapSize == 0:
                    break

                if not subStack:
                    continue
                else:
                    ilen = len("\t" * 4 * 4)
                    symbolStack = self.makeUserSymList(subStack, ilen)

                SysMgr.printPipe(
                    "\t+ {0:>8} |{1:32}".format(
                        convSize(heapSize), symbolStack
                    )
                )

            SysMgr.printPipe(oneLine)

        if not self.heapTable:
            SysMgr.printPipe("\tNone\n%s" % oneLine)

        SysMgr.printPipe("\n")

        # Print remaining heap history #
        if not SysMgr.showAll or not self.heapTable:
            SysMgr.printPipe("\n\n")
            return

        SysMgr.clearPrint()
        SysMgr.printPipe(
            "[%s History] [Cnt: %s]\n%s"
            % (title, UtilMgr.convNum(len(self.heapTable)), twoLine)
        )

        SysMgr.printPipe(
            (
                "{0:_^32}|{1:_^12}|{2:_^17}({3:_^7})|"
                "{4:_^8}|{5:_^17}|\n{6:1}"
            ).format("VAddr", "Size", "COMM", "TID", "CORE", "TIME", twoLine)
        )

        # sort by time #
        for segment in sorted(
            self.heapTable.items(), key=lambda e: e[1]["time"]
        ):
            addr = segment[0]

            size = segment[1]["size"]
            time = segment[1]["time"]
            core = segment[1]["core"]
            tid = segment[1]["tid"]

            usersym = segment[1]["sym"]
            kernelsym = segment[1]["ksym"]
            userstack = segment[1]["subStackAddr"]
            kernelstack = segment[1]["ksubStackAddr"]

            title = (
                "{0:^32}| {1:>10} | {2:>16}({3:>7})|{4:>6} | {5:>15} |"
            ).format(
                addr,
                convSize(size),
                self.threadData[tid]["comm"],
                tid,
                long(core),
                time,
            )
            SysMgr.printPipe("%s\n%s" % (title, len(title) * "-"))

            # Make user call info #
            ilen = 32
            nowLen = ilen
            try:
                userCall = " %s[%s]" % (
                    usersym,
                    self.userSymData[usersym]["origBin"],
                )
                nowLen += len(userCall)

                # Set user stack list #
                if self.sort == "sym":
                    targetStack = self.userSymData[usersym]["symStack"]
                elif self.sort == "pos":
                    targetStack = self.userSymData[usersym]["stack"]

                # Find user stack by addr #
                stack = []
                for val in targetStack:
                    if id(val[subStackIndex]) == userstack:
                        stack = val[subStackIndex]
                        break

                for subcall in stack:
                    try:
                        nextCall = " <- %s[%s]" % (
                            subcall,
                            self.userSymData[subcall]["origBin"],
                        )
                        if SysMgr.lineLength > nowLen + len(nextCall):
                            userCall += nextCall
                            nowLen += len(nextCall)
                        else:
                            userCall = "%s\n%s %s" % (
                                userCall,
                                " " * ilen,
                                nextCall,
                            )
                            nowLen = ilen + len(nextCall)
                    except:
                        pass
            except:
                pass

            # Make kernel call info #
            ilen = 32
            nowLen = ilen
            try:
                kernelCall = " %s" % (kernelsym)
                nowLen += len(kernelCall)

                # Set kernel stack list #
                if self.sort == "sym":
                    targetStack = self.kerSymData[kernelsym]["symStack"]
                elif self.sort == "pos":
                    targetStack = self.kerSymData[kernelsym]["stack"]

                # Find kernel stack by addr #
                stack = []
                for val in targetStack:
                    if id(val[subStackIndex]) == kernelstack:
                        stack = val[subStackIndex]
                        break

                for subcall in stack:
                    try:
                        nextCall = " <- %s" % (subcall)
                        if SysMgr.lineLength > nowLen + len(nextCall):
                            kernelCall += nextCall
                            nowLen += len(nextCall)
                        else:
                            kernelCall = "%s\n%s %s" % (
                                kernelCall,
                                " " * ilen,
                                nextCall,
                            )
                            nowLen = ilen + len(nextCall)
                    except:
                        pass
            except:
                pass

            if userCall != " 0":
                SysMgr.printPipe(
                    "{0:>32}|{1:<121}".format("[User] ", userCall)
                )
            if kernelCall != " 0":
                SysMgr.printPipe(
                    "{0:>32}|{1:<121}".format("[Kernel] ", kernelCall)
                )
            SysMgr.printPipe(oneLine)

        SysMgr.printPipe("\n\n")

    def printLockUsage(self):
        # no lock event #
        if not self.lockEnabled or not SysMgr.userEnable:
            return

        subStackIndex = FunctionAnalyzer.symStackIdxTable.index("STACK")
        lockIndex = FunctionAnalyzer.symStackIdxTable.index("LOCK_TRY")
        unlockIndex = FunctionAnalyzer.symStackIdxTable.index("UNLOCK")

        # Print lock try #
        title = "Function Lock-Try Info"
        SysMgr.clearPrint()
        SysMgr.printPipe(
            "[%s] [Cnt: %d] (USER)\n%s"
            % (title, self.lockTryEventCnt, twoLine)
        )

        SysMgr.printPipe(
            "{0:_^9}|{1:_^47}|{2:_^49}|{3:_^46}\n{4:1}".format(
                "Usage", "Function", "Binary", "Source", twoLine
            )
        )

        for idx, value in sorted(
            self.userSymData.items(),
            key=lambda e: e[1]["lockTryCnt"],
            reverse=True,
        ):

            if value["lockTryCnt"] == 0:
                break

            binary = self.posData[value["pos"]]["origBin"]
            source = self.posData[value["pos"]]["src"]
            SysMgr.printPipe(
                "{0:8} |{1:^47}| {2:48}| {3:37}".format(
                    value["lockTryCnt"], idx, binary, source
                )
            )

            # Set target stack #
            targetStack = self.getTargetStack(value, lockIndex)

            # Merge and Print symbols in stack #
            for stack in targetStack:
                lockTryCnt = stack[lockIndex]
                subStack = list(stack[subStackIndex])

                if lockTryCnt == 0:
                    break

                if not subStack:
                    continue
                else:
                    ilen = len("\t" * 4 * 4)
                    symbolStack = self.makeUserSymList(subStack, ilen)

                SysMgr.printPipe(
                    "\t+ {0:8} |{1:32}".format(lockTryCnt, symbolStack)
                )

            SysMgr.printPipe(oneLine)

        if self.lockTryEventCnt == 0:
            SysMgr.printPipe("\tNone\n%s" % oneLine)

        SysMgr.printPipe("\n")

        # Print lock per-file #
        title = "Function Lock-Try File Info"
        SysMgr.printPipe(
            "[%s] [Cnt: %d] (USER)\n%s"
            % (title, self.lockTryEventCnt, twoLine)
        )

        SysMgr.printPipe(
            "{0:_^9}|{1:_^144}\n{2:1}".format("Usage", "Binary", twoLine)
        )

        for idx, value in sorted(
            self.userFileData.items(),
            key=lambda e: e[1]["lockTryCnt"],
            reverse=True,
        ):

            if value["lockTryCnt"] == 0:
                break

            SysMgr.printPipe(
                "{0:8} | {1:<142}\n{2:1}".format(
                    value["lockTryCnt"], idx, oneLine
                )
            )

        if self.periodicEventCnt == 0:
            SysMgr.printPipe("\tNone\n%s" % oneLine)

        SysMgr.printPipe("\n")

        # Print unlock #
        title = "Function Unlock Info"
        SysMgr.clearPrint()
        SysMgr.printPipe(
            "[%s] [Cnt: %d] (USER)\n%s" % (title, self.unlockEventCnt, twoLine)
        )

        SysMgr.printPipe(
            "{0:_^9}|{1:_^47}|{2:_^49}|{3:_^46}\n{4:1}".format(
                "Usage", "Function", "Binary", "Source", twoLine
            )
        )

        for idx, value in sorted(
            self.userSymData.items(),
            key=lambda e: e[1]["unlockCnt"],
            reverse=True,
        ):

            if value["unlockCnt"] == 0:
                break

            binary = self.posData[value["pos"]]["origBin"]
            source = self.posData[value["pos"]]["src"]
            SysMgr.printPipe(
                "{0:8} |{1:^47}| {2:48}| {3:37}".format(
                    value["unlockCnt"], idx, binary, source
                )
            )

            # Set target stack #
            targetStack = self.getTargetStack(value, unlockIndex)

            # Merge and Print symbols in stack #
            for stack in targetStack:
                unlockCnt = stack[unlockIndex]
                subStack = list(stack[subStackIndex])

                if unlockCnt == 0:
                    break

                if not subStack:
                    continue
                else:
                    ilen = len("\t" * 4 * 4)
                    symbolStack = self.makeUserSymList(subStack, ilen)

                SysMgr.printPipe(
                    "\t+ {0:8} |{1:32}".format(unlockCnt, symbolStack)
                )

            SysMgr.printPipe(oneLine)

        if self.unlockEventCnt == 0:
            SysMgr.printPipe("\tNone\n%s" % oneLine)

        SysMgr.printPipe("\n")

        # Print unlock per-file #
        title = "Function Unlock File Info"
        SysMgr.printPipe(
            "[%s] [Cnt: %d] (USER)\n%s"
            % (title, self.lockTryEventCnt, twoLine)
        )

        SysMgr.printPipe(
            "{0:_^9}|{1:_^144}\n{2:1}".format("Usage", "Binary", twoLine)
        )

        for idx, value in sorted(
            self.userFileData.items(),
            key=lambda e: e[1]["unlockCnt"],
            reverse=True,
        ):

            if value["unlockCnt"] == 0:
                break

            SysMgr.printPipe(
                "{0:8} | {1:<142}".format(value["unlockCnt"], idx)
            )

            SysMgr.printPipe(oneLine)

        if self.periodicEventCnt == 0:
            SysMgr.printPipe("\tNone\n%s" % oneLine)

        SysMgr.printPipe("\n")

        # Print lock history #
        if not SysMgr.showAll or not self.lockCallData:
            SysMgr.printPipe("\n\n")
            return

        title = "Function Lock History"
        SysMgr.clearPrint()
        SysMgr.printPipe(
            "[%s] [Lock: %d] [Unlock: %d]\n%s"
            % (title, self.lockTryEventCnt, self.unlockEventCnt, twoLine)
        )

        SysMgr.printPipe(
            (
                "{0:_^32}|{1:_^16}|{2:_^17}({3:_^7})|"
                "{4:_^8}|{5:_^17}|\n{6:1}"
            ).format("Event", "Target", "COMM", "TID", "Core", "Time", twoLine)
        )

        # sort by time #
        for call in self.lockCallData:
            event = call[0]
            target = call[1][0]
            time = call[1][1]
            core = call[1][2]
            tid = call[1][3]
            userstack = call[2]

            comm = self.threadData[tid]["comm"]
            title = (
                "{0:^32}|{1:^16}|{2:>16}({3:>7})| {4:>6} | {5:>15} |".format(
                    event, target, comm, tid, core, time
                )
            )
            SysMgr.printPipe("%s\n%s" % (title, len(title) * "-"))

            # Make user call info #
            ilen = 32
            nowLen = ilen
            try:
                last = userstack[0]
                stack = userstack[1]
                symbol = self.posData[last]["symbol"]
                binary = self.posData[last]["binary"]
                userCall = " %s[%s]" % (symbol, binary)
                nowLen += len(userCall)
                for subcall in stack:
                    try:
                        symbol = self.posData[subcall]["symbol"]
                        binary = self.posData[subcall]["binary"]
                        nextCall = " <- %s[%s]" % (symbol, binary)
                        if SysMgr.lineLength > nowLen + len(nextCall):
                            userCall += nextCall
                            nowLen += len(nextCall)
                        else:
                            userCall = "%s\n%s %s" % (
                                userCall,
                                " " * ilen,
                                nextCall,
                            )
                            nowLen = ilen + len(nextCall)
                    except:
                        pass
            except SystemExit:
                sys.exit(0)
            except:
                pass

            SysMgr.printPipe(
                "{0:>32}|{1:<121}\n{2:1}".format("[User] ", userCall, oneLine)
            )

        SysMgr.printPipe("\n\n")

    def printBlockWrUsage(self):
        # no block write event #
        if not self.bwriteEnabled:
            return

        title = "Function Write-Block Info"
        subStackIndex = FunctionAnalyzer.symStackIdxTable.index("STACK")
        blkWrIndex = FunctionAnalyzer.symStackIdxTable.index("BLK_WRITE")
        convSize = UtilMgr.convSize2Unit
        convNum = UtilMgr.convNum
        size = convSize(self.blockWrUsageCnt << 9)

        # Print block write in user space #
        if SysMgr.userEnable:
            SysMgr.clearPrint()
            SysMgr.printPipe(
                "[%s] [Size: %s] [Cnt: %s] (USER)\n%s"
                % (title, size, convNum(self.blockWrEventCnt), twoLine)
            )

            SysMgr.printPipe(
                "{0:_^9}|{1:_^47}|{2:_^49}|{3:_^46}\n{4:1}".format(
                    "Usage", "Function", "Binary", "Source", twoLine
                )
            )

            for idx, value in sorted(
                self.userSymData.items(),
                key=lambda e: e[1]["blockWrCnt"],
                reverse=True,
            ):

                if value["blockWrCnt"] == 0:
                    break

                binary = self.posData[value["pos"]]["origBin"]
                source = self.posData[value["pos"]]["src"]
                SysMgr.printPipe(
                    "{0:>8} |{1:^47}| {2:48}| {3:37}".format(
                        convSize(value["blockWrCnt"] << 9), idx, binary, source
                    )
                )

                # Set target stack #
                targetStack = self.getTargetStack(value, blkWrIndex)

                # Merge and Print symbols in stack #
                for stack in targetStack:
                    blockWrCnt = stack[blkWrIndex]
                    subStack = list(stack[subStackIndex])

                    if blockWrCnt == 0:
                        break

                    if not subStack:
                        continue
                    else:
                        ilen = len("\t" * 4 * 4)
                        symbolStack = self.makeUserSymList(subStack, ilen)

                    SysMgr.printPipe(
                        "\t+ {0:>8} |{1:32}".format(
                            convSize(blockWrCnt << 9), symbolStack
                        )
                    )

                SysMgr.printPipe(oneLine)

            if self.blockWrUsageCnt == 0:
                SysMgr.printPipe("\tNone\n%s" % oneLine)

            SysMgr.printPipe("\n")

        # Print block write in kernel space #
        SysMgr.clearPrint()
        SysMgr.printPipe(
            "[%s] [Size: %s] [Cnt: %s] (KERNEL)\n%s"
            % (title, size, convNum(self.blockWrEventCnt), twoLine)
        )

        SysMgr.printPipe(
            "{0:_^9}|{1:_^144}\n{2:1}".format("Usage", "Function", twoLine)
        )

        # Print block write usage of stacks #
        for idx, value in sorted(
            self.kerSymData.items(),
            key=lambda e: e[1]["blockWrCnt"],
            reverse=True,
        ):

            if value["blockWrCnt"] == 0:
                break

            SysMgr.printPipe(
                "{0:>8} |{1:^134}".format(
                    convSize(value["blockWrCnt"] << 9), idx
                )
            )

            # Sort stacks by usage #
            value["stack"] = sorted(
                value["stack"], key=lambda x: x[blkWrIndex], reverse=True
            )

            # Print stacks by symbol #
            for stack in value["stack"]:
                blockWrCnt = stack[blkWrIndex]
                subStack = list(stack[subStackIndex])

                if blockWrCnt == 0:
                    continue

                if not subStack:
                    symbolStack = "\tNone"
                else:
                    ilen = len("\t" * 4 * 4)
                    symbolStack = self.makeKernelSymList(subStack, ilen)

                SysMgr.printPipe(
                    "\t+ {0:>8} |{1:32}".format(
                        convSize(blockWrCnt << 9), symbolStack
                    )
                )

            SysMgr.printPipe(oneLine)

        if self.blockWrUsageCnt == 0:
            SysMgr.printPipe("\tNone\n%s" % oneLine)

        SysMgr.printPipe("\n\n")

    def getExceptionList(self):
        exceptList = {}

        # do not use this method now #
        return exceptList

        for pos, value in self.posData.items():
            if value["symbol"] == "None":
                try:
                    exceptList[pos]
                except:
                    exceptList[pos] = {}

        return exceptList

    def getTargetStack(self, value, index=None):
        targetStack = []
        if self.sort == "sym":
            targetStack = value["symStack"]
        elif self.sort == "pos":
            targetStack = value["stack"]

        # Sort by usage #
        if index:
            targetStack = sorted(
                targetStack, key=lambda x: x[index], reverse=True
            )
        else:
            targetStack.sort(reverse=True)

        return targetStack

    def printBlockRdUsage(self):
        # no block read event #
        if not self.breadEnabled:
            return

        title = "Function Read-Block Info"
        subStackIndex = FunctionAnalyzer.symStackIdxTable.index("STACK")
        blkRdIndex = FunctionAnalyzer.symStackIdxTable.index("BLK_READ")
        convSize = UtilMgr.convSize2Unit
        convNum = UtilMgr.convNum
        size = convSize(self.blockRdUsageCnt << 9)

        # Print block read in user space #
        if SysMgr.userEnable:
            SysMgr.clearPrint()
            SysMgr.printPipe(
                "[%s] [Size: %s] [Cnt: %s] (USER)\n%s"
                % (title, size, convNum(self.blockRdEventCnt), twoLine)
            )

            SysMgr.printPipe(
                "{0:_^9}|{1:_^47}|{2:_^49}|{3:_^46}\n{4:1}".format(
                    "Usage", "Function", "Binary", "Source", twoLine
                )
            )

            for idx, value in sorted(
                self.userSymData.items(),
                key=lambda e: e[1]["blockRdCnt"],
                reverse=True,
            ):

                if value["blockRdCnt"] == 0:
                    break

                binary = self.posData[value["pos"]]["origBin"]
                source = self.posData[value["pos"]]["src"]
                SysMgr.printPipe(
                    "{0:>8} |{1:^47}| {2:48}| {3:37}".format(
                        convSize(value["blockRdCnt"] << 9), idx, binary, source
                    )
                )

                # Set target stack #
                targetStack = self.getTargetStack(value, blkRdIndex)

                # Merge and Print symbols in stack #
                for stack in targetStack:
                    blockRdCnt = stack[blkRdIndex]
                    subStack = list(stack[subStackIndex])

                    if blockRdCnt == 0:
                        break

                    if not subStack:
                        continue
                    else:
                        ilen = len("\t" * 4 * 4)
                        symbolStack = self.makeUserSymList(subStack, ilen)

                    SysMgr.printPipe(
                        "\t+ {0:8} |{1:32}".format(
                            convSize(blockRdCnt << 9), symbolStack
                        )
                    )

                SysMgr.printPipe(oneLine)

            SysMgr.printPipe("\n")

        # Print block read in kernel space #
        SysMgr.clearPrint()
        SysMgr.printPipe(
            "[%s] [Size: %s] [Cnt: %s] (KERNEL)\n%s"
            % (title, size, convNum(self.blockRdEventCnt), twoLine)
        )

        SysMgr.printPipe(
            "{0:_^9}|{1:_^144}\n{2:1}".format("Usage", "Function", twoLine)
        )

        # Print block read usage of stacks #
        for idx, value in sorted(
            self.kerSymData.items(),
            key=lambda e: e[1]["blockRdCnt"],
            reverse=True,
        ):

            if value["blockRdCnt"] == 0:
                break

            SysMgr.printPipe(
                "{0:>8} |{1:^144}".format(
                    convSize(value["blockRdCnt"] << 9), idx
                )
            )

            # Sort stacks by usage #
            value["stack"] = sorted(
                value["stack"], key=lambda x: x[blkRdIndex], reverse=True
            )

            # Print stacks by symbol #
            for stack in value["stack"]:
                blockRdCnt = stack[blkRdIndex]
                subStack = list(stack[subStackIndex])

                if blockRdCnt == 0:
                    continue

                if not subStack:
                    symbolStack = "\tNone"
                else:
                    ilen = len("\t" * 4 * 4)
                    symbolStack = self.makeKernelSymList(subStack, ilen)

                SysMgr.printPipe(
                    "\t+ {0:>8} |{1:32}".format(
                        convSize(blockRdCnt << 9), symbolStack
                    )
                )

            SysMgr.printPipe(oneLine)

        SysMgr.printPipe("\n\n")


class LeakAnalyzer(object):
    """Analyzer for leaktracing"""

    startSig = 35  # SIGRT1
    stopSig = 36  # SIGRT2
    markedIdlePages = False
    idlePageList = []
    filterCode = None
    filterValue = 0

    def __init__(self, file=None, pid=None):

        self.pid = pid
        self.posData = {}
        self.symData = {}
        self.fileData = {}
        self.callData = []
        self.totalLeakSize = 0

        self.init_posData = {
            "offset": 0,
            "path": None,
            "lastPosCnt": 0,
            "callList": None,
            "count": 0,
            "size": 0,
            "lastPosSize": 0,
            "sym": "??",
        }

        self.init_symData = {
            "offset": 0,
            "path": None,
            "lastPosCnt": 0,
            "substack": None,
            "count": 0,
            "size": 0,
            "lastPosSize": 0,
        }

        self.init_fileData = {
            "lastPosCnt": 0,
            "count": 0,
            "size": 0,
            "lastPosSize": 0,
        }

        # Get file size #
        fsize = UtilMgr.getFileSizeStr(file)

        # Open log file #
        try:
            SysMgr.printInfo("start loading '%s'%s" % (file, fsize))

            fd = open(file, "r")
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenErr(file)
            sys.exit(-1)

        SysMgr.printInfo("start processing data...")

        self.callData = self.parseLines(fd)

        # Get process object #
        try:
            proc = Debugger(pid=int(pid), attach=False)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to analyze leakage for the task with PID %s" % pid,
                True,
            )
            sys.exit(-1)

        SysMgr.printInfo("start resolving symbols...")

        # Resolve symbols #
        self.resolveSymbols(proc)

        SysMgr.printInfo("start merging symbols...")

        # Merge symbols #
        self.mergeSymbols()

    def printLeakage(self, runtime, profileTime, startTime):
        # define shortcut #
        convSize = UtilMgr.convSize2Unit

        try:
            mlist = SysMgr.getMemStat(self.pid)
            mstat = SysMgr.convMemStat(mlist)
            vss = convSize(mstat["vss"])
            rss = convSize(mstat["rss"])
        except SystemExit:
            sys.exit(0)
        except:
            vss = rss = "?"

        # task info #
        proc = "%s(%s)" % (SysMgr.getComm(self.pid), self.pid)

        # set name #
        name = "Leakage"
        if LeakAnalyzer.markedIdlePages:
            if "REPORTIDLE" in SysMgr.environList:
                name = "Idle"
            elif "REPORTACTIVE" in SysMgr.environList:
                name = "Active"

        # set title #
        title = "Function %s Info" % name
        titleStr = (
            "\n\n[%s] [Process: %s] [Start: %s] [Run: %s] [Profile: %s] "
            "[VSS: %s] [RSS: %s] [%s: %s] [NrCall: %s]"
        ) % (
            title,
            proc,
            startTime,
            runtime,
            profileTime,
            vss,
            rss,
            name,
            convSize(self.totalLeakSize),
            convSize(len(self.callData)),
        )
        SysMgr.printPipe(titleStr)

        SysMgr.printPipe(
            "{4:1}\n{0:>7} | {1:>7} | {2:>7} | {3:<122} |".format(
                "Size", "Count", "Avg", "Function", twoLine
            )
        )
        SysMgr.printPipe(
            "{0:>7} | {1:>7} | {2:<132} |\n{3:1}".format(
                " ", "Size", " Backtrace", twoLine
            )
        )

        # init flamegraph variable #
        stackList = {}

        count = 0
        for sym, val in sorted(
            self.symData.items(),
            key=lambda e: long(e[1]["lastPosSize"]),
            reverse=True,
        ):
            if val["lastPosSize"] == 0:
                break

            size = val["lastPosSize"]
            count = val["lastPosCnt"]
            avg = long(size / count)

            SysMgr.printPipe(
                "{0:>7} | {1:>7} | {2:>7} | {3:<122} ".format(
                    convSize(size),
                    convSize(count),
                    convSize(avg),
                    "%s[%s]" % (sym, val["path"]),
                )
            )

            for substack, size in sorted(
                val["substack"].items(), key=lambda e: e[1], reverse=True
            ):
                SysMgr.printPipe(
                    "{0:>7} | {1:>7} | {2:<132} ".format(
                        "", convSize(size), substack
                    )
                )

                # register fullstack to the list for flamegraph #
                fullStack = " ".join(
                    [item.strip() for item in (sym + substack).split("\n")]
                )
                stackList[fullStack] = size

            count += 1

            SysMgr.printPipe(oneLine)

        if count == 0:
            SysMgr.printPipe("\tNone\n%s" % oneLine)

        # set title #
        title = "File %s Info" % name
        SysMgr.printPipe(
            (
                "\n\n[%s] [Process: %s] [Start: %s] [Run: %s] [Profile: %s] "
                "[VSS: %s] [RSS: %s] [%s: %s] [NrCall: %s]\n%s"
            )
            % (
                title,
                proc,
                startTime,
                runtime,
                profileTime,
                vss,
                rss,
                name,
                convSize(self.totalLeakSize),
                convSize(len(self.callData)),
                twoLine,
            )
        )

        SysMgr.printPipe(
            "{0:>7} | {1:>7} | {2:>7} | {3:<122} |\n{4:1}".format(
                "Size", "Count", "Avg", "Path", twoLine
            )
        )

        count = 0
        for fpath, val in sorted(
            self.fileData.items(),
            key=lambda e: long(e[1]["lastPosSize"]),
            reverse=True,
        ):
            if val["lastPosSize"] == 0:
                break
            elif val["lastPosCnt"] == 0:
                continue

            size = val["lastPosSize"]
            count = val["lastPosCnt"]
            avg = long(size / count)

            SysMgr.printPipe(
                "{0:>7} | {1:>7} | {2:>7} | {3:<122} |".format(
                    convSize(size), convSize(count), convSize(avg), fpath
                )
            )

            count += 1

        if count == 0:
            SysMgr.printPipe("\tNone")

        SysMgr.printPipe(oneLine)

        # check exit condition #
        if not self.callData:
            SysMgr.printWarn("no sample data", True)
            return

        # draw flamegraph #
        if SysMgr.inputFile:
            inputFile = SysMgr.inputFile
        else:
            inputFile = "guider.out"
        inputFile = os.path.realpath(inputFile)
        SysMgr.printStat(r"start drawing flamegraph...")
        Debugger.drawFlame(inputFile, stackList, titleStr, suffix=True)

        # check exit condition #
        if not SysMgr.showAll:
            return

        # leakage history #
        title = "Leakage History"
        SysMgr.printPipe(
            "\n[%s] [Start: %s] [Total: %s] [Count: %s]\n%s"
            % (
                title,
                startTime,
                convSize(self.totalLeakSize, True),
                convSize(len(self.callData), True),
                twoLine,
            )
        )

        SysMgr.printPipe(
            "{0:^16} | {1:^16} | {2:^6} |{3:^50}| {4:^53}\n{5:1}".format(
                "Time", "Addr", "Size", "Data", "Stack", oneLine
            )
        )

        for time, items in sorted(
            self.callData.items(), key=lambda e: e[0], reverse=False
        ):

            stack = " <- ".join(
                [
                    "%s(%s)[%s]" % (item[1], item[0], item[2])
                    for item in list(items["symstack"])
                ]
            )

            SysMgr.printPipe(
                "{0:>16} | {1:>16} | {2:>6} |{3:<50}| {4:<53}\n{5:1}".format(
                    time,
                    items["addr"] if "addr" in items else " ",
                    convSize(long(items["size"])),
                    items["data"][:-1],
                    stack,
                    oneLine,
                )
            )

    def mergeSymbols(self):
        cnt = 0
        total = len(self.posData)
        dobj = Debugger()
        for pos, val in self.posData.items():
            UtilMgr.printProgress(cnt, total)
            cnt += 1

            # merge by symbol #
            sym = val["sym"]

            try:
                symData = self.symData[sym]
                symData["count"] += val["count"]
                symData["size"] += val["size"]
                symData["lastPosSize"] += val["lastPosSize"]
                if val["lastPosSize"] > 0:
                    symData["lastPosCnt"] += val["count"]
            except SystemExit:
                sys.exit(0)
            except:
                self.symData[sym] = dict(self.init_symData)
                symData = self.symData[sym]
                symData["offset"] = val["offset"]
                symData["path"] = val["path"]
                symData["count"] = val["count"]
                symData["size"] = val["size"]
                symData["lastPosSize"] = val["lastPosSize"]
                if val["lastPosSize"] > 0:
                    symData["lastPosCnt"] += val["count"]
                symData["substack"] = {}

            # merge by backtrace #
            path = val["path"]
            if val["callList"]:
                for time in list(val["callList"]):
                    callinfo = self.callData[time]
                    substack = dobj.getBtStr(callinfo["symstack"][1:])
                    dobj.btStr = None
                    size = long(callinfo["size"])

                    try:
                        symData["substack"][substack] += size
                    except:
                        symData["substack"][substack] = size

            # merge by file #
            try:
                fileData = self.fileData[path]
                fileData["count"] += val["count"]
                fileData["size"] += val["size"]
                fileData["lastPosSize"] += val["lastPosSize"]
                if val["lastPosSize"] > 0:
                    fileData["lastPosCnt"] += val["count"]
            except SystemExit:
                sys.exit(0)
            except:
                self.fileData[path] = dict(self.init_fileData)
                fileData = self.fileData[path]
                fileData["count"] = val["count"]
                fileData["size"] = val["size"]
                fileData["lastPosSize"] = val["lastPosSize"]
                if val["lastPosSize"] > 0:
                    fileData["lastPosCnt"] = val["count"]

            self.totalLeakSize += val["lastPosSize"]

        if cnt:
            UtilMgr.deleteProgress()

    def resolveSymbols(self, proc):
        cnt = 0
        total = len(self.posData) + len(self.callData)

        # resolve all symbols #
        for pos, val in self.posData.items():
            UtilMgr.printProgress(cnt, total)
            cnt += 1

            try:
                ret = proc.getSymbolInfo(long(pos, 16))
            except:
                SysMgr.printWarn(
                    "failed to get symbol for %s" % pos, reason=True
                )
                continue

            if ret and len(ret) > 3:
                val["sym"] = ret[0]
                val["path"] = ret[1]
                val["offset"] = ret[2]

        # resolve symbols in stacks #
        for pos, val in self.callData.items():
            UtilMgr.printProgress(cnt, total)
            cnt += 1

            if not "stack" in val:
                continue

            symstack = list(val["stack"])

            for idx, offset in enumerate(val["stack"]):
                data = self.posData[offset]
                symstack[idx] = [data["offset"], data["sym"], data["path"]]

            val["symstack"] = symstack

            try:
                posid = val["stack"][0]
                self.posData[posid]["callList"][pos] = None
            except:
                self.posData[posid]["callList"] = {}
                self.posData[posid]["callList"][pos] = None

        if cnt:
            UtilMgr.deleteProgress()

    def parseLines(self, fd):
        callinfo = {}
        total = os.fstat(fd.fileno()).st_size
        pageSize = SysMgr.PAGESIZE

        # check REPORTIDLE variable to report only idle page info #
        if LeakAnalyzer.markedIdlePages:
            if "REPORTIDLE" in SysMgr.environList:
                bitVal = 0
            elif "REPORTACTIVE" in SysMgr.environList:
                bitVal = 1
            else:
                LeakAnalyzer.markedIdlePages = False

        # define size filter function #
        def _sizeChecker(val):
            return True

        if LeakAnalyzer.filterCode:
            if LeakAnalyzer.filterCode == "<":

                def _sizeChecker(val):
                    if val < LeakAnalyzer.filterValue:
                        return True
                    else:
                        return False

            elif LeakAnalyzer.filterCode == ">":

                def _sizeChecker(val):
                    if val > LeakAnalyzer.filterValue:
                        return True
                    else:
                        return False

            elif LeakAnalyzer.filterCode == "=":

                def _sizeChecker(val):
                    if val == LeakAnalyzer.filterValue:
                        return True
                    else:
                        return False

        while 1:
            try:
                line = fd.readline()
            except SystemExit:
                sys.exit(0)
            except:
                continue

            # check EOF #
            if not line:
                break

            # print progress #
            cur = fd.tell()
            if cur > total:
                total = os.fstat(fd.fileno()).st_size
            UtilMgr.printProgress(cur, total)

            # check prefix #
            if not line.startswith("leak,"):
                continue

            items = line.split(", ")
            time = None
            item = {}

            for content in items[1:]:
                try:
                    name, body = content.split("=", 1)
                except SystemExit:
                    sys.exit(0)
                except:
                    continue

                if name == "time":
                    time = body
                elif name == "stack":
                    # split callstack #
                    try:
                        item[name] = body.split()
                        item[name] = item[name][1:]
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass
                elif not SysMgr.showAll and name == "data":
                    continue
                else:
                    item[name] = body

            # check size value #
            if not item or not "size" in item or not item["size"].isdigit():
                continue

            # get allocation size #
            size = long(item["size"])
            if not _sizeChecker(size):
                continue

            # filter parts on idle pages #
            if LeakAnalyzer.markedIdlePages and "addr" in item:
                # get start address for a chunk #
                addr = long(item["addr"], 16)
                addrStart = long(addr / pageSize) * pageSize
                addrDiff = addr - addrStart

                # get end address for a chunk #
                sizeAligned = long((size + addrDiff + pageSize - 1) / pageSize)
                addrEnd = addrStart + sizeAligned

                # ignore active part for a chunk #
                try:
                    for mem in LeakAnalyzer.idlePageList[self.pid]:
                        mapStart, mapEnd, bitmap = mem

                        # check scope #
                        if addrStart >= mapEnd or addrEnd <= mapStart:
                            continue

                        # get start address for check #
                        start = addrStart - mapStart
                        if start < 0:
                            sizeAligned += start / pageSize
                            start = 0
                        idx = long((start) / pageSize)

                        # subtract the size of used pages #
                        for offset in range(sizeAligned):
                            targetIdx = idx + offset
                            if len(bitmap) <= targetIdx:
                                break
                            elif bitmap[targetIdx] != bitVal:
                                size -= pageSize
                        # TODO: consider spanning chunks between two pages #
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printWarn(
                        "failed to check an idle chunk", True, True
                    )

                # skip all used chunks #
                if size < 1:
                    continue

                # update stack size #
                item["size"] = size

            # save pos in common area #
            for pos in item["stack"]:
                try:
                    self.posData[pos]["count"] += 1
                    self.posData[pos]["size"] += size
                except SystemExit:
                    sys.exit(0)
                except:
                    self.posData[pos] = dict(self.init_posData)
                    self.posData[pos]["count"] = 1
                    self.posData[pos]["size"] = size
                    self.posData[pos]["callList"] = {}

            try:
                lastPos = item["stack"][0]
            except:
                continue

            self.posData[lastPos]["lastPosSize"] += size

            callinfo[time] = item

        UtilMgr.deleteProgress()

        return callinfo


class FileAnalyzer(object):
    """Analyzer for file profiling"""

    procMapCache = {}
    procMapStrCache = {}

    init_mapData = {
        "offset": 0,
        "size": 0,
        "pageCnt": 0,
        "fd": None,
        "totalSize": 0,
        "fileMap": None,
        "pids": None,
        "linkCnt": 0,
        "inode": None,
        "accessTime": None,
        "devid": None,
        "isRep": True,
        "perm": None,
        "nrOpen": 0,
        "repFile": None,
        "hardLink": long(1),
        "linkList": None,
        "vstart": 0,
        "vend": 0,
        "elfInfo": None,
        "nrMap": 0,
    }

    def __init__(self):
        self.profSuccessCnt = 0
        self.profFailedCnt = 0
        self.profPageCnt = 0
        self.pgRclmBg = 0
        self.pgRclmFg = 0
        self.procData = {}
        self.fileData = {}
        self.inodeData = {}
        self.target = [""]
        self.readaheadStr = ""

        self.procList = {}
        self.fileList = {}

        self.intervalProcData = []
        self.intervalFileData = []

        self.init_procData = {
            "tids": None,
            "pageCnt": 0,
            "procMap": None,
            "comm": "",
        }
        self.init_threadData = {"comm": ""}
        self.init_inodeData = {}

        # set system maximum fd number #
        SysMgr.setMaxFd()

        # set specific file #
        targetFiles = []

        # convert target path to abspath #
        for item in SysMgr.customCmd:
            if "*" in item:
                continue
            path = os.path.realpath(item)
            targetFiles.append(path)

        # convert target path to realpath #
        if SysMgr.customCmd:
            SysMgr.printInfo(
                "start checking specific files related to [ %s ]"
                % ", ".join(SysMgr.customCmd)
            )

            # get specific file list #
            convList = UtilMgr.getFileList(SysMgr.customCmd)
            for fname in convList:
                try:
                    if os.path.isdir(fname):
                        for subfname in UtilMgr.getFiles(
                            fname, recursive=SysMgr.recursionEnable
                        ):
                            SysMgr.getFd(subfname)
                            targetFiles.append(os.path.realpath(subfname))
                    elif os.path.isfile(fname):
                        SysMgr.getFd(fname)
                        targetFiles.append(os.path.realpath(fname))
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr("failed to open '%s'" % fname, reason=True)
                    sys.exit(-1)
        targetFiles = set(targetFiles)

        # handle no target case #
        if SysMgr.filterGroup:
            self.target = SysMgr.filterGroup

        if not SysMgr.guiderObj:
            # load libc #
            SysMgr.loadLibcObj(exit=True)

            # define mmap types #
            SysMgr.libcObj.mmap.argtypes = [
                POINTER(None),
                c_size_t,
                c_int,
                c_int,
                c_int,
                c_long,
            ]
            SysMgr.libcObj.mmap.restype = POINTER(None)

            # define munmap types #
            SysMgr.libcObj.munmap.argtypes = [POINTER(None), c_size_t]
            SysMgr.libcObj.munmap.restype = c_int

            # define mincore types #
            SysMgr.libcObj.mincore.argtypes = [
                POINTER(None),
                c_size_t,
                POINTER(c_ubyte),
            ]
            SysMgr.libcObj.mincore.restype = c_int

        while 1:
            # print plan #
            if targetFiles:
                SysMgr.printStat(
                    "start collecting a total of %s files..."
                    % UtilMgr.convNum(len(targetFiles))
                )
            else:
                SysMgr.printStat("start collecting all files on memory...")

            targetFiles = targetFiles if targetFiles else [""]

            # scan proc directory and save map information of processes #
            self.scanProcs(filterList=targetFiles)

            # merge maps of processes into a integrated file map #
            SysMgr.printStat("start merging file info...")
            self.mergeFileMapInfo(filterList=targetFiles)

            # get file map info on memory #
            self.getFilePageMaps()

            # fill file map of each processes #
            self.fillFileMaps()

            if SysMgr.intervalEnable:
                # save previous file usage and initialize all variables #
                self.intervalProcData.append(self.procData)
                self.intervalFileData.append(self.fileData)
                self.procData = {}
                self.fileData = {}
                self.inodeData = {}
                self.profSuccessCnt = 0
                self.profFailedCnt = 0

                # check exit condition for interval profile #
                if not SysMgr.condExit:
                    SysMgr.waitEvent()
                else:
                    break
            else:
                break

        # save system reclaim info
        try:
            # get vmstat #
            vmData = SysMgr.getVmstat(retDict=True)

            for name in list(ConfigMgr.BGRECLAIMSTAT):
                if name in vmData:
                    self.pgRclmBg += vmData[name]

            for name in list(ConfigMgr.FGRECLAIMSTAT):
                if name in vmData:
                    self.pgRclmFg += vmData[name]
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to get system reclaim stat", True)

    def __del__(self):
        pass

    def printIntervalInfo(self):
        # merge process info into a global list #
        for data in self.intervalProcData:
            for pid, info in data.items():
                try:
                    if self.procList[pid]["pageCnt"] < info["pageCnt"]:
                        self.procList[pid]["pageCnt"] = info["pageCnt"]
                except:
                    self.procList[pid] = dict(self.init_procData)
                    self.procList[pid]["tids"] = {}
                    self.procList[pid]["pageCnt"] = info["pageCnt"]
                    self.procList[pid]["comm"] = info["comm"]

                for tid, val in info["tids"].items():
                    try:
                        self.procList[pid]["tids"][tid]
                    except:
                        self.procList[pid]["tids"][tid] = dict(
                            self.init_threadData
                        )
                        self.procList[pid]["tids"][tid]["comm"] = val["comm"]

        if not self.procList:
            SysMgr.printErr("no process profiled")
            sys.exit(-1)

        # merge file info into a global list #
        for data in self.intervalFileData:
            for name, stat in data.items():
                try:
                    fl = self.fileList[name]
                    if fl["pageCnt"] < stat["pageCnt"]:
                        fl["pageCnt"] = stat["pageCnt"]
                except:
                    self.fileList[name] = dict(FileAnalyzer.init_mapData)
                    self.fileList[name]["pageCnt"] = stat["pageCnt"]
                    self.fileList[name]["totalSize"] = stat["totalSize"]

        # check result #
        if not self.fileList:
            SysMgr.printErr("no file profiled")
            sys.exit(-1)

        self.procData = self.procList

        SysMgr.printLogo(big=True)

        # print system information #
        SysMgr.printInfoBuffer()

        # define alias #
        pageSize = SysMgr.PAGESIZE
        convSize = UtilMgr.convSize2Unit
        convColor = UtilMgr.convColor
        convNum = UtilMgr.convNum
        uptime = UtilMgr.convTime(SysMgr.updateUptime())

        # print process list #
        self.printProcUsage()

        # print file list #
        SysMgr.printPipe(
            (
                "[%s] [File: %s] [LastRAM: %s] [Reclaim: %s/%s] "
                "[Uptime: %s] [Keys: Foward/Back/Save/Quit]\n%s"
            )
            % (
                "File Usage Info",
                convNum(len(self.fileList)),
                convSize(self.profPageCnt * 4 << 10),
                convSize(self.pgRclmBg * 4 << 10),
                convSize(self.pgRclmFg * 4 << 10),
                uptime,
                twoLine,
            )
        )

        printMsg = "{0:_^8}|{1:_^8}|{2:_^3}|".format("InitRAM", "File", "%")

        if len(self.intervalFileData) > 1:
            for idx in xrange(1, len(self.intervalFileData)):
                printMsg += "{0:_^15}|".format(str(idx))

        # print title #
        lineLength = SysMgr.lineLength
        printMsg += "{0:_^8}|{1:_^3}|".format("LastRAM", "%")
        printMsg += "_" * (long((lineLength - len(printMsg)) / 2) - 2)
        printMsg += "Library"
        printMsg += "_" * (lineLength - len(printMsg))
        printMsg += "\n%s" % twoLine
        SysMgr.printPipe(printMsg)

        # print interval usage #
        for fileName, val in sorted(
            self.fileList.items(),
            key=lambda e: long(e[1]["pageCnt"]),
            reverse=True,
        ):
            # memory size #
            try:
                memSize = (
                    self.intervalFileData[0][fileName]["pageCnt"] * pageSize
                )
            except:
                memSize = 0

            try:
                idx = val["totalSize"] + pageSize - 1
                fileSize = long(idx / pageSize) * pageSize
            except:
                fileSize = 0

            # set percentage #
            if fileSize != 0:
                per = long(long(memSize) / float(fileSize) * 100)
                per = UtilMgr.convCpuColor(per, size=3)
            else:
                per = 0

            if memSize > 0:
                memSize = convColor(convSize(memSize), "YELLOW", 7)

            # check whether this file was profiled or not #
            isRep = False
            for fileData in reversed(self.intervalFileData):
                if fileName in fileData and fileData[fileName]["isRep"]:
                    printMsg = "{0:>7} |{1:>7} |{2:>3}|".format(
                        memSize, convSize(fileSize), per
                    )
                    isRep = True
                    break

            if not isRep:
                continue

            # calculate diff of on-memory file size #
            if len(self.intervalFileData) > 1:
                for idx in xrange(len(self.intervalFileData) - 1):
                    diffNew = 0
                    diffDel = 0

                    try:
                        nowFileMap = self.intervalFileData[idx][fileName][
                            "fileMap"
                        ]
                    except:
                        nowFileMap = None

                    try:
                        prevFileMap = self.intervalFileData[idx - 1][fileName][
                            "fileMap"
                        ]
                    except:
                        prevFileMap = None

                    fileData = self.intervalFileData

                    if not nowFileMap:
                        if prevFileMap:
                            diffDel = fileData[idx - 1][fileName]["pageCnt"]
                    else:
                        if not prevFileMap:
                            diffNew = fileData[idx][fileName]["pageCnt"]
                        else:
                            if len(nowFileMap) == len(prevFileMap):
                                for i in xrange(len(nowFileMap)):
                                    if nowFileMap[i] > prevFileMap[i]:
                                        diffNew += 1
                                    elif nowFileMap[i] < prevFileMap[i]:
                                        diffDel += 1

                    if diffNew > 0:
                        diffNew = convColor(
                            convSize(diffNew * pageSize), "RED", 6
                        )
                    else:
                        diffNew = " "

                    if diffDel > 0:
                        diffDel = convColor(
                            convSize(diffDel * pageSize), "RED", 6
                        )
                    else:
                        diffDel = " "

                    printMsg += "+%6s/-%6s|" % (diffNew, diffDel)

            finalData = self.intervalFileData[-1][fileName]

            totalMemSize = finalData["pageCnt"] * pageSize

            if fileSize != 0:
                per = long(long(totalMemSize) / float(fileSize) * 100)
                per = UtilMgr.convCpuColor(per, size=3)
            else:
                per = 0

            if totalMemSize > 0:
                totalMemSize = convColor(convSize(totalMemSize), "YELLOW", 7)

            printMsg += "{0:>7} |{1:>3}| {2:1}".format(
                totalMemSize, per, fileName
            )

            SysMgr.printPipe(printMsg)

        SysMgr.printPipe("%s\n\n\n" % oneLine)

    @staticmethod
    def isValidFile(fileName, special=False):
        # skip non-files #
        if not fileName.startswith("/"):
            return False
        # skip device nodes #
        elif fileName.startswith("/dev/"):
            return False
        # skip proc nodes #
        elif fileName.startswith("/proc/"):
            return False
        # skip sys nodes #
        elif fileName.startswith("/sys/"):
            return False
        # skip non-contiguous segments #
        elif SysMgr.magicStr in fileName:
            return False
        # skip deleted files #
        elif " (deleted)" in fileName:
            return False

        # check special #
        if special:
            if fileName == "vdso":
                return True

        return True

    @staticmethod
    def getMapAddr(pid, fname, fd=None, retList=False):
        if not fname:
            SysMgr.printWarn("no file name to be searched for address")
            return None
        elif not fd:
            fd = FileAnalyzer.getMapFd(pid)
            if not fd:
                return None

        addrList = []
        allAnon = allFile = allPages = noPerm = something = False

        # check anon #
        if fname == "anon":
            allAnon = True
        # check file #
        elif fname == "file":
            allFile = True
        # check all #
        elif fname == "all":
            allPages = True
        # check noperm #
        elif fname == "noperm":
            noPerm = True
        else:
            something = True

        # read maps #
        fd.seek(0, 0)
        for item in fd.readlines():
            mdict = FileAnalyzer.parseMapLine(
                item, needName=allFile or something
            )
            if not mdict:
                continue

            # all #
            if allPages:
                pass
            # no perm #
            elif noPerm:
                if not mdict["perm"].startswith("--"):
                    continue
            # anons #
            elif allAnon:
                if mdict["inode"] != "0":
                    continue
            # files #
            else:
                if not "binName" in mdict or not mdict["binName"]:
                    continue
                # all files #
                elif (
                    allFile
                    and mdict["binName"].startswith("/")
                    and mdict["inode"] != "0"
                ):
                    pass
                # a specific file #
                elif not mdict["binName"].endswith(
                    fname
                ) and not UtilMgr.isValidStr(mdict["binName"], [fname]):
                    continue

            start = str(mdict["startAddr"])
            end = str(mdict["endAddr"])

            if retList:
                addrList.append([start, end])
            else:
                return start, end

        if retList:
            return addrList
        else:
            return None

    @staticmethod
    def getMapFilePath(pid, fname, fd=None):
        if not fname:
            SysMgr.printWarn("no file name to be searched for path")
            return None
        elif not fd:
            fd = FileAnalyzer.getMapFd(pid)
            if not fd:
                return None

        # read maps #
        fd.seek(0, 0)
        for item in fd.readlines():
            mdict = FileAnalyzer.parseMapLine(item)
            if mdict and mdict["binName"]:
                if os.path.basename(mdict["binName"]).startswith(fname):
                    return str(mdict["binName"])
        return None

    @staticmethod
    def getEmptyMapAddr(pid, fd=None, size=0, onlyExec=False):
        if not fd:
            fd = FileAnalyzer.getMapFd(pid)
            if not fd:
                return None

        # search empty space #
        for item in fd.readlines():
            mdict = FileAnalyzer.parseMapLine(item)
            if not mdict:
                mapLine = item.split()
                addrs = list(map(lambda x: long(x, 16), mapLine[0].split("-")))
                perm = mapLine[1]
                if onlyExec and not "x" in perm:
                    continue

                return addrs[0]

    @staticmethod
    def getProcMapFd(pid, verb=False):
        fd = FileAnalyzer.getMapFd(pid, verb)
        if fd:
            return fd
        else:
            # get comm #
            comm = SysMgr.getComm(pid)

            # check alive #
            if not SysMgr.isAlive(pid):
                reason = " because it is terminated"
            # check root #
            elif not SysMgr.isRoot():
                reason = " because of no root permission"
            else:
                reason = ""

            SysMgr.printErr(
                "failed to get memory map for %s(%s)%s" % (comm, pid, reason)
            )
            sys.exit(-1)

    @staticmethod
    def getMapFd(pid, verb=False):
        # open maps #
        try:
            path = "%s/%s/maps" % (SysMgr.procPath, pid)
            return open(path, "r")
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenWarn(path, verb)
            return None

    @staticmethod
    def getAnonMapInfo(pid, fd=None, onlyExec=True):
        # set file descriptor #
        if fd:
            fd.seek(0, 0)
        else:
            fd = FileAnalyzer.getProcMapFd(pid)

        # read maps #
        mapBuf = fd.readlines()

        # define map dictionary #
        anonMap = []

        # parse lines #
        for string in mapBuf:
            m = re.match(
                (
                    r"^(?P<startAddr>.\S+)-(?P<endAddr>.\S+) (?P<perm>.\S+) "
                    r"(?P<offset>.\S+) (?P<devid>.\S+) 0"
                ),
                string,
            )
            if not m:
                continue

            d = m.groupdict()

            # get execution permission #
            if onlyExec and "perm" in d and d["perm"][-2] == "-":
                continue

            # get size info #
            startAddr = long(d["startAddr"], 16)
            endAddr = long(d["endAddr"], 16)
            size = endAddr - startAddr

            anonMap.append([startAddr, endAddr])

        return anonMap

    @staticmethod
    def getProcMapInfo(pid, fd=None, onlyExec=False, saveAll=False):
        # set file descriptor #
        if fd:
            fd.seek(0, 0)
        else:
            fd = FileAnalyzer.getProcMapFd(pid)

        # read maps #
        mapBuf = fd.readlines()

        # check map cache #
        try:
            if FileAnalyzer.procMapStrCache[pid] == mapBuf:
                return FileAnalyzer.procMapCache[pid]
        except SystemExit:
            sys.exit(0)
        except:
            pass
        finally:
            FileAnalyzer.procMapStrCache[pid] = mapBuf

        # define map dictionary #
        fileMap = {}

        # parse and merge lines in maps #
        for val in mapBuf:
            FileAnalyzer.mergeMapLine(val, fileMap, saveAll=saveAll)

        # remove non-executable files #
        if onlyExec:
            for fname in list(fileMap):
                if fname != "stack" and not fileMap[fname]["exec"]:
                    fileMap.pop(fname, None)

        # save map cache #
        FileAnalyzer.procMapCache[pid] = fileMap

        return fileMap

    @staticmethod
    def addMapLine(dataObj, fileName, newOffset, newSize):
        newEnd = newOffset + newSize

        try:
            savedOffset = dataObj[fileName]["offset"]
            savedSize = dataObj[fileName]["size"]
            savedEnd = savedOffset + savedSize

            # start address bigger than saved one #
            if savedOffset <= newOffset:
                # merge bigger end address than saved one #
                if savedEnd < newEnd:
                    dataObj[fileName]["size"] += (
                        newEnd - savedOffset - savedSize
                    )
                # ignore lesser end address than saved one #
                else:
                    pass
            # start address lesser than saved one #
            else:
                if savedEnd >= newEnd:
                    dataObj[fileName]["size"] += savedOffset - newOffset
                else:
                    dataObj[fileName]["size"] = newSize

                dataObj[fileName]["offset"] = newOffset
        except SystemExit:
            sys.exit(0)
        except:
            dataObj[fileName] = dict(FileAnalyzer.init_mapData)
            dataObj[fileName]["offset"] = newOffset
            dataObj[fileName]["size"] = newSize
            dataObj[fileName]["nrMap"] = 1

    @staticmethod
    def parseMapLine(string, needName=True):
        if needName:
            matchStr = (
                r"^(?P<startAddr>.\S+)-(?P<endAddr>.\S+) (?P<perm>.\S+) "
                r"(?P<offset>.\S+) (?P<devid>.\S+) (?P<inode>0|.\S+)"
                r".\s*(?P<binName>.+)"
            )
        else:
            matchStr = (
                r"^(?P<startAddr>.\S+)-(?P<endAddr>.\S+) (?P<perm>.\S+) "
                r"(?P<offset>.\S+) (?P<devid>.\S+) (?P<inode>0|.\S+)"
            )

        m = re.match(matchStr, string)
        if not m:
            return None

        return m.groupdict()

    @staticmethod
    def getReadaheadListStr(raList, raSummary):
        if not raList:
            SysMgr.printWarn("no readahead item", True)
            return ""

        # define variables #
        convNum = UtilMgr.convNum
        printStr = ""

        # print readahead stat #
        printStr += (
            "\n[Thread Readahead Info] (NrFiles: %s) (NrCalls: %s)\n%s\n"
            % (convNum(len(raSummary)), convNum(len(raList)), twoLine)
        )
        printStr += "{0:>12} {1:>12} {2:>1}\n{3:1}\n".format(
            "Size", "Count", "Path", twoLine
        )

        for fname, stat in sorted(
            raSummary.items(), key=lambda e: e[1]["size"], reverse=True
        ):
            printStr += "{0:>12} {1:>12} {2:>1}\n".format(
                UtilMgr.convSize2Unit(stat["size"]),
                convNum(stat["count"]),
                fname,
            )

        if not raSummary:
            printStr += "\tNone\n"

        printStr += "%s\n" % oneLine

        return printStr

    @staticmethod
    def makeReadaheadFile(
        raPath, readaheadList, pathConvList, raMin, raAddList
    ):

        # check readahead file path #
        if not raPath:
            return readaheadList, {}

        # apply add list #
        for item in raAddList:
            # parse file info #
            finfo = item.split(":")
            try:
                item = finfo[0]
                offset = size = 0

                if len(finfo) == 1:
                    pass
                elif len(finfo) == 2:
                    if finfo[1]:
                        size = UtilMgr.convUnit2Size(finfo[1])
                else:
                    offset = UtilMgr.convUnit2Size(finfo[1])
                    if finfo[2]:
                        size = UtilMgr.convUnit2Size(finfo[2])
            except SystemExit:
                sys.exit(0)
            except:
                fname = SysMgr.environList["RAADDLIST"][0]
                SysMgr.printErr(
                    "failed to apply readahead add list from '%s'" % fname,
                    reason=True,
                )
                sys.exit(-1)

            # get full path #
            fpath = os.path.realpath(item)
            if not os.path.exists(fpath):
                SysMgr.printWarn(
                    (
                        "skipped adding '%s' to readahead list "
                        "because not exists"
                    )
                    % fpath,
                    True,
                )
                continue

            # get file size #
            fsize = UtilMgr.getFileSize(fpath, False)
            fsizeStr = UtilMgr.convSize2Unit(fsize)
            finfo = "%s[%s]" % (fpath, fsizeStr)

            # set full size #
            if size == 0:
                size = fsize

            # get path index #
            if finfo in pathConvList:
                idx = pathConvList[finfo][1]
            else:
                idx = len(pathConvList)
                pathConvList.setdefault(finfo, [fpath, idx])

            # add readahead list #
            readaheadList.append([idx, offset, size])

        # backup exist readahead list #
        SysMgr.backupFile(raPath)

        # create a new file for readahead list #
        try:
            raFd = open(raPath, "wb")
            os.chmod(raPath, 0o777)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenErr(raPath)
            sys.exit(-1)

        # merge readahead chunks #
        if "RAMERGE" in SysMgr.environList:
            SysMgr.printInfo("merge continuous readahead chunks")

            prevChunk = None
            origRaList = readaheadList
            readaheadList = []
            for chunk in origRaList:
                fid, offset, size = chunk
                if not prevChunk:
                    prevChunk = [fid, offset, size]
                    readaheadList.append(prevChunk)
                    continue

                # merge chunks #
                if (
                    fid == prevChunk[0]
                    and offset == prevChunk[1] + prevChunk[2]
                ):
                    prevChunk[2] += size
                    readaheadList[-1] = prevChunk
                    continue

                # add original chunk to list #
                prevChunk = [fid, offset, size]
                readaheadList.append(prevChunk)

        # write readahead list to file #
        try:
            raSummary = {}

            # encode file list #
            fileList = [
                value[0]
                for path, value in sorted(
                    pathConvList.items(), key=lambda e: e[1][1]
                )
            ]
            fileStr = "#".join(fileList)
            fileStr = fileStr.encode()

            # write file list size #
            raFd.write(struct.pack("I", len(fileStr)))

            # write file list #
            raFd.write(fileStr)

            # write readahead chunks #
            for chunk in readaheadList:
                # skip chunks lesser than minimum size #
                if raMin > chunk[2]:
                    continue

                fid, offset, size = chunk

                # write chunks #
                raFd.write(struct.pack("HQI", fid, offset, size))

                # save readahead stat #
                fname = fileList[fid]
                raSummary.setdefault(fname, dict({"count": 0, "size": 0}))
                raSummary[fname]["count"] += 1
                raSummary[fname]["size"] += size

            raFd.close()

            # print file size #
            fsize = UtilMgr.getFileSizeStr(raFd.name)

            SysMgr.printInfo(
                "saved the readahead list to '%s'%s successfully"
                % (raFd.name, fsize)
            )
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to save the readahead list to '%s'" % raFd.name, True
            )

        return readaheadList, raSummary

    @staticmethod
    def getReadaheadItems():
        # get readahead list path #
        if "RALIST" in SysMgr.environList:
            # set list file #
            raPath = SysMgr.environList["RALIST"][0]
            if raPath == "SET":
                raPath = "readahead.list"

            # convert to absolute path #
            raPath = os.path.realpath(raPath)

            # set inode scan flag #
            if not "CONVINODE" in SysMgr.environList:
                SysMgr.addEnvironVar("CONVINODE")
        else:
            raPath = None

        # set minimum size #
        raMin = 0
        if "RAMIN" in SysMgr.environList:
            try:
                raMin = SysMgr.environList["RAMIN"][0]
                raMin = long(raMin)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    (
                        "failed to set the minimum size to '%s'"
                        "for readahead chunk"
                    )
                    % raMin,
                    True,
                )

        # get readahead allow list path #
        raAllowList = []
        if "RAALLOWLIST" in SysMgr.environList:
            # get list file #
            try:
                fname = os.path.realpath(SysMgr.environList["RAALLOWLIST"][0])

                SysMgr.printInfo(
                    "apply readahead target list from '%s'" % fname
                )

                with open(fname, "r") as fd:
                    raAllowList = fd.readlines()
                    raAllowList = list(map(lambda x: x.rstrip(), raAllowList))
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenErr(fname)
                sys.exit(-1)

        # get readahead deny list path #
        raDenyList = []
        if "RADENYLIST" in SysMgr.environList:
            # get list file #
            try:
                fname = os.path.realpath(SysMgr.environList["RADENYLIST"][0])

                SysMgr.printInfo(
                    "apply readahead exception list from '%s'" % fname
                )

                with open(fname, "r") as fd:
                    raDenyList = fd.readlines()
                    raDenyList = list(map(lambda x: x.rstrip(), raDenyList))
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenErr(fname)
                sys.exit(-1)

        # get readahead add list path #
        raAddList = []
        if "RAADDLIST" in SysMgr.environList:
            # get list file #
            try:
                fname = os.path.realpath(SysMgr.environList["RAADDLIST"][0])

                SysMgr.printInfo("apply readahead add list from '%s'" % fname)

                with open(fname, "r") as fd:
                    raAddList = fd.readlines()
                    raAddList = list(map(lambda x: x.rstrip(), raAddList))
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenErr(fname)
                sys.exit(-1)

        return raPath, raMin, raAllowList, raDenyList, raAddList

    @staticmethod
    def mergeMapLine(string, procMap, onlyExec=False, saveAll=False):
        d = FileAnalyzer.parseMapLine(string)
        if not d:
            return

        # get execution permission #
        if d["perm"][-2] == "-":
            isExec = False
        else:
            isExec = True

        # check execution permission #
        if onlyExec and not isExec:
            return

        # convert file name #
        fileName = d["binName"]
        if fileName.startswith("["):
            fileName = fileName[1:-1]
        if fileName.endswith(" (deleted)"):
            fileName = fileName[:-10]

        # set address #
        startAddr = long(d["startAddr"], 16)
        endAddr = long(d["endAddr"], 16)

        newOffset = long(d["offset"], 16)
        newSize = endAddr - startAddr

        # handle discontiguous segments #
        if fileName in procMap and procMap[fileName]["vend"] != startAddr:
            cnt = 0
            while 1:
                newFileName = "%s%s%s" % (fileName, SysMgr.magicStr, cnt)

                # check next segment is contiguous with this line #
                if (
                    newFileName in procMap
                    and procMap[newFileName]["vend"] != startAddr
                ):
                    cnt += 1
                    continue
                else:
                    break

            fileName = newFileName

        # merge map line #
        FileAnalyzer.addMapLine(procMap, fileName, newOffset, newSize)

        # apply attributes #
        if saveAll:
            procMap[fileName]["perm"] = d["perm"]
            procMap[fileName]["devid"] = d["devid"]
            procMap[fileName]["inode"] = d["inode"]
            procMap[fileName]["offset"] = d["offset"]

        # set mapped addr #
        if procMap[fileName]["vstart"] == 0:
            procMap[fileName]["vstart"] = startAddr

        # set executable flag #
        if "exec" not in procMap[fileName] or not procMap[fileName]["exec"]:
            procMap[fileName]["exec"] = isExec

        procMap[fileName]["vend"] = endAddr

    def printProcUsage(self):
        # define alias #
        convert = UtilMgr.convSize2Unit
        convColor = UtilMgr.convColor
        convNum = UtilMgr.convNum
        pageSize = SysMgr.PAGESIZE
        uptime = UtilMgr.convTime(SysMgr.updateUptime())

        # Print process list #
        SysMgr.printPipe(
            (
                "[%s] [Process : %s] [RAM: %s] [Reclaim: %s/%s] "
                "[Uptime: %s] [Keys: Foward/Back/Save/Quit] "
                "[Capture: Ctrl+\\]\n%s"
            )
            % (
                "File Process Info",
                UtilMgr.convNum(len(self.procData)),
                convert(self.profPageCnt * 4 << 10),
                convert(self.pgRclmBg * 4 << 10),
                convert(self.pgRclmFg * 4 << 10),
                uptime,
                twoLine,
            )
        )

        procTitle = "%s(%s)" % ("Thread", "TID")
        SysMgr.printPipe(
            "{0:_^16}({1:_^7})|{2:_^7}|{3:_^120}\n{4:1}".format(
                "Process", "PID", "RAM", procTitle, twoLine
            )
        )

        procInfo = "{0:^16}({0:^7})|{0:7} |".format("")
        threadInfo = " {0:^16}({0:^7})".format("")
        procLength = len(procInfo)
        threadLength = len(threadInfo)
        lineLength = SysMgr.lineLength
        commLen = SysMgr.commLen

        for pid, val in sorted(
            self.procData.items(),
            key=lambda e: long(e[1]["pageCnt"]),
            reverse=True,
        ):
            try:
                rsize = val["pageCnt"] * pageSize
            except:
                SysMgr.printWarn(
                    "failed to get total mapped size for %s" % val["comm"],
                    reason=True,
                )
                continue

            if rsize > 0:
                rsize = convColor(convert(rsize), "YELLOW", 7)

            printMsg = "{0:>16}({1:>7})|{2:>7}|".format(
                val["comm"][:commLen], pid, rsize
            )
            linePos = len(printMsg)

            for tid, threadVal in sorted(val["tids"].items()):
                threadInfo = "{0:>1}({1:>1})".format(
                    threadVal["comm"][:commLen], tid
                )
                threadInfo = "{0:>25}".format(threadInfo)

                linePos += threadLength

                if linePos > lineLength:
                    linePos = procLength + threadLength
                    printMsg += "\n" + (" " * (procLength - 2)) + "|"

                printMsg += threadInfo

            SysMgr.printPipe(printMsg)

        SysMgr.printPipe("%s\n\n" % oneLine)

        # remove invalid files #
        for fileName in list(self.fileData):
            if not FileAnalyzer.isValidFile(fileName):
                self.fileData.pop(fileName, None)

    def printUsage(self):
        if not self.procData:
            SysMgr.printErr("no process profiled")
            sys.exit(-1)
        if not self.fileData:
            SysMgr.printErr("no file profiled")
            sys.exit(-1)

        SysMgr.printLogo(big=True)

        # print system information #
        SysMgr.printInfoBuffer()

        # define alias #
        convert = UtilMgr.convSize2Unit
        convColor = UtilMgr.convColor
        convNum = UtilMgr.convNum
        pageSize = SysMgr.PAGESIZE
        uptime = UtilMgr.convTime(SysMgr.updateUptime())

        # print process list #
        self.printProcUsage()

        # Print file list #
        SysMgr.printPipe(
            (
                "[%s] [File: %s] [RAM: %s] [Reclaim: %s/%s] [Uptime: %s]"
                " [Keys: Foward/Back/Save/Quit]\n%s"
            )
            % (
                "File Usage Info",
                UtilMgr.convNum(len(self.fileData)),
                convert(self.profPageCnt * 4 << 10),
                convert(self.pgRclmBg * 4 << 10),
                convert(self.pgRclmFg * 4 << 10),
                uptime,
                twoLine,
            )
        )
        SysMgr.printPipe(
            "{0:_^8}|{1:_^8}|{2:_^5}|{3:_^8}|{4:_^121}\n{5:1}".format(
                "RAM", "File", "%", "PSS", "Library & Process", twoLine
            )
        )

        for fileName, val in sorted(
            self.fileData.items(),
            key=lambda e: long(e[1]["pageCnt"]),
            reverse=True,
        ):

            # get stat #
            memSize = val["pageCnt"] * pageSize
            nrFilePage = long((val["totalSize"] + pageSize - 1) / pageSize)
            fileSize = nrFilePage * pageSize
            if fileSize != 0:
                per = long(long(memSize) / float(fileSize) * 100)
                per = UtilMgr.convCpuColor(per, size=4)
            else:
                per = 0

            try:
                pss = long(memSize / len(val["pids"]))
                if pss > 0:
                    pss = convColor(convert(pss), "GREEN", 7)
            except:
                pss = 0

            if memSize > 0:
                memSize = convColor(convert(memSize), "YELLOW", 7)

            if not val["isRep"]:
                continue
            else:
                if val["nrMap"] - 1 > 0:
                    cntStr = " [Map: %s]" % convNum(val["nrMap"] - 1)
                else:
                    cntStr = ""

                if val["nrOpen"] > 0:
                    cntStr += " [Open: %s]" % convNum(val["nrOpen"])
                else:
                    cntStr += ""

                SysMgr.printPipe(
                    (
                        "{0:>7} |{1:>7} |{2:>4} |{3:>7} | {4:1} "
                        "[Proc: {5:1}] [Link: {6:1}]{7:1}"
                    ).format(
                        memSize,
                        convert(fileSize),
                        per,
                        pss,
                        fileName,
                        len(val["pids"]),
                        convNum(val["hardLink"]),
                        cntStr,
                    )
                )

            # prepare for printing process list #
            pidInfo = ""
            lineLength = SysMgr.lineLength
            pidLength = len(" %16s (%6s) |" % ("", ""))
            ilength = len("{0:7} |{0:7} |{0:4} |{0:7} ".format(""))
            linePos = ilength + pidLength

            # print hard-linked list #
            if val["hardLink"] > 1:
                for fileLink, tmpVal in val["linkList"].items():
                    if fileName != fileLink:
                        SysMgr.printPipe((" " * ilength) + "| -> " + fileLink)

            # print process list #
            for pid, comm in val["pids"].items():
                if linePos > lineLength:
                    linePos = ilength + pidLength
                    pidInfo += "\n" + (" " * ilength) + "|"

                pidInfo += " %16s (%7s) |" % (comm[: SysMgr.commLen], pid)

                linePos += pidLength

            SysMgr.printPipe((" " * ilength) + "|" + pidInfo)
            SysMgr.printPipe(oneLine)

        if self.readaheadStr:
            SysMgr.printPipe(self.readaheadStr)

        SysMgr.printPipe("\n\n\n")

    def scanProcs(self, filterList=None):
        # get process list in proc filesystem #
        pids = SysMgr.getPidList()

        # initialize proc object #
        procObj = TaskAnalyzer(onlyInstance=True)

        # scan tasks #
        for pid in pids:
            try:
                # skip myself #
                if SysMgr.pid == long(pid) and not SysMgr.customCmd:
                    continue
            except SystemExit:
                sys.exit(0)
            except:
                continue

            # make process path #
            procPath = "%s/%s" % (SysMgr.procPath, pid)

            # save stat of process #
            try:
                ret = procObj.saveProcData(procPath, pid)
                pidComm = procObj.procData[pid]["comm"]
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenWarn(procPath)
                continue

            # skip kernel tasks #
            if procObj.isKernelThread(pid):
                continue

            # make path of tid #
            taskPath = "%s/%s" % (procPath, "task")

            try:
                tids = os.listdir(taskPath)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenWarn(taskPath)
                continue

            # scan threads #
            for tid in tids:
                try:
                    long(tid)
                except:
                    continue

                # make thread path #
                threadPath = "%s/%s" % (taskPath, tid)

                # save stat of thread #
                try:
                    ret = procObj.saveProcData(threadPath, tid)
                    comm = procObj.procData[tid]["comm"]
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printOpenWarn(threadPath)
                    continue

                # check condition #
                if (
                    self.target != [""]
                    and not tid in self.target
                    and not UtilMgr.isValidStr(comm, self.target)
                ):
                    continue

                # update procData #
                if not pid in self.procData:
                    self.procData[pid] = dict(self.init_procData)
                    self.procData[pid]["tids"] = {}
                    self.procData[pid]["procMap"] = {}
                    self.procData[pid]["comm"] = pidComm

                    # update mapInfo per process #
                    self.procData[pid][
                        "procMap"
                    ] = FileAnalyzer.getProcMapInfo(pid)

                    # save file info per process #
                    try:
                        fdlist = []
                        fdlistPath = "%s/fd" % procPath
                        fdlist = os.listdir(fdlistPath)
                    except SystemExit:
                        sys.exit(0)
                    except:
                        SysMgr.printOpenWarn(fdlistPath)

                    # scan file descriptors #
                    for fd in fdlist:
                        try:
                            # get real path #
                            fdPath = "%s/%s" % (fdlistPath, long(fd))
                            fname = os.readlink(fdPath)

                            # check files #
                            if not FileAnalyzer.isValidFile(fname):
                                continue
                            elif (
                                tid != pid
                                and fname in self.procData[pid]["procMap"]
                            ):
                                continue
                            elif filterList != [""] and not UtilMgr.isValidStr(
                                fname, filterList
                            ):
                                continue

                            # init file info #
                            size = os.stat(fname).st_size
                            if size == 0:
                                continue
                            procMap = self.procData[pid]["procMap"]
                            procMap[fname] = dict(FileAnalyzer.init_mapData)
                            procMap[fname]["size"] = size
                            procMap[fname]["nrOpen"] = 1
                        except SystemExit:
                            sys.exit(0)
                        except:
                            pass

                # check thread list #
                if tid in self.procData[pid]["tids"]:
                    continue

                # update threadData #
                threadList = SysMgr.getThreadList(pid)
                for ttid in threadList:
                    if ttid in self.procData[pid]["tids"]:
                        continue

                    self.procData[pid]["tids"][ttid] = dict(
                        self.init_threadData
                    )

                    self.procData[pid]["tids"][ttid]["comm"] = SysMgr.getComm(
                        ttid
                    )

    def fillFileMaps(self):
        self.profPageCnt = 0

        for fileName, val in self.fileData.items():
            if val["fileMap"] and val["isRep"]:
                val["pageCnt"] = val["fileMap"].count(1)
                self.profPageCnt += val["pageCnt"]

        pageSize = SysMgr.PAGESIZE
        for pid, val in self.procData.items():
            for fileName, mapInfo in val["procMap"].items():
                if not fileName in self.fileData:
                    continue
                elif not self.fileData[fileName]["fileMap"] or not mapInfo:
                    continue

                # convert address and size to index in mapping table #
                offset = mapInfo["offset"] - self.fileData[fileName]["offset"]
                offset = long((offset + pageSize - 1) / pageSize)
                size = long((mapInfo["size"] + pageSize - 1) / pageSize)

                mapInfo["fileMap"] = list(
                    self.fileData[fileName]["fileMap"][offset:size]
                )
                mapInfo["pageCnt"] = mapInfo["fileMap"].count(1)
                val["pageCnt"] += mapInfo["pageCnt"]

    def mergeFileMapInfo(self, filterList=[]):
        myPid = str(SysMgr.pid)
        for pid, val in self.procData.items():
            for fileName, scope in val["procMap"].items():
                # check file filter #
                if filterList != [""] and not UtilMgr.isValidStr(
                    fileName, filterList
                ):
                    continue

                newOffset = scope["offset"]
                newSize = scope["size"]

                # merge map line #
                FileAnalyzer.addMapLine(
                    self.fileData, fileName, newOffset, newSize
                )

                # add map count #
                if scope["nrMap"]:
                    self.fileData[fileName]["nrMap"] += scope["nrMap"]

                # add open count #
                if scope["nrOpen"]:
                    self.fileData[fileName]["nrOpen"] += scope["nrOpen"]

                # add pid into file info #
                if not self.fileData[fileName]["pids"]:
                    self.fileData[fileName]["pids"] = {}
                if not pid in self.fileData[fileName]["pids"] and pid != myPid:
                    self.fileData[fileName]["pids"][pid] = val["comm"]

    def getFilePageMaps(self):
        # pylint: disable=no-member

        pageSize = SysMgr.PAGESIZE
        self.profSuccessCnt = 0
        self.profFailedCnt = 0

        # get ctypes object #
        if not SysMgr.guiderObj:
            SysMgr.importPkgItems("ctypes")

        # define readahead list #
        pathConvList = {}
        readaheadList = []
        skipFiles = {}

        # get readahead items #
        (
            raPath,
            raMin,
            raAllowList,
            raDenyList,
            raAddList,
        ) = FileAnalyzer.getReadaheadItems()

        for fileName, val in self.fileData.items():
            # check exceptional file #
            if not FileAnalyzer.isValidFile(fileName):
                continue

            if self.intervalFileData:
                # use file descriptor already saved as possible #
                try:
                    fileData = self.intervalFileData
                    fileInfo = fileData[len(self.intervalFileData) - 1][
                        fileName
                    ]

                    val["fd"] = fileInfo["fd"]

                    val["totalSize"] = fileInfo["totalSize"]

                    val["isRep"] = fileInfo["isRep"]
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

                if not val["isRep"]:
                    continue

            if not val["fd"]:
                """
                no fd related to this file
                case 1) no opened
                case 2) closed by mincore error
                case 3) closed because of rlimit
                """

                try:
                    # check whether pages are on memory or not #
                    stat = os.stat(fileName)

                    devid = stat.st_dev
                    inode = stat.st_ino

                    # check whether this file was profiled or not #
                    if inode in self.inodeData:
                        found = False
                        repFile = ""
                        fileList = {}
                        procList = dict(val["pids"].items())

                        for fileIdx, devid in self.inodeData[inode].items():
                            # this hard-lined file was already profiled #
                            if devid != devid:
                                continue

                            found = True

                            # add file into same file list #
                            fileList[fileName] = True
                            fileList[fileIdx] = True

                            # merge process list related to this file #
                            procList.update(self.fileData[fileIdx]["pids"])

                            if self.fileData[fileIdx]["isRep"]:
                                repFile = fileIdx

                        self.inodeData[inode][fileName] = devid

                        if found:
                            self.fileData[fileName]["isRep"] = False
                            hardLinkCnt = len(fileList)

                            # set representative file #
                            for fileIdx, value in fileList.items():
                                self.fileData[fileIdx]["repFile"] = repFile
                                self.fileData[fileIdx][
                                    "hardLink"
                                ] = hardLinkCnt

                            # assign merged process list to representative file #
                            self.fileData[repFile]["pids"] = procList
                            self.fileData[repFile]["hardLink"] = hardLinkCnt

                            if self.fileData[repFile]["linkList"]:
                                self.fileData[repFile]["linkList"].update(
                                    fileList
                                )
                            else:
                                self.fileData[repFile]["linkList"] = fileList

                            continue
                    else:
                        self.inodeData[inode] = dict(self.init_inodeData)
                        self.inodeData[inode][fileName] = devid

                    # get meta data #
                    size = stat.st_size
                    linkCnt = stat.st_nlink
                    time = stat.st_atime

                    # update meta data #
                    val["inode"] = inode
                    val["totalSize"] = size
                    val["linkCnt"] = linkCnt
                    val["accessTime"] = time

                    # open file #
                    val["fd"] = open(fileName, "r")
                except SystemExit:
                    sys.exit(0)
                except:
                    self.profFailedCnt += 1
                    if SysMgr.warnEnable:
                        SysMgr.printOpenWarn(fileName)
                    continue

            # check file size whether it is readable or not #
            if val["totalSize"] <= 0:
                self.profFailedCnt += 1
                if SysMgr.warnEnable:
                    SysMgr.printWarn("failed to mmap %s" % fileName)
                continue

            # prepare variables for mincore syscall #
            fd = val["fd"].fileno()
            offset = val["offset"]
            size = val["totalSize"]

            # get page-aligned size #
            tsize = long((size + pageSize - 1) / pageSize)
            size = tsize * pageSize

            if SysMgr.guiderObj:
                # map a file to ram with PROT_NONE(0), MAP_SHARED(0x10) flags #
                mm = SysMgr.guiderObj.mmap(0, size, 0, 2, fd, offset)

                # call mincore syscall by standard libc library #
                pagemap = SysMgr.guiderObj.mincore(mm, size)

                # unmap #
                SysMgr.guiderObj.munmap(mm, size)
            else:
                # map a file to ram with PROT_NONE(0), MAP_SHARED(0x10) flags #
                mm = SysMgr.libcObj.mmap(
                    POINTER(c_char)(), size, 0, 2, fd, offset
                )

                # make a pagemap table #
                pagemap = (tsize * c_ubyte)()

                # call mincore syscall by standard libc library #
                ret = SysMgr.libcObj.mincore(
                    mm, size, cast(pagemap, POINTER(c_ubyte))
                )
                if ret < 0:
                    pagemap = None

                # unmap #
                SysMgr.libcObj.munmap(mm, size)

            # save the on-memory file page table #
            if pagemap:
                try:
                    if SysMgr.guiderObj:
                        val["fileMap"] = [
                            ord(pagemap[i]) for i in xrange(tsize)
                        ]
                    else:
                        val["fileMap"] = [pagemap[i] for i in xrange(tsize)]

                    self.profSuccessCnt += 1

                    # fd resource is about to run out #
                    if SysMgr.maxKeepFd < fd:
                        val["fd"].close()
                        val["fd"] = None
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printWarn("failed to access %s" % fileName)
                    val["fileMap"] = None
                    self.profFailedCnt += 1

                # add filemap info to readahead list #
                if raPath:
                    # check allow list #
                    if raAllowList and not UtilMgr.isValidStr(
                        fileName, raAllowList
                    ):
                        skip = True
                    # check deny list #
                    elif raDenyList and UtilMgr.isValidStr(
                        fileName, raDenyList
                    ):
                        skip = True
                    else:
                        skip = False

                    # check skip condition #
                    if skip:
                        skipFiles.setdefault(fileName, None)
                        continue

                    fileIdx = len(pathConvList)
                    pathConvList.setdefault(fileName, [fileName, fileIdx])

                    start = -1
                    for idx, bit in enumerate(pagemap):
                        if start == -1:
                            if bit:
                                start = idx
                            else:
                                continue

                        # check contiguous chunk #
                        if bit and idx != len(pagemap) - 1:
                            continue

                        # add contiguous chunks to readahead list #
                        offset = start * pageSize
                        size = (idx - start + 1) * pageSize
                        readaheadList.append([fileIdx, offset, size])

                        start = -1
            else:
                val["fd"].close()
                val["fd"] = None

        if not self.fileData:
            SysMgr.printErr("failed to profile files")
            sys.exit(-1)

        SysMgr.printGood(
            "profiled a total of %s files"
            % UtilMgr.convNum(self.profSuccessCnt)
        )

        if self.profFailedCnt > 0:
            SysMgr.printWarn(
                "failed to open a total of %s files"
                % UtilMgr.convNum(self.profFailedCnt)
            )

        # print skip files #
        for path in sorted(list(skipFiles)):
            SysMgr.printWarn("skipped adding '%s' to readahead list" % path)

        # make readahead list file #
        if raPath:
            readaheadList, raSummary = FileAnalyzer.makeReadaheadFile(
                raPath, readaheadList, pathConvList, raMin, raAddList
            )

            # print readahead list info #
            self.readaheadStr = FileAnalyzer.getReadaheadListStr(
                readaheadList, raSummary
            )


class LogMgr(object):
    """Manager for error log"""

    # define log level #
    LOG_EMERG = 0
    LOG_ALERT = 1
    LOG_CRIT = 2
    LOG_ERR = 3
    LOG_WARNING = 4
    LOG_NOTICE = 5
    LOG_INFO = 6
    LOG_DEBUG = 7

    # define syslog type #
    SYSLOG_ACTION_CLOSE = 0
    SYSLOG_ACTION_OPEN = 1
    SYSLOG_ACTION_READ = 2
    SYSLOG_ACTION_READ_ALL = 3
    SYSLOG_ACTION_READ_CLEAR = 4
    SYSLOG_ACTION_CLEAR = 5
    SYSLOG_ACTION_CONSOLE_OFF = 6
    SYSLOG_ACTION_CONSOLE_ON = 7
    SYSLOG_ACTION_CONSOLE_LEVEL = 8
    SYSLOG_ACTION_SIZE_UNREAD = 9
    SYSLOG_ACTION_SIZE_BUFFER = 10

    # define journal type #
    SD_JOURNAL_LOCAL_ONLY = 1 << 0
    SD_JOURNAL_RUNTIME_ONLY = 1 << 1
    SD_JOURNAL_SYSTEM = 1 << 2
    SD_JOURNAL_CURRENT_USER = 1 << 3
    SD_JOURNAL_OS_ROOT = 1 << 4
    SD_JOURNAL_SYSTEM_ONLY = SD_JOURNAL_SYSTEM

    def __init__(self, target="error"):
        self.errFd = None

        if target == "error":
            self.terminal = sys.stderr
            self.notified = False
            self.error = False
        else:
            # backup #
            SysMgr.backupFile(target)

            # open #
            try:
                self.terminal = open(target, "w")
                os.chmod(target, 0o777)
                self.error = True
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("failed to open %s" % target, True)

    def write(self, message):
        try:
            self.terminal.write(message)
            self.terminal.flush()
        except SystemExit:
            sys.exit(0)
        except:
            return

        if self.error:
            return

        # check cache dir #
        if not os.path.exists(SysMgr.cacheDirPath):
            try:
                os.makedirs(SysMgr.cacheDirPath)
            except SystemExit:
                sys.exit(0)
            except:
                err = SysMgr.getErrMsg()
                SysMgr.printWarn(
                    (
                        "failed to make %s directory because %s "
                        "so that use /tmp dir"
                    )
                    % (SysMgr.cacheDirPath, err),
                    True,
                )
                SysMgr.cacheDirPath = "/tmp"

        # set file path for error log #
        if not self.errFd:
            errorFile = "%s/guider.err" % SysMgr.cacheDirPath
            if not SysMgr.isWritable(errorFile):
                SysMgr.printWarn(
                    (
                        "failed to get write permission for %s "
                        "so that use /tmp/guider.err"
                    )
                    % errorFile,
                    True,
                )
                SysMgr.cacheDirPath = "/tmp"
                errorFile = "%s/guider.err" % SysMgr.cacheDirPath

            try:
                self.errFd = open(errorFile, "a")
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenErr(errorFile)
                self.error = True

        try:
            if hasattr(self, "notified") and not self.notified:
                SysMgr.printErr(
                    (
                        "please report '%s' to "
                        "https://github.com/iipeace/guider/issues"
                    )
                    % self.errFd.name
                    if self.errFd
                    else "error"
                )
                self.notified = True

            # write log to the file #
            if self.errFd:
                SysMgr.writeErr(self.errFd, message)
        except SystemExit:
            sys.exit(0)
        except:
            pass

    def flush(self):
        pass

    def __getattr__(self, attr):
        return getattr(self.terminal, attr)

    @staticmethod
    def lock(fd):
        # pylint: disable=undefined-variable
        if not SysMgr.isLinux:
            return

        try:
            SysMgr.importPkgItems("fcntl")
            lockf(fd, LOCK_EX, 1, 0, 0)
        except SystemExit:
            sys.exit(0)
        except:
            name = fd.name if fd else "logger"
            reason = SysMgr.getErrMsg()
            print(
                "\n[ERROR] failed to get lock for %s because %s"
                % (name, reason)
            )

    @staticmethod
    def unlock(fd):
        # pylint: disable=undefined-variable
        if not SysMgr.isLinux:
            return

        try:
            SysMgr.importPkgItems("fcntl")
            lockf(fd, LOCK_UN, 1, 0, 0)
        except SystemExit:
            sys.exit(0)
        except:
            name = fd.name if fd else "logger"
            reason = SysMgr.getErrMsg()
            print(
                "\n[ERROR] failed to free lock for %s because %s"
                % (name, reason)
            )

    @staticmethod
    def printSyslog(console=False):
        # check root permission #
        SysMgr.checkRootPerm()

        # open syslog file #
        try:
            if not SysMgr.syslogFd:
                SysMgr.syslogFd = open(SysMgr.syslogPath, "r")
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenErr(SysMgr.syslogPath)
            sys.exit(-1)

        # set nonblock attribute #
        try:
            if SysMgr.findOption("Q"):
                SysMgr.setBlock(SysMgr.syslogFd, False)
                stream = True
            else:
                SysMgr.setBlock(SysMgr.syslogFd)
                stream = False
        except SystemExit:
            sys.exit(0)
        except:
            pass

        SysMgr.printInfo("start printing syslog... [ STOP(Ctrl+c) ]")

        # set file posiion #
        SysMgr.syslogFd.seek(0)

        # get item for log filter #
        if "WATCHLOG" in SysMgr.environList:
            watchcond = SysMgr.environList["WATCHLOG"][0].split("+")
        else:
            watchcond = None

        while 1:
            log = SysMgr.syslogFd.readline()
            if not log:
                if stream:
                    break
                else:
                    time.sleep(0.1)
            elif not UtilMgr.isValidStr(log, inc=True):
                continue

            if SysMgr.outPath and console:
                print(log)

            SysMgr.printPipe(log, newline=False)

            # check log command #
            SysMgr.checkLogCond(log, watchcond)

    @staticmethod
    def printJournal(console=False):
        # get ctypes object #
        SysMgr.importPkgItems("ctypes")

        """
        struct sd_journal {
                int toplevel_fd;

                char *path;
                char *prefix;
                char *namespace;

                OrderedHashmap *files;
                IteratedCache *files_cache;
                MMapCache *mmap;

                Location current_location;

                JournalFile *current_file;
                uint64_t current_field;

                Match *level0, *level1, *level2;

                pid_t original_pid;

                int inotify_fd;
                unsigned current_invalidate_counter, last_invalidate_counter;
                usec_t last_process_usec;
                unsigned generation;

                /* Iterating through unique fields and their data values */
                char *unique_field;
                JournalFile *unique_file;
                uint64_t unique_offset;

                /* Iterating through known fields */
                JournalFile *fields_file;
                uint64_t fields_offset;
                uint64_t fields_hash_table_index;
                char *fields_buffer;
                size_t fields_buffer_allocated;

                int flags;

                bool on_network:1;
                bool no_new_files:1;
                bool no_inotify:1;
                bool unique_file_lost:1; /* File we were iterating over got
                                            removed, and there were no more
                                            files, so sd_j_enumerate_unique
                                            will return a value equal to 0. */
                bool fields_file_lost:1;
                bool has_runtime_files:1;
                bool has_persistent_files:1;

                size_t data_threshold;

                Hashmap *directories_by_path;
                Hashmap *directories_by_wd;

                Hashmap *errors;
        };
        """

        # load libsystemd library #
        try:
            if not SysMgr.systemdObj:
                SysMgr.systemdObj = SysMgr.loadLib(SysMgr.libsystemdPath)
                if not SysMgr.systemdObj:
                    raise Exception("no %s" % SysMgr.libsystemdPath)

            func = "sd_journal_open"
            if not hasattr(SysMgr.systemdObj, func):
                raise Exception("no %s in %s" % (func, SysMgr.libsystemdPath))
        except:
            SysMgr.printErr("failed to print journal", True)
            sys.exit(-1)

        # define shortcut for object #
        systemdObj = SysMgr.systemdObj

        # open journal #
        jrl = c_void_p(0)
        flag = LogMgr.SD_JOURNAL_LOCAL_ONLY
        res = systemdObj.sd_journal_open(byref(jrl), c_int(flag))
        if res < 0:
            SysMgr.printErr("failed to print journal because no journal")
            return

        SysMgr.printInfo("start printing journal... [ STOP(Ctrl+c) ]")

        # set head #
        res = systemdObj.sd_journal_seek_head(jrl)
        if res < 0:
            SysMgr.printErr("failed to print journal because no journal head")
            return

        # get item for log filter #
        if "WATCHLOG" in SysMgr.environList:
            watchcond = SysMgr.environList["WATCHLOG"][0].split("+")
        else:
            watchcond = None

        # get tail value #
        if "TAIL" in SysMgr.environList:
            since = time.time()
        else:
            since = 0

        # initialize variables #
        data = c_void_p(0)
        size = c_size_t(0)
        usec = c_uint64(0)
        timeout = c_uint64(10000)
        quitFlag = SysMgr.findOption("Q")

        # set fields #
        if SysMgr.inputParam:
            fieldList = SysMgr.inputParam.split(",")
        else:
            fieldList = [
                b"_TIME",
                b"_HOSTNAME",
                b"_TRANSPORT",
                b"_COMM",
                b"_PID",
                b"MESSAGE",
            ]

        # move to the end of journal #
        if not SysMgr.showAll:
            systemdObj.sd_journal_seek_tail(jrl)

        # define summary table #
        table = {}

        SysMgr.printPipe("\n")

        # start reading journal in loop #
        try:
            while 1:
                res = systemdObj.sd_journal_next(jrl)
                if res == 0:
                    ret = systemdObj.sd_journal_wait(jrl, timeout)
                    # SD_JOURNAL_NOP / SD_JOURNAL_APPEND / SD_JOURNAL_INVALID #
                    if ret == 0:
                        if quitFlag:
                            break
                        else:
                            continue
                    elif ret == 1 or ret == 2:
                        continue
                    elif ret < 0:
                        break
                elif res < 1:
                    break

                # check skip condition for time #
                if since:
                    ret = systemdObj.sd_journal_get_realtime_usec(
                        jrl, byref(usec)
                    )
                    if ret == 0:
                        realtime = usec.value / 1000000
                        if realtime < since:
                            continue

                # traverse specific fields #
                if SysMgr.inputParam:
                    res = systemdObj.sd_journal_restart_data(jrl)
                    while 1:
                        res = systemdObj.sd_journal_enumerate_data(
                            jrl, byref(data), byref(size)
                        )
                        if res < 1:
                            break

                        SysMgr.printPipe(
                            cast(data, c_char_p).value.decode("latin-1"),
                            flush=True,
                        )
                    SysMgr.printPipe(flush=True)
                    continue

                # traverse all fields #
                jrlStr = b""
                for field in fieldList:
                    if field == b"_TIME":
                        # get time #
                        ret = systemdObj.sd_journal_get_realtime_usec(
                            jrl, byref(usec)
                        )
                        if ret < 0:
                            realtime = 0
                        else:
                            realtime = usec.value

                        wtime = time.strftime(
                            "%m %d %H:%M:%S ",
                            time.localtime(realtime / float(1000000)),
                        )
                        """
                        ret = systemdObj.sd_journal_get_monotonic_usec(
                            jrl, byref(usec), boottime)
                        """

                        # set time #
                        jrlStr += wtime.encode()

                        continue

                    res = systemdObj.sd_journal_get_data(
                        jrl, field, byref(data), byref(size)
                    )
                    if res < 0:
                        continue

                    val = cast(data, c_char_p).value[len(field) + 1 :]
                    if field == b"_COMM":
                        if SysMgr.outPath:
                            comm = val.decode("latin-1").rstrip("\x01")
                            table.setdefault(comm, 0)
                            table[comm] += 1
                    elif field == b"_PID":
                        val = b"[%s]: " % val
                    elif field == b"_TRANSPORT" and val == b"kernel":
                        val += b": "
                    else:
                        val += b" "

                    jrlStr += val

                # print journal #
                if jrlStr:
                    try:
                        decstr = jrlStr.decode("latin-1")

                        # check filter #
                        if not UtilMgr.isValidStr(decstr):
                            continue

                        if SysMgr.outPath and console:
                            print(decstr)

                        SysMgr.printPipe(decstr, flush=True)

                        # check log command #
                        SysMgr.checkLogCond(decstr, watchcond)
                    except SystemExit:
                        sys.exit(0)
                    except:
                        SysMgr.printPipe(jrlStr, flush=True)

            # close journal #
            systemdObj.sd_journal_close(jrl)
        except SystemExit:
            if not table:
                return

            SysMgr.printPipe("\n[Journal Summary]\n%s\n" % twoLine)

            SysMgr.printPipe(
                "{0:>32} {1:>16}\n{2:1}".format("COMM", "COUNT", oneLine)
            )

            total = 0
            for comm, count in sorted(
                table.items(), key=lambda x: x[1], reverse=True
            ):
                SysMgr.printPipe(
                    "{0:>32} {1:>16}".format(comm, UtilMgr.convNum(count))
                )
                total += count

            SysMgr.printPipe(
                "\n{0:>32} {1:>16}\n{2:1}".format(
                    "TOTAL", UtilMgr.convNum(total), oneLine
                )
            )

    @staticmethod
    def getKmsg(line=0):
        try:
            fd = os.open(SysMgr.kmsgPath, os.O_RDONLY | os.O_NONBLOCK)
        except:
            return None

        logs = []
        while 1:
            try:
                data = os.read(fd, SysMgr.PAGESIZE).decode()
                logs.append(data)
            except SystemExit:
                sys.exit(0)
            except:
                break

        # convert logs #
        retList = []
        for log in logs[-line:]:
            # parse log #
            pos = log.find(";")

            meta = log[:pos].split(",")
            if len(meta) > 2:
                nrLevel = long(meta[0])
                try:
                    level = ConfigMgr.LOG_LEVEL[nrLevel]
                except:
                    level = nrLevel

                # time #
                ltime = str(meta[2])
                if len(ltime) < 7:
                    ltime = "0.%s" % ltime
                else:
                    ltime = "%s.%s" % (ltime[:-6], ltime[-6:])

                # name & log #
                log = log[pos + 1 :]
                npos = log.find(":")
                name = log[:npos]
                if log[-1] == "\n":
                    log = log[npos + 1 : -1]
                else:
                    log = log[npos + 1 :]

                retList.append("[%s] (%s) %s: %s" % (ltime, level, name, log))

        return retList[-line:]

    @staticmethod
    def printKmsg(console=False):
        # open kmsg device node #
        try:
            if not SysMgr.kmsgFd:
                SysMgr.kmsgFd = open(SysMgr.kmsgPath, "r")
                if SysMgr.findOption("Q"):
                    SysMgr.setBlock(SysMgr.kmsgFd, False)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenErr(SysMgr.kmsgPath)
            sys.exit(-1)

        SysMgr.printInfo("start printing kernel log... [ STOP(Ctrl+c) ]")

        # get item for log filter #
        if "WATCHLOG" in SysMgr.environList:
            watchcond = SysMgr.environList["WATCHLOG"][0].split("+")
        else:
            watchcond = None

        # get tail value #
        if "TAIL" in SysMgr.environList:
            tail = True
            SysMgr.getUptime()
        else:
            tail = False

        # check device node #
        try:
            SysMgr.kmsgFd.readline()
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.kmsgFd = None

        # syslog #
        if not SysMgr.kmsgFd:
            # get ctypes object #
            SysMgr.importPkgItems("ctypes")

            # get kernel ring-buffer size #
            size = SysMgr.syscall(
                "syslog", LogMgr.SYSLOG_ACTION_SIZE_BUFFER, 0, 0
            )

            # allocate buffer #
            buf = (c_char * size)()

            ret = SysMgr.syscall(
                "syslog", LogMgr.SYSLOG_ACTION_READ_ALL, buf, size
            )
            if ret > 0:
                logBuf = memoryview(buf).tobytes().decode()
                for line in logBuf.split("\n"):
                    if not UtilMgr.isValidStr(line):
                        continue

                    # convert log level #
                    if line.startswith("<"):
                        try:
                            level, line = line.split(">", 1)

                            nrLevel = long(level[1:])
                            try:
                                level = ConfigMgr.LOG_LEVEL[nrLevel]
                            except:
                                level = nrLevel

                            ts, line = line.split(" ", 1)

                            line = "%s <%s> %s" % (ts, level, line)
                        except SystemExit:
                            sys.exit(0)
                        except:
                            pass

                    # skip old logs #
                    if tail:
                        try:
                            if not line.startswith("["):
                                raise Exception("no time")

                            item = line.split("]", 1)[0]
                            ltime = item[1:]

                            if float(ltime) < SysMgr.uptime:
                                continue
                        except SystemExit:
                            sys.exit(0)
                        except:
                            pass

                    # print to console #
                    if SysMgr.outPath and console:
                        print(line)

                    # print #
                    SysMgr.printPipe(line)

                    # check log command #
                    SysMgr.checkLogCond(line, watchcond)

            while 1:
                memset(buf, 0, size)
                ret = SysMgr.syscall(
                    "syslog", LogMgr.SYSLOG_ACTION_READ, buf, size
                )
                if ret < 1:
                    continue

                logBuf = memoryview(buf).tobytes().decode()
                if not UtilMgr.isValidStr(line):
                    continue

                if SysMgr.outPath and console:
                    print(logBuf)

                SysMgr.printPipe(logBuf)

            return

        # change file position #
        try:
            SysMgr.kmsgFd.seek(0)
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # kmsg node #
        while 1:
            jsonResult = {}
            log = SysMgr.kmsgFd.readline()
            if not log:
                break

            # apply filter #
            if not UtilMgr.isValidStr(log):
                continue

            # parse log #
            # PRIORITY,SEQUENCE_NUM,TIMESTAMP,-;MESSAGE #
            pos = log.find(";")
            meta = log[:pos].split(",")
            if len(meta) > 2:
                nrLevel = long(meta[0])
                try:
                    level = ConfigMgr.LOG_LEVEL[nrLevel]
                except:
                    level = nrLevel

                # time #
                ltime = str(meta[2])
                if len(ltime) < 7:
                    ltime = "0.%s" % ltime
                else:
                    ltime = "%s.%s" % (ltime[:-6], ltime[-6:])

                # skip old logs #
                if tail:
                    if float(ltime) < SysMgr.uptime:
                        continue

                # update pos #
                log = log[pos + 1 :]

                # name #
                npos = log.find(":")
                if npos < 0:
                    name = ""
                else:
                    name = log[:npos]

                # log #
                if log[-1] == "\n":
                    log = log[npos + 1 : -1]
                else:
                    log = log[npos + 1 :]

                # update message #
                if name:
                    log = "%s: %s" % (name, log)

                # set message #
                if SysMgr.jsonEnable:
                    jsonResult = dict(
                        time=ltime, level=level, name=name, log=log
                    )
                else:
                    if not SysMgr.outPath:
                        level = UtilMgr.convColor(level, "BOLD")
                        name = UtilMgr.convColor(name, "SPECIAL")
                        ltime = UtilMgr.convColor(ltime, "GREEN")
                    log = "[%s] (%s) %s" % (ltime, level, log)

            # print message #
            if SysMgr.jsonEnable:
                if jsonResult:
                    jsonResult = UtilMgr.convDict2Str(
                        jsonResult, pretty=not SysMgr.streamEnable
                    )
                    SysMgr.printPipe(jsonResult)
            else:
                if SysMgr.outPath and console:
                    print(log.rstrip())

                SysMgr.printPipe(log.rstrip())

            # check log command #
            SysMgr.checkLogCond(log, watchcond)

    @staticmethod
    def doLogKmsg(msg=None, level=None):
        # open kmsg device node #
        try:
            if not SysMgr.kmsgFd:
                SysMgr.kmsgFd = open(SysMgr.kmsgPath, "w")
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenErr(SysMgr.kmsgPath)
            return -1

        # print messages #
        try:
            msgList = msg.split("\n")
            for line in msgList:
                SysMgr.kmsgFd.write("guider: %s\n" % line)
                SysMgr.kmsgFd.flush()
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("failed to write kmsg", reason=True)
            return -1

        return 0

    @staticmethod
    def doLogSyslog(msg=None, level=None):
        if not msg:
            return -1

        # load libc #
        SysMgr.loadLibcObj(exit=True)

        # set default level #
        if level is None:
            level = LogMgr.LOG_NOTICE

        # write message #
        SysMgr.libcObj.syslog(level, msg.encode())

        return 0

    @staticmethod
    def doLogJournal(msg=None, level=None):
        # get ctypes object #
        SysMgr.importPkgItems("ctypes")

        if not msg:
            return -1

        # set default level #
        if level is None:
            level = LogMgr.LOG_NOTICE

        # load libsystemd library #
        try:
            if not SysMgr.systemdObj:
                SysMgr.systemdObj = SysMgr.loadLib(SysMgr.libsystemdPath)
                if not SysMgr.systemdObj:
                    raise Exception("no %s" % SysMgr.libsystemdPath)

            func = "sd_journal_print"
            if not hasattr(SysMgr.systemdObj, func):
                raise Exception("no %s in %s" % (func, SysMgr.libsystemdPath))
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to log a journal message", True)
            return -1

        # print message #
        return SysMgr.systemdObj.sd_journal_print(level, msg.encode())


class SysMgr(object):
    """Manager for system"""

    arch = None
    origArgs = []
    kernelVersion = None
    isLinux = True
    isDarwin = False
    isWindows = False
    isAndroid = False
    drawMode = False
    archOption = None

    # page size #
    try:
        PAGESIZE = os.sysconf("SC_PAGE_SIZE")
    except:
        PAGESIZE = 4096

    # define many-core number #
    NRMANYCORE = 8

    # set tick #
    try:
        HZ = 250  # 4ms tick #
        if isLinux:
            TICK = os.sysconf(os.sysconf_names["SC_CLK_TCK"])
        else:
            TICK = long((1 / float(HZ)) * 1000)
    except:
        TICK = long((1 / float(HZ)) * 1000)

    # python call function #
    if sys.version_info < (3, 6):
        pyCallFunc = "PyEval_EvalFrameEx"
    else:
        pyCallFunc = "_PyEval_EvalFrameDefault"

    startInitTime = 0  # init time for Guider #
    startTime = 0  # start time for Guider #
    startRecTime = 0  # start time for Recording #
    startRunTime = 0  # start time for Process #
    startOverheadTime = 0  # start overhead time for Process #

    blockSize = 512
    bufferSize = -1
    termGetId = None
    termSetId = None
    ttyRows = 43
    ttyRowsMargin = 2
    ttyCols = 156
    ttyData = None
    encoding = None
    remoteRun = False
    magicStr = "@@@@@"
    launchBuffer = ""
    lineLength = 154
    pid = 0
    comm = __module__
    commLen = 16
    masterPid = 0
    parentPid = 0
    prio = None
    ioprio = None
    funcDepth = 0
    maxPid = 32768
    maxRdCnt = 1024
    maxSize = 2147483647
    pidDigit = 5
    stdlog = None
    stderr = sys.stderr
    packetSize = 32767
    defaultCliPort = 5554
    defaultServPort = 5555
    bgProcList = None
    waitDelay = 0.5
    repeatCount = 0
    progressCnt = 0
    termCnt = 0
    repeatInterval = 0
    maxInterval = 0
    ipAddr = None
    swappiness = 0
    vmpressure = 0
    overcommit = 0
    limitRepDirSize = 0
    nrRun = 0
    nrReport = 0

    # watermark constants #
    cpuPerHighThreshold = 80
    cpuPerLowThreshold = 10
    memAvailPerThreshold = 10
    memHighThreshold = 1024
    memLowThreshold = 100
    swapPerThreshold = 90
    diskPerHighThreshold = 90
    fdHighThreshold = 1000

    # print condition #
    printCond = dict(
        CPUCOND=-1,
        MEMFREECOND=sys.maxsize,
        MEMAVLCOND=sys.maxsize,
        BLKRDCOND=-1,
        BLKWRCOND=-1,
    )

    # lifecycle condition #
    startUptime = 0
    deadlineUptime = 0
    startCondCpuMore = -1
    startCondCpuLess = -1
    startCondMemMore = -1
    startCondMemLess = -1
    exitCondCpuMore = -1
    exitCondCpuLess = -1
    exitCondMemMore = -1
    exitCondMemLess = -1
    cpuUsage = -1
    memAvail = -1
    memTotal = -1

    # path #
    procPath = "/proc"
    imagePath = None
    mountPath = None
    mountCmd = None
    cgroupPath = None
    drawFormat = "svg"
    debugfsPath = "/sys/kernel/debug"
    cacheDirPath = "/var/log/guider"
    outFilePath = "guider.out"
    confFileName = "guider.conf"
    cmdFileName = "guider.cmd"
    tmpPath = "/tmp"
    kmsgPath = "/dev/kmsg"
    nullPath = "/dev/null"
    rootdevPath = None
    syslogPath = "/var/log/syslog"
    lmkPath = "/sys/module/lowmemorykiller/parameters/minfree"
    pythonPath = sys.executable
    pyLibPath = None
    objdumpPath = []
    rootPath = ""
    fontPath = None
    libdltPath = "libdlt"
    libcPath = "libc"
    libgobjPath = "libgobject-2.0"
    libgioPath = "libgio-2.0"
    libdbusPath = "libdbus-1"
    libcppPath = "libstdc++"
    libsystemdPath = "libsystemd"
    libglesPath = "libGLESv2"
    ldCachePath = "/etc/ld.so.cache"
    libcorkscrewPath = "libcorkscrew"
    libdemanglePath = libcppPath
    libLLVMPath = "libLLVM.so"
    environList = {}
    externList = {}
    environ = {}
    eventLogPath = None
    inputFile = None
    outputFile = None
    inputParam = None
    outPath = None
    origOutPath = None
    freezerPath = None

    # list #
    signalCmd = "trap 'kill $$' INT\n"
    saveCmd = None
    boundaryLine = None
    nrTop = 0
    pipeForPager = None
    printFd = None
    fileSuffix = None
    parsedAnalOption = False
    optionList = []
    customCmd = []
    pyFuncFilter = []
    userCmd = []
    kernelCmd = []
    udpListCache = {}
    tcpListCache = {}
    udsListCache = {}
    ipAddrCache = {}
    customEventList = []
    userEventList = []
    kernelEventList = []
    perfEventChannel = {}
    perfTargetEvent = []
    ignoreItemList = []
    idList = []
    perfEventData = {}
    commCache = {}
    commFdCache = {}
    fdCache = {}
    libCache = {}
    rawFdCache = {}
    syscallCache = {}
    netAddrCache = {}
    pciList = []
    limitDirList = {}

    # threshold #
    thresholdData = {}
    prevThresholdData = {}
    thresholdTarget = {}
    thresholdRefreshList = []
    thresholdEventList = {}
    thresholdEventHistory = {}
    eventLockList = {}
    eventCommandList = {}

    # object #
    impPkg = {}
    impGlbPkg = {}
    skipImpPkg = {}
    exitFuncList = []
    dltObj = None
    dltCtx = None
    shmObj = None
    systemdObj = None
    libcObj = None
    libgioObj = None
    libdbusObj = None
    libcorkscrewObj = None
    libgObj = None
    libglesObj = None
    statvfsObj = None
    guiderObj = None
    libcppObj = None
    libdemangleObj = None
    libLLVMObj = None
    demangleFunc = None
    geterrnoFunc = None
    readaheadFunc = None
    readaheadMaxSize = 1048576  # 1MB #
    matplotlibVersion = 0
    matplotlibDpi = 500
    sigsetObj = None
    sigsetOldObj = None
    ansiObj = None
    localServObj = None
    remoteServObj = None
    netlinkObj = None

    geAttr = [0] * 9
    addrListForPrint = {}
    addrListForReport = {}

    # number #
    maxCore = 0
    nrCore = 0
    utilProc = 0
    logSize = 0
    kmsgLine = 100
    curLine = 0
    totalLine = 0
    dbgEventLine = 0
    uptime = 0
    prevUptime = 0
    uptimeDiff = 0
    diskStats = []
    prevDiskStats = []
    netstat = ""
    prevNetstat = ""
    loadavg = ""
    battery = {}
    netInIndex = -1
    nrUDPSock = 0
    nrTCPSock = 0
    nrUDSSock = 0
    nrTCPConn = 0

    # report #
    reportObject = None
    terminalOver = False
    procBuffer = []
    fixedProcList = {}
    topInstance = None
    procInstance = {}
    fileInstance = {}
    sysInstance = None
    procBufferSize = 0
    bufferOverflowed = False
    bufferString = ""
    bufferList = []
    bufferRows = 0
    systemInfoBuffer = ""
    kerSymTable = {}
    jsonData = {}
    nrTopRank = 10
    layout = None

    showAll = False
    disableAll = False
    intervalNow = 0
    recordStatus = False
    bgStatus = False
    condExit = False
    sort = None
    sortCond = None
    sortCondOp = None
    newlined = True

    # descriptor #
    maxFd = 512
    maxKeepFd = maxFd - 16
    batteryFd = None
    cmdFd = None
    diskStatsFd = None
    eventLogFd = None
    irqFd = None
    kmsgFd = None
    lmkFd = None
    loadavgFd = None
    memFd = None
    mountFd = None
    msgqFd = None
    netdevFd = None
    netstatFd = None
    nullFd = None
    semFd = None
    shmFd = None
    slabFd = None
    softirqFd = None
    statFd = None
    swapFd = None
    syslogFd = None
    uptimeFd = None
    vmstatFd = None
    vmallocFd = None
    zoneFd = None
    swappinessFd = None
    vmpressureFd = None
    overcommitFd = None

    # flag #
    affinityEnable = False
    avgEnable = False
    barGraphEnable = None
    binderEnable = False
    blockEnable = False
    bufferLossEnable = False
    cgroupEnable = False
    cloneEnable = True
    cmdEnable = False
    cmdlineEnable = False
    colorEnable = True
    compressEnable = False
    countEnable = False
    cpuAvgEnable = True
    cpuEnable = True
    dbusTopEnable = False
    delayEnable = False
    demangleEnable = True
    depEnable = False
    diskEnable = False
    dltEnable = False
    dltTopEnable = False
    dwarfEnable = False
    elasticEnable = False
    encodeEnable = True
    eventHandleEnable = True
    exceptCommFilter = False
    execEnable = None
    exitFlag = False
    inExit = False
    fileEnable = False
    fileTopEnable = False
    fixTargetEnable = False
    floatEnable = False
    forceColorEnable = False
    forceEnable = False
    freeMemEnable = False
    fsEnable = False
    functionEnable = False
    generalEnable = True
    gpuEnable = True
    graphEnable = False
    groupProcEnable = False
    heapEnable = False
    i2cEnable = False
    iouringEnable = False
    inWaitStatus = False
    initWssEnable = False
    inotifyEnable = False
    intervalEnable = 0
    irqEnable = False
    journalEnable = False
    jsonEnable = False
    keventEnable = False
    kvmEnable = False
    kmsgEnable = False
    latEnable = cpuEnable
    leakEnable = False
    lockEnable = False
    logEnable = True
    loggingEnable = False
    loggingOpsEnable = False
    logoEnable = True
    memEnable = False
    minStatEnable = False
    networkEnable = False
    nsEnable = False
    oomEnable = False
    perfEnable = False
    perfGroupEnable = False
    pipeEnable = False
    powerEnable = False
    printEnable = True
    processEnable = True
    pssEnable = False
    rankProcEnable = True
    recursionEnable = False
    reportEnable = False
    reportFileEnable = False
    resetEnable = False
    rssEnable = False
    schedEnable = False
    schedstatEnable = True
    selectEnable = True
    sigHandlerEnable = False
    stackEnable = False
    streamEnable = False
    sttyEnable = None
    sysEnable = False
    syslogEnable = False
    systemEnable = False
    taskEnable = True
    termFlag = True
    tgidEnable = True
    threadEnable = False
    thresholdEnable = False
    taskThresholdEnable = False
    totalEnable = False
    truncEnable = True
    ttyEnable = False
    ueventEnable = False
    userEnable = False
    userEnableWarn = False
    userRecordEnable = False
    ussEnable = False
    vssEnable = False
    waitEnable = False
    warnEnable = False
    wchanEnable = False
    wfcEnable = False
    wqEnable = False
    wssEnable = False
    idlePageEnable = False

    cmdList = {}
    rcmdList = {}
    savedProcTree = {}
    savedProcComm = {}
    savedMountTree = {}
    preemptGroup = []
    filterGroup = []
    schedFilter = []
    affinityFilter = []
    killFilter = []
    syscallList = []
    syscallExceptList = []
    perCoreList = []
    perCoreDrawList = []
    childList = {}
    gpuMemGetters = None
    pidFilter = ""

    cliCmdStr = """
Commands:
    - RUN:Command
    - BROADCAST:Command
    - UPSTREAM:Command
    - NOTIFY:Event
    - DOWNLOAD:RemotePath@LocalPath
    - UPLOAD:LocalPath@RemotePath
    - LIST
    - JOBS
    - PING
    - CLEAR
    - RESTART
    - HISTORY
    - QUIT\n"""

    def __init__(self, onlyInstance=False):
        self.cpuInfo = {}
        self.cpuCacheInfo = {}
        self.cpuCacheData = {}
        self.memInfo = {}
        self.devInfo = {}
        self.diskInfo = {}
        self.mountInfo = {}
        self.networkInfo = {}
        self.systemInfo = {}
        self.partitionInfo = {}
        self.devArchInfo = {}
        self.devNodeInfo = {}

        self.cpuData = None
        self.gpuData = {}
        self.memData = {}
        self.diskData = {}
        self.blockData = {}
        self.storageData = {}
        self.prevStorageData = {}
        self.storageMapData = {}
        self.ipcData = {}
        self.prevIpcData = {}
        self.userData = {}
        self.mountData = None
        self.mountUpdated = False
        self.loadData = None
        self.nrMaxThread = 0
        self.cmdlineData = None
        self.osData = None
        self.devData = None
        self.procData = None
        self.macAddr = None
        self.uname = []
        self.openFileData = {}
        self.limitData = []

        # resource update time #
        self.netUpdate = None
        self.storageUpdate = None
        self.ipcUpdate = None

        SysMgr.sysInstance = self
        if onlyInstance:
            return
        if not SysMgr.isLinux:
            return

        # save system info first #
        self.saveSysStat(False)

    def __del__(self):
        pass

    @staticmethod
    def writeErr(fd, log):
        LogMgr.lock(fd)

        try:
            fd.write(log)
        except SystemExit:
            sys.exit(0)
        except:
            return

        LogMgr.unlock(fd)

    @staticmethod
    def setErrorLogger():
        if SysMgr.isLinux:
            sys.stderr = LogMgr()

    @staticmethod
    def getMaxPid():
        path = "%s/sys/kernel/pid_max" % SysMgr.procPath
        try:
            with open(path, "r") as fd:
                maxPid = fd.readline()[:-1]

                # update pid length #
                if len(maxPid) > SysMgr.pidDigit:
                    SysMgr.pidDigit = len(maxPid)

                SysMgr.maxPid = long(maxPid)
        except SystemExit:
            sys.exit(0)
        except:
            pass

    @staticmethod
    def waitForResource(cpuRes=-1, cpuCond="MORE", memRes=-1, memCond="MORE"):
        # check condition #
        if cpuRes >= 0:
            SysMgr.printInfo(
                "wait for system CPU usage %s than %s%%"
                % (cpuCond, UtilMgr.convNum(cpuRes))
            )
        elif memRes >= 0:
            SysMgr.printInfo(
                ("wait for system available memory %s than %s MB")
                % (memCond, UtilMgr.convNum(memRes))
            )
        else:
            return False

        # convert condition #
        if cpuCond:
            cpuCond = cpuCond.upper()
        if memCond:
            memCond = memCond.upper()

        # init variables #
        dobj = Debugger(SysMgr.pid, attach=False)
        dobj.initValues()

        while 1:
            if cpuRes >= 0:
                cpuStat = dobj.getCpuUsage(system=True)
                if cpuStat and cpuStat[3]:
                    cpuUsage = 100 - (cpuStat[3] / SysMgr.uptimeDiff)
                    SysMgr.cpuUsage = cpuUsage
                    if cpuCond == "MORE" and cpuUsage >= cpuRes:
                        return True
                    elif cpuCond == "LESS" and cpuUsage <= cpuRes:
                        return True

            if memRes >= 0:
                memAvail = SysMgr.getAvailMemInfo(retstr=False)
                if memAvail:
                    SysMgr.memAvail = memAvail = memAvail >> 20
                    if memCond == "MORE" and memAvail >= memRes:
                        return True
                    elif memCond == "LESS" and memAvail <= memRes:
                        return True

            time.sleep(1)
            SysMgr.updateUptime()

    @staticmethod
    def loadLibcObj(exit=False):
        if not SysMgr.isLinux:
            return False
        elif SysMgr.libcObj:
            return True

        try:
            ret = SysMgr.loadLib(SysMgr.libcPath)
            if ret:
                SysMgr.libcObj = ret
                return True
            else:
                SysMgr.printErr("failed to load libc")
                if exit:
                    sys.exit(-1)
                else:
                    return False
        except SystemExit:
            sys.exit(0)
        except:
            return False

    @staticmethod
    def shrinkHeap():
        if not SysMgr.isLinux:
            return

        # load libc #
        if not SysMgr.loadLibcObj():
            return

        # check malloc_trim #
        if not hasattr(SysMgr.libcObj, "malloc_trim"):
            SysMgr.printWarn("no malloc_trim in %s" % SysMgr.libcPath)
            return

        # check env #
        if "NOSHRINK" in SysMgr.environList:
            return

        # int malloc_trim (size_t pad) #
        SysMgr.libcObj.malloc_trim(0)

    @staticmethod
    def doLogMode(mode):
        if mode.upper() == "KMSG":
            func = LogMgr.doLogKmsg
            mtype = "kernel"
        elif mode.upper() == "DLT":
            func = DltAnalyzer.doLogDlt
            mtype = "DLT"
        elif mode.upper() == "JOURNAL":
            func = LogMgr.doLogJournal
            mtype = "journal"
        elif mode.upper() == "SYSLOG":
            func = LogMgr.doLogSyslog
            mtype = "syslog"

        SysMgr.printLogo(big=True, onlyFile=True)

        # get message #
        if SysMgr.hasMainArg():
            msg = SysMgr.getMainArg()
        elif SysMgr.inputParam:
            msg = SysMgr.inputParam
        else:
            SysMgr.printErr("no input message for %s" % mtype)
            sys.exit(-1)

        # set alarm #
        if SysMgr.intervalEnable:
            cnt = SysMgr.intervalEnable
        else:
            cnt = 1

        for idx in xrange(cnt):
            ret = func(msg=msg)
            if ret == 0:
                SysMgr.printInfo(
                    "logged a %s message '%s' successfully" % (mtype, msg)
                )
            else:
                SysMgr.printErr("failed to log a %s message" % mtype)
                break

    @staticmethod
    def getPidList():
        try:
            if SysMgr.isLinux:
                pids = os.listdir(SysMgr.procPath)
            else:
                pids = list(map(str, SysMgr.getPkg("psutil").pids()))
            return pids
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenErr(SysMgr.procPath)
            return []

    @staticmethod
    def killProcGroup(procObj, sig=None):
        try:
            if not sig:
                sig = signal.SIGINT

            pgrp = os.getpgid(procObj.pid)
            os.killpg(pgrp, signal.SIGINT)
        except SystemExit:
            sys.exit(0)
        except:
            pass

    @staticmethod
    def getNrSysFdHandle():
        try:
            with open("%s/sys/fs/file-nr" % SysMgr.procPath) as fd:
                stats = list(map(long, fd.readline()[:-1].split()))
                """
                0: the total allocated file handles
                1: the number of currently used file handles (kernel 2.4)
                2: the maximum file handles that can be allocated
                """
                return stats
        except SystemExit:
            sys.exit(0)
        except:
            return None

    @staticmethod
    def setMaxFd():
        if not SysMgr.isLinux:
            return

        # define resource and value #
        rtype = "RLIMIT_NOFILE"
        slim = 1048576
        hlim = 1048576

        # try to change maximum open file #
        try:
            ret = SysMgr.chRlimit(os.getpid(), rtype, slim, hlim)
            if not ret:
                raise Exception("N/A")

            # update the number of maximum open file #
            SysMgr.maxFd = ret[0]
            SysMgr.maxKeepFd = SysMgr.maxFd - 16
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn(
                "failed to get the maximum file descriptor", reason=True
            )

    @staticmethod
    def setReportAttr():
        # get argument #
        if SysMgr.hasMainArg():
            SysMgr.inputFile = SysMgr.getMainArg()
        elif SysMgr.inputParam:
            SysMgr.inputFile = SysMgr.inputParam
        else:
            SysMgr.inputFile = "guider.dat"

        if not SysMgr.outPath:
            SysMgr.outPath = "%s.out" % os.path.splitext(SysMgr.inputFile)[0]

    @staticmethod
    def execSystemView():
        # parse all options and make output file path #
        SysMgr.parseAnalOption()

        SysMgr.printStat(r"start recording... [ STOP(Ctrl+c), MARK(Ctrl+\) ]")

        # wait for interval #
        if SysMgr.repeatInterval > 0:
            try:
                time.sleep(SysMgr.repeatInterval)
            except:
                pass
        # wait for user input #
        else:
            SysMgr.waitEvent()

        # save system info #
        SysMgr.saveSysStats()

        # get and remove process tree from data file #
        SysMgr.getProcTreeInfo()

        SysMgr.printLogo(big=True)

        # print system information #
        SysMgr.printInfoBuffer()

    @staticmethod
    def getVmstat(retDict=False):
        # read vmstat buf #
        vmBuf = SysMgr.readProcStat(
            SysMgr.vmstatFd, "vmstat", SysMgr, "vmstatFd"
        )
        if not vmBuf:
            return vmBuf

        # convert list to dictionary #
        if retDict:
            newDict = {}

            for line in vmBuf:
                try:
                    item = line.strip().split()
                    newDict.setdefault(item[0], long(item[1]))
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

            return newDict

        return vmBuf

    @staticmethod
    def setRecordAttr():
        # iorec #
        if SysMgr.checkMode("iorec"):
            SysMgr.blockEnable = True
            SysMgr.cpuEnable = False

        # function #
        elif SysMgr.checkMode("funcrec"):
            SysMgr.functionEnable = True

        # syscall #
        elif SysMgr.checkMode("sysrec"):
            SysMgr.sysEnable = True
            SysMgr.cpuEnable = False

        # file #
        elif SysMgr.checkMode("filerec"):
            SysMgr.fileEnable = True

        # general #
        elif SysMgr.checkMode("genrec"):
            SysMgr.systemEnable = True

        # update record status #
        SysMgr.inputFile = "/sys/kernel/debug/tracing/trace"

        SysMgr.parseRecordOption()

        # change the CPU scheduling priority for process #
        if SysMgr.prio is None:
            SysMgr.setPriority(SysMgr.pid, "C", -20)

        SysMgr.printProfileOption()
        SysMgr.printProfileCmd()

    @staticmethod
    def removeFd(fname):
        SysMgr.fdCache.pop(fname, None)

    @staticmethod
    def getFd(fname, perm="rb", verb=True):
        if fname in SysMgr.fdCache and SysMgr.fdCache[fname]["perm"] == perm:
            return SysMgr.fdCache[fname]["fd"]

        try:
            SysMgr.fdCache[fname] = {"fd": open(fname, perm), "perm": perm}
            return SysMgr.fdCache[fname]["fd"]
        except SystemExit:
            sys.exit(0)
        except:
            if verb:
                SysMgr.printOpenErr(fname)
            return None

    @staticmethod
    def setVisualAttr():
        # set default input path #
        if len(sys.argv) <= 2:
            sys.argv.insert(2, SysMgr.outFilePath)

        SysMgr.graphEnable = True

        # ignore user warning #
        SysMgr.ignoreWarn()

        # apply regular expression for first path #
        flist = UtilMgr.convPath(sys.argv[2])
        flist = UtilMgr.getFileList(flist, exceptDir=True)
        if type(flist) is list and len(flist) > 0:
            sys.argv = sys.argv[:2] + flist + sys.argv[3:]

        # thread draw mode #
        if TaskAnalyzer.getInitTime(sys.argv[2]) > 0:
            # apply launch option #
            SysMgr.applyLaunchOption()

            # check data type #
            if SysMgr.isFuncMode():
                SysMgr.printErr(
                    "failed to draw because this data is for function"
                )
                sys.exit(-1)
            elif (
                SysMgr.isThreadMode()
                or not SysMgr.systemInfoBuffer
                or SysMgr.forceEnable
            ):
                pass
            else:
                SysMgr.printErr(
                    "failed to draw because this data is not supported"
                )
                sys.exit(-1)

            # set input path #
            SysMgr.inputFile = sys.argv[1] = sys.argv[2]
            SysMgr.intervalEnable = 1
            if not SysMgr.outPath:
                SysMgr.outPath = (
                    "%s.out" % os.path.splitext(SysMgr.inputFile)[0]
                )
            del sys.argv[2]
        # top draw mode #
        else:
            # CPU #
            if SysMgr.checkMode("drawcpu") or SysMgr.checkMode("drawcpuavg"):
                SysMgr.layout = "CPU"
            # delay #
            elif SysMgr.checkMode("drawdelay"):
                SysMgr.layout = "DELAY"
            # memory #
            elif SysMgr.checkMode("drawmem") or SysMgr.checkMode("drawmemavg"):
                SysMgr.layout = "MEM"
            # VSS #
            elif SysMgr.checkMode("drawvss") or SysMgr.checkMode("drawvssavg"):
                SysMgr.layout = "MEM"
                SysMgr.vssEnable = True
            # RSS #
            elif SysMgr.checkMode("drawrss") or SysMgr.checkMode("drawrssavg"):
                SysMgr.layout = "MEM"
                SysMgr.rssEnable = True
            # leak #
            elif SysMgr.checkMode("drawleak"):
                SysMgr.layout = "MEM"
                SysMgr.leakEnable = True
            # I/O #
            elif SysMgr.checkMode("drawio"):
                SysMgr.layout = "IO"

            # average #
            if SysMgr.isDrawAvgMode():
                SysMgr.avgEnable = True

            # modify args for drawing multiple input files #
            sys.argv[1] = "top"
            args = sys.argv[2:]
            SysMgr.inputParam = UtilMgr.getFileList(args)

    @staticmethod
    def execFileAnalysis():
        SysMgr.checkRootPerm()

        # parse analysis option #
        SysMgr.parseAnalOption()

        SysMgr.printStat(r"start analyzing... [ STOP(Ctrl+c), MARK(Ctrl+\) ]")

        # start analyzing files #
        try:
            pi = FileAnalyzer()
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to analyze memory-mapped files", reason=True
            )
            sys.exit(-1)

        # save system info #
        SysMgr.saveSysStats()

        # get and remove process tree from data file #
        SysMgr.getProcTreeInfo()

        if SysMgr.intervalEnable == 0:
            # print total file usage per process #
            pi.printUsage()
        else:
            # print file usage per process on timeline #
            pi.printIntervalInfo()

    @staticmethod
    def execRecordLoop():
        skipWait = False

        while SysMgr.repeatInterval > 0:
            # set alarm #
            signal.alarm(SysMgr.repeatInterval)

            # get init time in buffer for verification #
            if SysMgr.graphEnable:
                skipWait = True
                initTime = 0
            else:
                initTime = TaskAnalyzer.getInitTime(SysMgr.inputFile)

            # wait for timer #
            try:
                for cnt in xrange(SysMgr.repeatInterval):
                    UtilMgr.printProgress(cnt, SysMgr.repeatInterval)
                    time.sleep(1)
            except SystemExit:
                sys.exit(0)
            except:
                pass

            # real-time copy from pipe to file #
            if SysMgr.pipeEnable:
                if SysMgr.outputFile:
                    # backup #
                    SysMgr.backupFile(SysMgr.outputFile)

                    # copy #
                    SysMgr.copyPipeToFile(
                        "%s%s" % (SysMgr.inputFile, "_pipe"), SysMgr.outputFile
                    )
                else:
                    SysMgr.printErr(
                        "wrong option used, use also -s option to save data"
                    )
                sys.exit(-1)

            # check counter #
            if SysMgr.repeatCount <= SysMgr.progressCnt and SysMgr.termFlag:
                # check exit condition #
                if SysMgr.graphEnable:
                    break

                SysMgr.printWarn("terminated by timer\n", True)
                sys.exit(-1)

            # compare init time with now time for buffer verification #
            if 0 < initTime < TaskAnalyzer.getInitTime(SysMgr.inputFile):
                SysMgr.printErr(
                    "buffer size is not enough (%sKB)" % SysMgr.getBufferSize()
                )
                sys.exit(-1)
            else:
                SysMgr.clearTraceBuffer()

        # start writing logs to file through pipe #
        if SysMgr.pipeEnable:
            if SysMgr.outputFile:
                pipePath = "%s%s" % (SysMgr.inputFile, "_pipe")
                SysMgr.copyPipeToFile(pipePath, SysMgr.outputFile)
            else:
                SysMgr.printErr(
                    "wrong option used, use also -s option to save data"
                )
            sys.exit(-1)

        if not SysMgr.graphEnable:
            # get init time from buffer for verification #
            initTime = TaskAnalyzer.getInitTime(SysMgr.inputFile)

        # wait for user input #
        while 1:
            if skipWait:
                break
            elif SysMgr.recordStatus:
                SysMgr.condExit = True

                SysMgr.waitEvent()
                if SysMgr.condExit:
                    break
            else:
                break

        # FUNCTION GRAPH MODE #
        if SysMgr.graphEnable:
            if not SysMgr.outputFile:
                SysMgr.stopRecording()

                # read trace data #
                data = SysMgr.readFile(SysMgr.inputFile)

                # parse options #
                SysMgr.parseAnalOption()

                # apply core filter #
                if SysMgr.perCoreList:
                    data = data.split("\n")
                    data = SysMgr.applyCoreFilter(data)
                    data = "\n".join(data)

                # print trace data #
                SysMgr.printPipe(data)

                sys.exit(0)
            elif SysMgr.repeatInterval:
                sys.exit(0)
        # THREAD & FUNCTION MODE #
        else:
            # compare init time with now time for buffer verification #
            if initTime < TaskAnalyzer.getInitTime(SysMgr.inputFile):
                SysMgr.printErr(
                    "buffer size %sKB is not enough" % SysMgr.getBufferSize()
                )
                sys.exit(-1)

            # save system info #
            SysMgr.saveSysStats()

    @staticmethod
    def applyCoreFilter(lines):
        newList = []
        filterList = set(map(str, SysMgr.perCoreList))

        for line in lines:
            m = re.match(r"^\s*(?P<time>.+) \|\s*(?P<core>[0-9]+)\)", line)
            if not m:
                newList.append(line)
                continue

            # check core number #
            d = m.groupdict()
            if d["core"] in filterList:
                newList.append(line)

        return newList

    @staticmethod
    def getGpuMem():
        if SysMgr.gpuMemGetters is None:
            SysMgr.gpuMemGetters = [
                SysMgr.getNvGpuMem,  # nvidia #
                SysMgr.getMaliGpuMem,  # mali #
            ]

        res = {}
        removeList = []
        getters = SysMgr.gpuMemGetters

        for func in getters:  # pylint: disable=not-an-iterable
            ret = func()
            if ret:
                # merge size #
                for item in ret:
                    if item in res:
                        res[item]["size"] += ret[item]["size"]
                    else:
                        res[item] = ret[item]
            else:
                removeList.append(func)

        # remove invalid getters #
        if removeList:
            SysMgr.gpuMemGetters = list(set(getters) - set(removeList))

        return res

    @staticmethod
    def getMaliGpuMem():
        # read Mali GPU memory info #
        try:
            path = "/sys/kernel/debug/mali/gpu_memory"
            if not os.path.exists(path):
                return

            with open(path, "rb") as fd:
                gpuInfo = fd.readlines()[2:]
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenWarn(path)
            return

        gpuStat = {}

        # parse per-process memory info #
        for item in gpuInfo:
            try:
                line = item.decode().split()

                if line[0] == "Mali":
                    if line[2] == "usage":
                        pid = "0"
                        comm = "TOTAL"
                        size = line[3]
                    else:
                        continue
                else:
                    comm, pid, mali, malimax, extern, ump, dma = line
            except SystemExit:
                sys.exit(0)
            except:
                continue

            # save stat #
            gpuStat.setdefault(pid, {"comm": comm, "size": long(mali)})

        return gpuStat

    @staticmethod
    def getNvGpuMem():
        # read NVIDIA GPU memory info #
        try:
            path = "/sys/kernel/debug/nvmap/iovmm/clients"
            if not os.path.exists(path):
                return

            with open(path, "rb") as fd:
                gpuInfo = fd.readlines()[1:]
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenWarn(path)
            return

        gpuStat = {}

        # parse per-process memory info #
        for item in gpuInfo:
            try:
                line = item.decode().split()
                if line[0] == "total":
                    pid = "0"
                    comm = "TOTAL"
                    size = line[1]
                else:
                    comm, pid, size = line[1:]
            except SystemExit:
                sys.exit(0)
            except:
                continue

            # convert size to number #
            size = UtilMgr.convUnit2Size(size)

            # save stat #
            gpuStat.setdefault(pid, {"comm": comm, "size": size})

        return gpuStat

    @staticmethod
    def execSshCmd(cmd, addr, port=22, user="root", passwd=None):
        # get subprocess object #
        subprocess = SysMgr.getPkg("subprocess")

        # get environment variables #
        env = SysMgr.getEnvList()

        cmdList = []

        if passwd:
            # get sshpass path #
            sshpassPath = UtilMgr.which("sshpass")
            if not sshpassPath:
                SysMgr.printErr("failed to get sshpass path")
                sys.exit(-1)
            sshpassPath = sshpassPath[0]

            # add sshpass command #
            cmdList += [sshpassPath, "-p", passwd]

        # get ssh path #
        sshPath = UtilMgr.which("ssh")
        if not sshPath:
            SysMgr.printErr("failed to get ssh path")
            sys.exit(-1)
        sshPath = sshPath[0]

        # set option #
        opt = "-oStrictHostKeyChecking=no"

        # add ssh command #
        cmdList += [sshPath, opt, "-p", str(port), "%s@%s" % (user, addr), cmd]

        # save start time #
        startTime = time.time()

        # create process to communicate #
        procObj = subprocess.Popen(
            cmdList,
            stdout=subprocess.PIPE,
            stdin=subprocess.PIPE,
            stderr=subprocess.PIPE,
            universal_newlines=True,
            bufsize=0,
            env=env,
        )

        # run mainloop #
        try:
            select = SysMgr.getPkg("select")
            while 1:
                res = select.select(
                    [procObj.stdout, procObj.stderr], [], [], 1
                )
                if not res[0]:
                    continue
                for item in res[0]:
                    val = item.read()
                    if val:
                        print(val)
                    else:
                        raise Exception()
        except SystemExit:
            sys.exit(0)
        except:
            pass
        finally:
            duration = time.time() - startTime

        # kill subprocess group #
        SysMgr.killProcGroup(procObj)

        SysMgr.printInfo("elapsed %.6f for '%s'" % (duration, cmd))

        sys.exit(0)

    @staticmethod
    def execTopCmd():
        # check background processes #
        if not "FASTINIT" in SysMgr.environList and not SysMgr.isDrawMode():
            SysMgr.checkBgProcs()

        # write user command #
        SysMgr.runProfCmd("BEFORE")

        # set signal handler #
        if SysMgr.isDrawMode():
            SysMgr.setDefaultSignal()
        # print profile option #
        else:
            SysMgr.printProfileOption()
            SysMgr.printProfileCmd()

            # set handler for exit #
            SysMgr.setNormalSignal()

        # thread #
        if SysMgr.checkMode("ttop"):
            SysMgr.processEnable = False

        # file #
        elif SysMgr.checkMode("ftop"):
            SysMgr.fileTopEnable = True

        # stack #
        elif SysMgr.checkMode("stacktop"):
            if SysMgr.checkStackTopCond():
                SysMgr.processEnable = False
                SysMgr.stackEnable = True
            else:
                sys.exit(-1)

        # perf #
        elif SysMgr.checkMode("ptop"):
            if SysMgr.checkPerfTopCond():
                SysMgr.perfEnable = True
                if SysMgr.findOption("g"):
                    SysMgr.processEnable = False
                    SysMgr.perfGroupEnable = True
            else:
                sys.exit(-1)

        # mem #
        elif SysMgr.checkMode("mtop"):
            if SysMgr.checkMemTopCond():
                SysMgr.memEnable = True
                SysMgr.sort = "m"
            else:
                sys.exit(-1)

        # WSS (Working Set Size) #
        elif SysMgr.checkMode("wtop"):
            if SysMgr.checkWssTopCond():
                SysMgr.memEnable = True
                SysMgr.wssEnable = True
                SysMgr.sort = "m"
            else:
                sys.exit(-1)

        # disk #
        elif SysMgr.checkMode("disktop"):
            if SysMgr.checkDiskTopCond():
                SysMgr.diskEnable = True
                SysMgr.blockEnable = True
                SysMgr.sort = "b"
            else:
                sys.exit(-1)

        # all #
        elif SysMgr.checkMode("atop"):
            SysMgr.cpuEnable = True
            SysMgr.memEnable = True
            SysMgr.irqEnable = True
            SysMgr.diskEnable = True
            SysMgr.networkEnable = True

            if SysMgr.isRoot():
                SysMgr.blockEnable = True
                SysMgr.perfEnable = True
            else:
                SysMgr.printWarn(
                    "block stat is disabled because of no root permission"
                )

        # condition #
        elif SysMgr.checkMode("ctop"):
            # check config file #
            if not SysMgr.getOption("C"):
                # search config file #
                SysMgr.updateConfigPath()

            # load config file #
            if ConfigMgr.confData:
                pass
            elif not SysMgr.loadConfig(SysMgr.confFileName):
                sys.exit(-1)

            # ignore output #
            if not SysMgr.outPath:
                if SysMgr.isWindows:
                    SysMgr.outPath = "NUL"
                else:
                    SysMgr.outPath = SysMgr.nullPath

            # get output dir #
            if SysMgr.outPath == SysMgr.nullPath:
                targetDir = SysMgr.tmpPath
            elif os.path.isdir(SysMgr.outPath):
                targetDir = SysMgr.outPath
            else:
                targetDir = os.path.dirname(SysMgr.outPath)

            # remove SIGINT handler to ignore creating the report file #
            signal.signal(signal.SIGINT, SysMgr.exitHandler)

            # update run number #
            if not SysMgr.nrRun:
                try:
                    SysMgr.updateNrRun(targetDir)
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(
                        "failed to update sequence number of execution", True
                    )

            # set buffer strip #
            SysMgr.bufferLossEnable = True

            # set threshold handle flag #
            SysMgr.thresholdEnable = True

            # disable color and encoding #
            SysMgr.colorEnable = False
            SysMgr.encodeEnable = False

        # DLT #
        elif SysMgr.checkMode("dlttop"):
            SysMgr.dltTopEnable = True

        # D-Bus #
        elif SysMgr.checkMode("dbustop"):
            SysMgr.dbusTopEnable = True
            SysMgr.floatEnable = True

            # set default interval to 3 for performance #
            if not SysMgr.findOption("i") and not SysMgr.findOption("R"):
                SysMgr.intervalEnable = 3

        # usercall #
        elif SysMgr.checkMode("utop"):
            SysMgr.doTrace("usercall")

        # pycall #
        elif SysMgr.checkMode("pytop"):
            SysMgr.doTrace("pycall")

        # breakcall #
        elif SysMgr.checkMode("btop"):
            SysMgr.doTrace("breakcall")

        # syscall #
        elif SysMgr.checkMode("systop"):
            SysMgr.doTrace("syscall")

        # kernelcall #
        elif SysMgr.checkMode("ktop"):
            SysMgr.doTrace("kernel")

        # network #
        elif SysMgr.checkMode("ntop"):
            SysMgr.networkEnable = True

        # background #
        elif SysMgr.checkMode("bgtop"):
            # check condition #
            if not SysMgr.checkBgTopCond():
                sys.exit(-1)

            # check permission #
            if SysMgr.isRoot():
                SysMgr.blockEnable = True
            else:
                SysMgr.printWarn(
                    "block stat is disabled because of no root permission"
                )

            SysMgr.diskEnable = True
            SysMgr.networkEnable = True

            SysMgr.runBackgroundMode()

        # report #
        elif SysMgr.checkMode("rtop"):
            SysMgr.jsonEnable = True

            # check root permission #
            if SysMgr.isRoot():
                SysMgr.diskEnable = True
                SysMgr.networkEnable = True

                # disable resources by option #
                disableList = SysMgr.getOption("d")
                if disableList:
                    if "d" in disableList:
                        SysMgr.diskEnable = False
                    if "n" in disableList:
                        SysMgr.networkEnable = False
            else:
                SysMgr.printWarn(
                    "failed to get stats for disk and network "
                    "because of no root permission"
                )

            # check command requirement #
            if not SysMgr.checkRepTopCond():
                sys.exit(-1)

        # init network resource data #
        if SysMgr.networkEnable and not SysMgr.sysInstance.networkInfo:
            SysMgr.sysInstance.updateNetworkInfo()

        # init disk resource data #
        if SysMgr.diskEnable and not SysMgr.sysInstance.storageData:
            SysMgr.sysInstance.updateStorageInfo()

        # run process / file monitoring #
        TaskAnalyzer()

    @staticmethod
    def loadLibCache():
        try:
            if not os.path.exists(SysMgr.ldCachePath):
                raise Exception("no %s" % SysMgr.ldCachePath)

            libDict = {}

            # load libs from cache #
            libList = UtilMgr.convBin2Str(SysMgr.ldCachePath)
            for idx, item in enumerate(libList):
                try:
                    if libList[idx + 1].startswith("/"):
                        value = libList[idx + 1]
                        libDict.setdefault(item, [])
                        libDict[item].append(value)
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

            # load libs form /usr/local/lib #
            for path in ["/usr/local/lib", "/usr/local/lib64"]:
                if not os.path.exists(path):
                    continue

                for item in os.listdir(path):
                    if not ".so" in item:
                        continue

                    value = os.path.join(path, item)

                    libDict.setdefault(item, [])
                    libDict[item].append(value)

            # save lib list #
            SysMgr.libCache = libDict
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("failed to load library cache", reason=True)
            return False

    @staticmethod
    def findLib(lib, inc=False):
        if not SysMgr.libCache:
            SysMgr.loadLibCache()

        for key, val in SysMgr.libCache.items():
            # convert for specific caches are only consist of absolute paths #
            if key.startswith("/"):
                val = [key]
                key = os.path.basename(key)

            # check path #
            if key == lib:
                pass
            elif not key.startswith(lib):
                continue
            elif inc and key.startswith(lib):
                pass
            elif len(key) <= len(lib):
                continue
            elif key[len(lib)] == "." or key[len(lib)] == "-":
                pass
            else:
                continue

            # return found values #
            if len(val) > 1:
                SysMgr.printWarn(
                    "multiple libraries [ %s ] exist for %s"
                    % (", ".join(val), key)
                )

            return val

        return None

    @staticmethod
    def getPrintFlag():
        if "QUIET" in SysMgr.environList:
            return False
        else:
            return True

    @staticmethod
    def loadLib(lib, path=False, inc=False):
        if not SysMgr.importPkgItems("ctypes", False):
            return

        # absolute path #
        if path:
            return CDLL(lib)

        # search ld.so.cache #
        target = SysMgr.findLib(lib, inc)
        if not target:
            target = ["%s.so" % lib]
            ret = FileAnalyzer.getMapFilePath(SysMgr.pid, lib)
            if ret:
                target.append(ret)

        # load libraries #
        for item in target:
            try:
                res = cdll.LoadLibrary(item)
                if res:
                    return res
            except SystemExit:
                sys.exit(0)
            except:
                pass

    @staticmethod
    def importNative():
        try:
            # do not use native library to improve initialization time #
            raise Exception

            import guider

            guider.check()  # pylint: disable=no-member
            SysMgr.guiderObj = guider
        except:
            pass

    @staticmethod
    def applyKillVal(value):
        if not value:
            SysMgr.printErr("no value to send signal")
            sys.exit(-1)

        SysMgr.checkRootPerm()

        jobs = value.split(",")
        for job in jobs:
            try:
                value = job.split(":")

                if len(value) > 3:
                    raise Exception("wrong input")

                # set task #
                tid = value[0]

                # set signal #
                if len(value) == 1:
                    sig = signal.SIGKILL
                else:
                    sig = SysMgr.getSigNum(value[1])
                    if not sig:
                        raise Exception("wrong signal %s" % value[1])

                if len(value) > 2 and value[2].upper() == "CONT":
                    flag = "CONT"
                else:
                    flag = "ONCE"

                SysMgr.killFilter.append([tid, sig, flag])
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("failed to set signal", True)
                sys.exit(-1)

    @staticmethod
    def parseAffinityOption(jobs, launch=False):
        if not jobs:
            SysMgr.printErr("wrong option value")
            sys.exit(-1)

        doneList = set()
        for origVal in jobs:
            try:
                value = origVal.split(":")

                if len(value) < 2 or len(value) > 3:
                    raise Exception("wrong input")

                # set task #
                tid = value[0]
                if tid == "":
                    tid = str(SysMgr.pid)

                # set mask #
                mask = value[1]
                if not mask:
                    raise Exception("wrong input")

                if launch:
                    sibling = SysMgr.groupProcEnable
                    targetList = SysMgr.getTids(tid, sibling=sibling)
                    targetList = list(map(long, targetList))
                    targetList = list(set(targetList) - doneList)
                    if targetList:
                        SysMgr.setAffinity(mask, targetList)
                        doneList = set(list(doneList) + targetList)
                    elif doneList:
                        pass
                    else:
                        SysMgr.printWarn("no thread related to '%s'" % tid)

                if len(value) == 3 and value[2].upper() == "CONT":
                    flag = "CONT"
                else:
                    flag = "ONCE"

                SysMgr.affinityFilter.append([tid, mask, flag])
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("wrong option value '%s'" % origVal, True)
                sys.exit(-1)

    @staticmethod
    def doDump():
        # get argument #
        if SysMgr.hasMainArg():
            inputParam = SysMgr.getMainArgs()
        elif SysMgr.filterGroup:
            inputParam = SysMgr.filterGroup
        else:
            SysMgr.printErr("no input for COMM or PID")
            sys.exit(-1)

        # check condition #
        if not inputParam:
            SysMgr.printErr("no input for COMM or PID")
            sys.exit(-1)
        elif not SysMgr.outPath:
            SysMgr.printErr("no output path")
            sys.exit(-1)
        elif not SysMgr.inputParam:
            SysMgr.printErr("no input for memory area")
            sys.exit(-1)

        # convert comm to pid #
        targetList = []
        for item in inputParam:
            targetList += SysMgr.getTids(item, isThread=False)
        targetList = list(set(targetList))

        # check target #
        if not targetList:
            SysMgr.printErr("no target process")
            sys.exit(-1)
        elif len(targetList) > 1:
            SysMgr.printErr(
                "found multiple tasks [%s]" % SysMgr.getCommList(targetList)
            )
            sys.exit(-1)

        # set args #
        pid = targetList[0]
        meminfo = SysMgr.inputParam
        output = SysMgr.outPath
        if os.path.isdir(output):
            output = "%s/dump.out" % output

        # dump memory #
        Debugger.dumpTaskMemory(pid, meminfo, output)

    @staticmethod
    def readProcStat(fd, name, obj, attr, err=False, retry=True):
        try:
            buf = None
            while 1:
                fd.seek(0)
                buf = fd.readlines()
                # retry to read for shared descriptor #
                if buf or not retry:
                    break
        except SystemExit:
            sys.exit(0)
        except:
            try:
                bufPath = "%s/%s" % (SysMgr.procPath, name)
                fd = open(bufPath, "r")
                setattr(obj, attr, fd)
                buf = fd.readlines()
            except SystemExit:
                sys.exit(0)
            except:
                if err:
                    SysMgr.printOpenErr(bufPath)
                else:
                    SysMgr.printOpenWarn(bufPath)
        return buf

    @staticmethod
    def getNrFd(pid):
        # get the number of fds #
        try:
            path = "%s/%s/fd" % (SysMgr.procPath, pid)
            return len(os.listdir(path))
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenWarn(path)
            return 0

    @staticmethod
    def getIdleMap():
        try:
            with open("/sys/kernel/mm/page_idle/bitmap", "rb") as fd:
                return fd.read(8888888)
        except SystemExit:
            sys.exit(0)
        except:
            return None

    @staticmethod
    def handleIdlePage(pfn, write=True, flush=True, bitmap=None):
        try:
            # check pfn 0 #
            if not pfn:
                return None

            # set permission #
            if write:
                perm = "wb"
            else:
                perm = "rb"

            # get fd #
            fd = SysMgr.getFd("/sys/kernel/mm/page_idle/bitmap", perm)
            if not fd:
                sys.exit(-1)

            # define size #
            word = 8
            bit = word * 8

            # set pos #
            offset = long(pfn / bit) * word
            if not bitmap:
                fd.seek(offset, 0)

            # handle operation #
            if write:
                val = fd.write(struct.pack("Q", 2**bit - 1))
                if flush:
                    fd.flush()
                return val
            else:
                if bitmap:
                    val = bitmap[offset : offset + 8]
                else:
                    val = fd.read(word)

                val = struct.unpack("Q", val)[0]
                if val & 1 << (pfn % 64):
                    return True
                else:
                    return False
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn(
                "failed to mark idle page (PFN: %s)" % hex(pfn), reason=True
            )
            return None

    @staticmethod
    def clearPageRefs(pid, val):
        """
        The /proc/PID/clear_refs is used to reset the PG_Referenced and ACCESSED/YOUNG
        bits on both physical and virtual pages associated with a process, and the
        soft-dirty bit on pte (see Documentation/admin-guide/mm/soft-dirty.rst
        for details).

        To clear the bits for all the pages associated with the process
            > echo 1 > /proc/PID/clear_refs

        To clear the bits for the anonymous pages associated with the process
            > echo 2 > /proc/PID/clear_refs

        To clear the bits for the file mapped pages associated with the process
            > echo 3 > /proc/PID/clear_refs

        To clear the soft-dirty bit
            > echo 4 > /proc/PID/clear_refs

        To reset the peak resident set size ("high water mark") to the process's
        current value:
            > echo 5 > /proc/PID/clear_refs

        Any other value written to /proc/PID/clear_refs will have no effect.
        """

        try:
            path = "%s/%s/clear_refs" % (SysMgr.procPath, pid)
            with open(path, "w") as fd:
                fd.write(val)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to write '%s' to %s" % (val, path), True)

    @staticmethod
    def doMount(args=None):
        # get argument #
        if args:
            value = args
        elif SysMgr.hasMainArg():
            value = SysMgr.getMainArgs(False, ":")
        elif SysMgr.inputParam:
            value = SysMgr.inputParam
        else:
            SysMgr.printErr(
                (
                    "wrong value to mount filesystem, "
                    "input in the format DEV:DIR:FS:FLAGS:DATA"
                )
            )
            sys.exit(-1)

        # backup input value #
        origVal = deepcopy(value)

        # mount a filesystem #
        try:
            # convert flags #
            flags = 0
            if len(value) >= 4:
                for item in value[3].split(","):
                    try:
                        name = "MS_%s" % item.upper()
                        flags |= ConfigMgr.MOUNT_TYPE[name]
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass

                # update flags #
                value[3] = flags

            # get flags #
            if flags > 0:
                flagStr = "|".join(
                    UtilMgr.getFlagList(flags, ConfigMgr.MOUNT_TYPE)
                )
                flagStr = " with %s" % flagStr
            else:
                flagStr = ""

            # mount #
            ret = SysMgr.mount(*value)
            if ret == 0:
                SysMgr.printInfo(
                    "mounted %s on '%s' to '%s'%s successfully"
                    % (
                        value[2],
                        os.path.realpath(value[0]),
                        os.path.realpath(value[1]),
                        flagStr,
                    )
                )
            else:
                errReason = SysMgr.getErrReason()
                SysMgr.printErr(
                    "failed to mount '%s' because %s"
                    % (":".join(origVal), errReason)
                )
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to mount '%s'" % ":".join(origVal), True)

    @staticmethod
    def doUnmount(args=None):
        # get argument #
        if args:
            value = args
        elif SysMgr.hasMainArg():
            value = SysMgr.getMainArgs(False, ":")
        elif SysMgr.inputParam:
            value = SysMgr.inputParam
        else:
            SysMgr.printErr(
                (
                    "wrong value to unmount filesystem, "
                    "input in the format TARGET:FLAGS"
                )
            )
            sys.exit(-1)

        # backup input value #
        origVal = deepcopy(value)

        # mount a filesystem #
        try:
            # convert flags #
            flags = 0
            if len(value) >= 2:
                for item in value[1].split(","):
                    try:
                        name = "MNT_%s" % item.upper()
                        flags |= ConfigMgr.UMOUNT_TYPE[name]
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass

                # update flags #
                value[1] = flags

            # get flags #
            if flags > 0:
                flagStr = "|".join(
                    UtilMgr.getFlagList(flags, ConfigMgr.UMOUNT_TYPE)
                )
                flagStr = " with %s" % flagStr
            else:
                flagStr = ""

            # mount #
            ret = SysMgr.umount(*value)
            if ret == 0:
                SysMgr.printInfo(
                    "unmounted '%s'%s successfully"
                    % (os.path.realpath(value[0]), flagStr)
                )
            else:
                errReason = SysMgr.getErrReason()
                SysMgr.printErr(
                    "failed to unmount '%s' because %s"
                    % (":".join(origVal), errReason)
                )
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to unmount '%s'" % ":".join(origVal), True)

    @staticmethod
    def initLibcorkscrew():
        if "NOLIBCORK" in SysMgr.environList:
            SysMgr.libcorkscrewObj = -1
        elif SysMgr.libcorkscrewObj:
            return
        else:
            SysMgr.libcorkscrewObj = SysMgr.loadLib(SysMgr.libcorkscrewPath)
            if SysMgr.libcorkscrewObj:
                libcc = SysMgr.libcorkscrewObj

                # define load_ptrace_context #
                libcc.load_ptrace_context.argtypes = [c_int]
                libcc.load_ptrace_context.restype = c_void_p

                # define free_ptrace_context #
                libcc.free_ptrace_context.argtypes = [c_void_p]
                libcc.free_ptrace_context.restype = None

                # define unwind_backtrace_ptrace #
                libcc.unwind_backtrace_ptrace.argtypes = [
                    c_int,
                    c_void_p,
                    c_void_p,
                    c_size_t,
                    c_size_t,
                ]
                libcc.unwind_backtrace_ptrace.restype = c_size_t

                # define get_backtrace_symbols_ptrace #
                libcc.get_backtrace_symbols_ptrace.argtypes = [
                    c_void_p,
                    c_void_p,
                    c_size_t,
                    c_void_p,
                ]
                libcc.get_backtrace_symbols_ptrace.restype = None
            else:
                SysMgr.libcorkscrewObj = -1

    @staticmethod
    def doRlimit():
        # get argument #
        if SysMgr.hasMainArg():
            value = SysMgr.getMainArgs()
        elif SysMgr.filterGroup:
            value = SysMgr.filterGroup
        else:
            SysMgr.printErr(
                (
                    "wrong value to change resource limit, "
                    "input in the format TID|COMM:RTYPE:SLIM:HLIM"
                )
            )
            sys.exit(-1)

        for item in value:
            conf = item.split(":")
            if len(conf) != 1 and len(conf) != 4:
                SysMgr.printErr(
                    (
                        "wrong value to change resource limit, "
                        "input in the format TID|COMM:RTYPE:SLIM:HLIM"
                    )
                )
                sys.exit(-1)

            conf = UtilMgr.cleanItem(conf, False)

            # get tasks #
            target = SysMgr.getTids(conf[0])
            if not target:
                SysMgr.printErr("no task related to '%s'" % conf[0])
                sys.exit(-1)

            # get return type #
            if len(conf) == 4:
                rtype = conf[1]
                slim, hlim = list(map(long, conf[2:4]))

            # apply new limits #
            for tid in target:
                # get comm for the task #
                comm = SysMgr.getComm(tid, cache=True)

                if len(conf) == 1:
                    rlist = SysMgr.readProcData(tid, "limits")
                    if rlist:
                        SysMgr.printPipe(
                            "\n[Task Limit Info] [%s(%s)]\n%s\n%s%s"
                            % (comm, tid, twoLine, "".join(rlist), oneLine)
                        )
                    continue

                # change resource limit #
                ret = SysMgr.chRlimit(long(tid), rtype, slim, hlim)
                if ret:
                    SysMgr.printInfo(
                        "changed %s to %s/%s for %s(%s)"
                        % (
                            conf[1],
                            UtilMgr.convNum(ret[0]),
                            UtilMgr.convNum(ret[1]),
                            comm,
                            tid,
                        )
                    )
                else:
                    SysMgr.printErr(
                        "failed to change %s to %s/%s for %s(%s)"
                        % (
                            conf[1],
                            UtilMgr.convNum(slim),
                            UtilMgr.convNum(hlim),
                            comm,
                            tid,
                        )
                    )

    @staticmethod
    def getAvailMemInfo(retstr=True, unit=None):
        try:
            # read memory stats #
            memBuf = SysMgr.getMemInfo()

            # parse lines #
            memData = {}
            for line in memBuf:
                if line.startswith("Buffers"):
                    break

                memList = line.split()
                memData[memList[0][:-1]] = long(memList[1])

            # get available memory #
            if "MemAvailable" in memData:
                sysMemStr = memData["MemAvailable"] << 10
            elif "MemFree" in memData:
                sysMemStr = memData["MemFree"] << 10
            else:
                sysMemStr = 0

            if not retstr:
                return sysMemStr

            sysMemStr = UtilMgr.convSize2Unit(
                sysMemStr, isInt=False, unit=unit
            )
        except SystemExit:
            sys.exit(0)
        except:
            sysMemStr = 0
        finally:
            return sysMemStr

    @staticmethod
    def updateNrRun(path):
        if not path or not os.path.isdir(path):
            SysMgr.printErr(
                (
                    "failed to update sequence number of execution ",
                    "because wrong directory path '%s'",
                )
                % path
            )
            return

        # get the file list sorted by name in the output dir #
        flist = sorted(
            filter(
                lambda x: os.path.isfile(os.path.join(path, x)),
                os.listdir(path),
            ),
            reverse=True,
        )

        # get the number of last execution #
        for fname in flist:
            m = re.match(r"^guider_(?P<run>[0-9]+)_*", fname)
            if not m:
                continue

            # update the execution number #
            d = m.groupdict()
            SysMgr.nrRun = long(d["run"]) + 1
            return

    @staticmethod
    def getMemInfo():
        # return mem buf #
        return SysMgr.readProcStat(
            SysMgr.memFd, "meminfo", SysMgr, "memFd", True
        )

    @staticmethod
    def madvise(addr, length, advise):
        try:
            # load libc #
            ret = SysMgr.loadLibcObj()
            if not ret:
                raise Exception("no library")
        except SystemExit:
            sys.exit(0)
        except:
            sys.exit(-1)

        # prlimit #
        if not hasattr(SysMgr.libcObj, "madvise"):
            SysMgr.printErr("no madvise in libc")
            sys.exit(-1)

        # define prototype #
        SysMgr.libcObj.madvise.argtypes = (POINTER(None), c_size_t, c_int)
        SysMgr.libcObj.madvise.restype = c_int

        return SysMgr.libcObj.madvise(addr, length, advise)

    @staticmethod
    def chRlimit(pid, rtype, slim, hlim):
        rtype = rtype.upper()
        if not rtype in ConfigMgr.RLIMIT_TYPE:
            SysMgr.printErr(
                "failed to change rlimit for %s because wrong resource" % rtype
            )
            return False

        rindex = ConfigMgr.RLIMIT_TYPE.index(rtype)

        # resource package #
        try:
            resource = SysMgr.getPkg("resource", False, True)
            if resource:
                resource.prlimit(pid, rindex, (slim, hlim))
                soft, hard = resource.prlimit(pid, rindex)
                return (soft, hard)
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # get ctypes object #
        if not SysMgr.importPkgItems("ctypes", False):
            return

        class rlimit(Structure):
            _fields_ = (("rlim_cur", c_ulong), ("rlim_max", c_ulong))

        # try to get maxFd by standard library call #
        try:
            # load libc #
            ret = SysMgr.loadLibcObj()
            if not ret:
                raise Exception("no library")

            # create new object #
            rlim = rlimit()
            rlim.rlim_cur = c_ulong(slim)
            rlim.rlim_max = c_ulong(hlim)

            # prlimit #
            if hasattr(SysMgr.libcObj, "prlimit") or hasattr(
                SysMgr.libcObj, "prlimit64"
            ):

                # define real function #
                if hasattr(SysMgr.libcObj, "prlimit"):
                    func = SysMgr.libcObj.prlimit
                else:
                    func = SysMgr.libcObj.prlimit64

                func.argtypes = (
                    c_int,
                    c_int,
                    POINTER(rlimit),
                    POINTER(rlimit),
                )
                func.restype = c_int

                # create origin object #
                oldrlim = rlimit()

                ret = func(
                    c_int(os.getpid()), rindex, byref(rlim), byref(oldrlim)
                )
                if ret != 0:
                    raise Exception("error return %s" % ret)
            # getrlimit / setrlimit #
            elif hasattr(SysMgr.libcObj, "getrlimit"):
                SysMgr.libcObj.getrlimit.argtypes = (c_int, POINTER(rlimit))
                SysMgr.libcObj.getrlimit.restype = c_int

                # set resource value #
                ret = SysMgr.libcObj.setrlimit(rindex, byref(rlim))
                if ret != 0:
                    raise Exception("error return %s" % ret)

                # get new resource value #
                ret = SysMgr.libcObj.getrlimit(rindex, byref(rlim))
            else:
                raise Exception("no function")

            return (rlim.rlim_cur, rlim.rlim_max)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn(
                "failed to change %s to (%s,%s)" % (rtype, slim, hlim),
                reason=True,
            )

    @staticmethod
    def doStrings():
        # get argument #
        if SysMgr.hasMainArg():
            inputParam = SysMgr.getMainArg()
        elif SysMgr.inputParam:
            inputParam = SysMgr.inputParam
        else:
            SysMgr.printErr("no input for path")
            sys.exit(-1)

        SysMgr.setStream()

        # get file size #
        if os.path.exists(inputParam):
            # get output size #
            fsize = UtilMgr.getFileSizeStr(inputParam)
        else:
            SysMgr.printErr("no %s file" % inputParam)
            sys.exit(-1)

        SysMgr.printStat("start reading %s%s..." % (inputParam, fsize))

        # convert binary file to string #
        clist = UtilMgr.convBin2Str(inputParam, pos=SysMgr.showAll)
        if clist:
            SysMgr.printPipe()
        else:
            SysMgr.printErr("no available string")
            return

        convColor = UtilMgr.convColor

        # print position #
        if SysMgr.showAll:
            lastPos = sorted(clist.values())[-1]
            maxDigit = len(hex(lastPos))

            # print strings #
            for string, pos in sorted(clist.items(), key=lambda e: e[1]):
                if not UtilMgr.isValidStr(string, inc=True, ignCap=True):
                    continue
                SysMgr.printPipe(
                    "{0:>{digit}} {1}".format(
                        convColor(hex(pos), "BLUE"),
                        convColor(string, "RED"),
                        digit=maxDigit,
                    )
                )
        else:
            if SysMgr.filterGroup:
                for string in clist:
                    if not UtilMgr.isValidStr(string, inc=True, ignCap=True):
                        continue
                    SysMgr.printPipe(convColor(string, "RED"))
            else:
                SysMgr.printPipe("\n".join(clist))

    @staticmethod
    def restart(cmd=[], env=None):
        try:
            if not cmd:
                cmd = SysMgr.getCmdline(os.getpid()).split()

            if not env:
                env = deepcopy(os.environ)

            os.execvpe(cmd[0], cmd, env)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to restart %s" % __module__, True)

    @staticmethod
    def removeCgroup(path):
        try:
            # init system context #
            if not SysMgr.sysInstance:
                SysMgr.initSystemContext()

            # get cgroup path #
            cgroupPath = SysMgr.sysInstance.getCgroupPath()
            if not cgroupPath:
                raise Exception("access fail to cgroup filesystem")

            # check and get root path #
            if path.startswith(cgroupPath):
                root = UtilMgr.lstrip(path, cgroupPath).split("/")
                root = UtilMgr.cleanItem(root)
                rootPath = os.path.join(cgroupPath, root[0], "tasks")
            elif os.path.exists(os.path.join(cgroupPath, path)):
                root = UtilMgr.cleanItem(path.split("/"))
                path = os.path.join(cgroupPath, path)
                rootPath = os.path.join(cgroupPath, root[0], "tasks")
            else:
                raise Exception("wrong directory path")

            # find all tasks files #
            targetList = UtilMgr.getFiles(path, ["tasks"])

            # get all tids #
            while 1:
                tids = []
                for f in targetList:
                    tids += SysMgr.readFile(f).split("\n")

                # check items #
                if not UtilMgr.cleanItem(tids):
                    break

                # remove all tasks from sub-groups #
                SysMgr.writeFile(rootPath, tids)

                # wait for a moment #
                time.sleep(0.1)

            # remove target directory #
            for p in sorted(
                targetList, key=lambda x: x.count("/"), reverse=True
            ):
                try:
                    os.rmdir(UtilMgr.rstrip(p, "/tasks"))
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printWarn("failed to remove '%s'" % p, True, True)

            return True
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("failed to remove '%s'" % path, True, True)
            return False

    @staticmethod
    def limitBlock(pids, attrs, devices=[]):
        if not pids:
            return

        # check root permission #
        SysMgr.checkRootPerm(msg="limit block usage using cgroup")

        # set device list for all #
        if not devices:
            # save diskstats #
            SysMgr.updateDiskStats()

            for line in SysMgr.diskStats:
                try:
                    devices.append(
                        ":".join(line.split(sep=None, maxsplit=3)[:2])
                    )
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

        name = str(time.time()).replace(".", "")

        # set commands for memory size #
        cmds = ["CREATE:blkio:guider_{0:1}:{1:1}".format(name, pids[0])]

        # set commands #
        if len(pids) > 1:
            for pid in pids[1:]:
                cmds.append("ADD:blkio:guider_{0:1}:{1:1}".format(name, pid))

        # set commands #
        for item in attrs:
            for dev in devices:
                cmds.append(
                    (
                        "WRITE:blkio:guider_{0:1}:{3:1} {2:1}"
                        "@blkio.throttle.{1:1}"
                    ).format(
                        name,
                        item[0],
                        item[1],
                        dev,
                    ),
                )

        # execute commands to limit memory #
        SysMgr.doCgroup(cmds, make=True, remove=True, verb=False)

    @staticmethod
    def limitCpu(pids, attrs):
        if not pids:
            return

        # check root permission #
        SysMgr.checkRootPerm(msg="limit cpu usage using cgroup")

        name = str(time.time()).replace(".", "")

        # set commands for CPU usage #
        cmds = ["CREATE:cpu:guider_{0:1}:{1:1}".format(name, pids[0])]
        cmds.append(
            "WRITE:cpu:guider_{0:1}:{2:1}@cpu.{1:1}".format(
                name, "cfs_period_us", 1000000
            )
        )
        cmds.append(
            "WRITE:cpu:guider_{0:1}:{2:1}@cpu.{1:1}".format(
                name, "rt_period_us", 1000000
            )
        )

        # set commands #
        if len(pids) > 1:
            for pid in pids[1:]:
                cmds.append("ADD:cpu:guider_{0:1}:{1:1}".format(name, pid))

        # set commands #
        for item in attrs:
            cmds.append(
                "WRITE:cpu:guider_{0:1}:{2:1}@cpu.{1:1}".format(
                    name, item[0], item[1]
                ),
            )

        # execute commands to limit memory #
        SysMgr.doCgroup(cmds, make=True, remove=True, verb=False)

    @staticmethod
    def limitMemory(pids, attrs):
        if not pids:
            return

        # check root permission #
        SysMgr.checkRootPerm(msg="limit memory usage using cgroup")

        name = str(time.time()).replace(".", "")

        # set commands for memory size #
        cmds = ["CREATE:memory:guider_{0:1}:{1:1}".format(name, pids[0])]

        # set commands #
        if len(pids) > 1:
            for pid in pids[1:]:
                cmds.append("ADD:memory:guider_{0:1}:{1:1}".format(name, pid))

        # set commands #
        for item in attrs:
            cmds.append(
                "WRITE:memory:guider_{0:1}:{2:1}@memory.{1:1}".format(
                    name, item[0], item[1]
                ),
            )

        # execute commands to limit memory #
        SysMgr.doCgroup(cmds, make=True, remove=True, verb=False)

    @staticmethod
    def doCgroup(cmds=[], make=False, remove=False, verb=True):
        def _moveTasks(srcFile, desFile, targetTasks):
            # read target tasks #
            tasks = SysMgr.readFile(srcFile)
            if tasks:
                tasks = tasks.split("\n")
            else:
                tasks = []

            # filter target tasks #
            tasks = list(set(tasks) & set(targetTasks))
            if not tasks:
                return []

            # move tasks #
            SysMgr.writeFile(desFile, tasks)

            return tasks

        # get argument #
        if cmds:
            value = cmds
        elif SysMgr.hasMainArg():
            value = SysMgr.getMainArgs(False)
        elif SysMgr.filterGroup:
            value = SysMgr.filterGroup
        else:
            SysMgr.printErr("failed to get commands for cgroup")
            sys.exit(-1)

        # verify and convert command strings #
        cmds = []
        for item in value:
            try:
                # CMD:SUB:NAME:TARGET #
                cmdset = item.split(":", 3)
                cmd, sub, name, target = cmdset
                cmds.append([cmd.upper(), sub, name, target.strip()])
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    (
                        "failed to convert cgroup command '%s' "
                        "in CMD:SUB:NAME:TARGET format"
                    )
                    % item,
                    True,
                )
                sys.exit(-1)

        # check task type #
        if SysMgr.processEnable:
            isThread = False
            taskType = "process"
            taskNode = "cgroup.procs"
        else:
            isThread = True
            taskType = "thread"
            taskNode = "tasks"

        # define shortcut variable #
        convNum = UtilMgr.convNum

        # handle commands #
        for clist in cmds:
            # get command info #
            cmd, sub, name, target = clist

            # check command #
            if not cmd in (
                "CREATE",
                "ADD",
                "MOVE",
                "REMOVE",
                "DELETE",
                "WRITE",
                "LIST",
            ):
                SysMgr.printErr("no support '%s' command" % cmd)
                sys.exit(-1)

            # get target tasks #
            if cmd in ("CREATE", "ADD", "MOVE", "REMOVE", "LIST"):
                if cmd == "CREATE" and not target:
                    targetTasks = None
                else:
                    targetTasks = SysMgr.getTids(
                        target,
                        isThread=isThread,
                        sibling=SysMgr.groupProcEnable,
                    )
                    if not targetTasks:
                        SysMgr.printErr("no target %s" % taskType, True)
                        continue
            else:
                targetTasks = None

            # handle move command #
            if cmd == "WRITE":
                # get target info #
                targetDir = SysMgr.getCgroup(sub, name, make, remove)
                try:
                    value, name = target.split("@")
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(
                        "wrong '%s' in VALUE@FILE format" % target, True
                    )
                    continue

                # get target path #
                targetFile = os.path.join(targetDir, name)

                # write value #
                SysMgr.writeFile(targetFile, value)

                # print message #
                SysMgr.printInfo("wrote '%s' to '%s'" % (value, targetFile))

                continue
            # handle move command #
            elif cmd == "LIST":
                # get target path #
                targetDir = SysMgr.getCgroup(sub, name, make, remove)
                targetFile = os.path.join(targetDir, taskNode)
                if not os.path.exists(targetFile):
                    SysMgr.printErr("wrong cgroup '%s' for list" % targetFile)
                    continue

                # print target tasks #
                tasks = SysMgr.readFile(targetFile)
                if tasks:
                    tasks = tasks.split("\n")
                else:
                    SysMgr.printInfo("no %s in '%s'" % (taskType, targetFile))
                    continue

                # apply filter #
                tasks = list(map(long, list(set(tasks) & set(targetTasks))))

                # print message #
                SysMgr.printInfo(
                    "print %s %s from '%s'"
                    % (convNum(len(tasks)), taskType, targetFile)
                )

                # print tasks #
                for idx, tid in enumerate(sorted(tasks)):
                    if not verb:
                        continue

                    SysMgr.printPipe(
                        "[%s] %s(%s)"
                        % (convNum(idx), SysMgr.getComm(tid), tid)
                    )

                continue
            # handle move command #
            elif cmd == "MOVE":
                # source #
                try:
                    srcSub, srcName = sub.split("/", 1)
                    srcDir = SysMgr.getCgroup(srcSub, srcName, make, remove)
                    srcFile = os.path.join(srcDir, taskNode)
                    if not os.path.exists(srcFile):
                        raise Exception("no file")
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(
                        "wrong source cgroup '%s' for move" % sub, True
                    )
                    continue

                # destination #
                try:
                    desSub, desName = name.split("/", 1)
                    desDir = SysMgr.getCgroup(desSub, desName, make, remove)
                    desFile = os.path.join(desDir, taskNode)
                    if not os.path.exists(desFile):
                        raise Exception("no file")
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(
                        "wrong destination cgroup '%s' for move" % name, True
                    )
                    continue

                # move tasks #
                tasks = _moveTasks(srcFile, desFile, targetTasks)
                if not tasks:
                    SysMgr.printErr(
                        "no %s to be moved from '%s' to '%s'"
                        % (taskType, srcFile, desFile)
                    )
                    continue

                # print message #
                SysMgr.printInfo(
                    "moved %s %s from '%s' to '%s'"
                    % (convNum(len(tasks)), taskType, srcDir, desDir)
                )

                # print tasks #
                for idx, tid in enumerate(tasks):
                    if not verb:
                        continue

                    SysMgr.printPipe(
                        "[%s] %s(%s)"
                        % (convNum(idx), SysMgr.getComm(tid), tid)
                    )

                continue

            # set make flag #
            if cmd == "CREATE":
                make = True
            else:
                make = False

            # get directory #
            targetDir = SysMgr.getCgroup(sub, name, make, remove)
            if not os.path.exists(targetDir):
                SysMgr.printErr("no target group %s" % targetDir)
                continue
            elif cmd == "DELETE":
                SysMgr.removeCgroup(targetDir)
                SysMgr.printInfo("deleted '%s' cgroup" % targetDir)
                continue
            elif cmd == "CREATE" and targetTasks is None:
                SysMgr.printInfo("created '%s' cgroup" % targetDir)
                continue

            # register tasks to cgroup node #
            targetFile = os.path.join(targetDir, taskNode)

            # ADD #
            if cmd in ("CREATE", "ADD"):
                # move tasks #
                SysMgr.writeFile(targetFile, targetTasks)

                # print message #
                SysMgr.printInfo(
                    "added %s %s in total to '%s' cgroup"
                    % (convNum(len(targetTasks)), taskType, targetDir)
                )

                SysMgr.printWarn(SysMgr.getCommList(targetTasks))

                tasks = targetTasks
            # REMOVE #
            else:
                # get target file #
                desFile = os.path.join(
                    os.path.dirname(targetFile), "..", taskNode
                )
                if not os.path.exists(desFile):
                    SysMgr.printErr(
                        "wrong destination cgroup '%s' for removal" % desFile
                    )
                    continue

                # move tasks #
                tasks = _moveTasks(targetFile, desFile, targetTasks)
                if not tasks:
                    SysMgr.printErr(
                        "no %s to be removed from '%s'" % (taskType, targetDir)
                    )
                    continue

                # print message #
                SysMgr.printInfo(
                    "removed %s %s from '%s' cgroup"
                    % (convNum(len(tasks)), taskType, targetDir)
                )

                SysMgr.printWarn(SysMgr.getCommList(tasks))

            # sort targets #
            tasks = sorted(list(map(long, tasks)))

            # print tasks #
            for idx, tid in enumerate(tasks):
                if not verb:
                    continue

                SysMgr.printPipe(
                    "[%s] %s(%s)" % (convNum(idx), SysMgr.getComm(tid), tid)
                )

    @staticmethod
    def getCgroup(sub, name=None, make=False, remove=False):
        try:
            # init system context #
            if not SysMgr.sysInstance:
                SysMgr.initSystemContext()

            # get cgroup path #
            cgroupPath = SysMgr.sysInstance.getCgroupPath()
            if not cgroupPath:
                raise Exception("access fail to cgroup filesystem")

            # check subsystem #
            cgroupPath = os.path.join(cgroupPath, sub)
            if not os.path.exists(cgroupPath):
                raise Exception("access fail to %s cgroup subsystem" % sub)

            # set dir name #
            if not name:
                name = "guider_%s" % SysMgr.pid

            # make target dir #
            targetDir = os.path.join(cgroupPath, name)
            try:
                if make and not os.path.exists(targetDir):
                    os.makedirs(targetDir)
            except SystemExit:
                sys.exit(0)
            except:
                raise Exception("make fail for '%s'" % targetDir)

            # register handler to remove directory #
            if remove:
                SysMgr.addExitFunc(SysMgr.removeCgroup, [targetDir])

            return targetDir
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("failed to get cgroup %s" % sub, True, True)
            return False

    @staticmethod
    def getCgroupFreezer():
        try:
            # check result #
            if SysMgr.freezerPath or SysMgr.freezerPath is False:
                return SysMgr.freezerPath

            # get cgroup #
            tempDir = SysMgr.getCgroup("freezer", make=True, remove=True)
            if not tempDir:
                return

            # freeze tasks #
            SysMgr.writeFile(os.path.join(tempDir, "freezer.state"), "FROZEN")

            # register tasks to cgroup node #
            SysMgr.freezerPath = os.path.join(tempDir, "tasks")
            return SysMgr.freezerPath
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("failed to create cgroup freezer", True, True)
            SysMgr.freezerPath = False
            return False

    @staticmethod
    def doFreeze():
        # check root permissino #
        SysMgr.checkRootPerm()

        # get argument #
        if SysMgr.hasMainArg():
            value = SysMgr.getMainArgs()
        elif SysMgr.filterGroup:
            value = SysMgr.filterGroup
        else:
            SysMgr.printErr("failed to freeze tasks because of no target")
            sys.exit(-1)

        # check task type #
        if SysMgr.processEnable:
            isThread = False
            taskType = "process"
            taskNode = "cgroup.procs"
        else:
            isThread = True
            taskType = "thread"
            taskNode = "tasks"

        # get target tasks #
        targetTasks = []
        for item in value:
            targetTasks += SysMgr.getTids(
                item, isThread=isThread, sibling=SysMgr.groupProcEnable
            )
        if not targetTasks:
            SysMgr.printErr("no target %s" % taskType)
            sys.exit(-1)

        # get cgroup #
        targetDir = SysMgr.getCgroup("freezer", make=True, remove=True)
        if not targetDir:
            return

        # register tasks to cgroup node #
        taskPushFile = os.path.join(targetDir, taskNode)
        SysMgr.writeFile(taskPushFile, targetTasks)

        # freeze tasks #
        SysMgr.writeFile(os.path.join(targetDir, "freezer.state"), "FROZEN")

        # print target tasks #
        tasks = SysMgr.readFile(taskPushFile).split("\n")
        for tid in tasks:
            if not tid:
                continue
            comm = SysMgr.getComm(tid)
            SysMgr.printInfo("freezed %s(%s) %s" % (comm, tid, taskType))

        # set alarm #
        signal.signal(signal.SIGALRM, SysMgr.onAlarm)
        signal.alarm(SysMgr.intervalEnable)

        # wait for events #
        SysMgr.waitEvent()

    @staticmethod
    def doSetAffinity():
        SysMgr.warnEnable = True

        # get argument #
        if SysMgr.hasMainArg():
            value = SysMgr.getMainArgs()
        elif SysMgr.filterGroup:
            value = SysMgr.filterGroup
        else:
            SysMgr.printErr(
                "failed to set CPU affinity of task because of no target"
            )
            sys.exit(-1)

        while 1:
            SysMgr.parseAffinityOption(value, launch=True)
            if SysMgr.intervalEnable:
                time.sleep(SysMgr.intervalEnable)
            else:
                break

        sys.exit(0)

    @staticmethod
    def importPkgItems(pkg, isExit=True):
        if pkg in SysMgr.impGlbPkg:
            return True

        module = SysMgr.getPkg(pkg, isExit)
        if not module:
            return False

        moduleDict = module.__dict__

        try:
            importList = module.__all__
        except SystemExit:
            sys.exit(0)
        except AttributeError:
            importList = [
                name for name in moduleDict if not name.startswith("_")
            ]

        newDict = {}
        for name in importList:
            newDict[name] = moduleDict[name]
        globals().update(newDict)

        SysMgr.impGlbPkg[pkg] = True

        return True

    @staticmethod
    def setBlock(fd, block=True):
        fcntl = SysMgr.getPkg("fcntl", False)

        try:
            if not fcntl:
                raise Exception("no fcntl")

            flag = fcntl.fcntl(fd.fileno(), fcntl.F_GETFL)

            if block:
                fcntl.fcntl(fd.fileno(), fcntl.F_SETFL, flag & ~os.O_NONBLOCK)
            else:
                fcntl.fcntl(fd.fileno(), fcntl.F_SETFL, flag | os.O_NONBLOCK)

            return True
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn(
                "failed to set block attribute to the file descriptor",
                reason=True,
            )
            return False

    @staticmethod
    def getHomePath():
        try:
            return os.environ["HOME"]
        except:
            return None

    @staticmethod
    def initLogWatcher(data):
        logList = {
            "KERNEL": "printkmsg",
            "DLT": "printdlt",
            "JOURNAL": "printjrl",
            "SYSLOG": "printsys",
        }

        for name, values in data.items():
            # check skip condition #
            if not name in logList:
                SysMgr.printErr("no support '%s' for log monitoring" % name)
                continue

            # check type #
            if type(values) is list:
                pass
            elif type(values) is dict:
                values = [values]
            else:
                continue

            for value in values:
                # check skip conditions #
                if not "apply" in value or value["apply"] != "true":
                    continue
                elif not "filter" in value:
                    SysMgr.printErr("no filter for '%s' monitoring" % name)
                    continue

                # get filter #
                target = value["filter"]

                # set event name #
                event = "CMD_NOTIFY:log_%s_%s" % (name, target)

                # get condition for exit #
                if ("oneshot" in value and value["oneshot"] == "true") or (
                    "goneshot" in value and value["goneshot"] == "true"
                ):
                    exitCond = ",WATCHLOGEXIT"
                else:
                    exitCond = ""

                # set port opt #
                portOpt = " -X%s" % SysMgr.localServObj.port

                # set default command #
                common = [
                    "-qWATCHLOG:%s,TAIL,WATCHLOGCMD:GUIDER event %s%s%s"
                    % (target, event, portOpt, exitCond),
                    "-dp",
                ]

                # set command #
                cmd = [logList[name]] + common

                # set mute flag #
                if "NOMUTE" in SysMgr.environList:
                    mute = False
                else:
                    mute = True

                # execute watcher tasks #
                ret = SysMgr.launchGuider(
                    cmd, mute=mute, pipe=False, stderr=True
                )
                # register the event handling process #
                if ret > 0:
                    SysMgr.eventCommandList.setdefault(event, ret)

    @staticmethod
    def initFuncWatcher(data):
        funcList = {
            "NATIVE": "btrace",
            "SYSCALL": "strace",
            "PYTHON": "pytrace",
            "SIGNAL": "sigtrace",
            "DBUS": "printdbus",
        }

        for name, values in data.items():
            # check skip condition #
            if not name in funcList:
                SysMgr.printErr(
                    "no support '%s' for function monitoring" % name
                )
                continue

            # check type #
            if type(values) is list:
                pass
            elif type(values) is dict:
                values = [values]
            else:
                continue

            for value in values:
                # check skip conditions #
                if not "apply" in value or value["apply"] != "true":
                    continue
                elif not "filter" in value:
                    SysMgr.printErr(
                        "no function filter for '%s' monitoring" % name
                    )
                    continue
                elif not "thread" in value:
                    SysMgr.printErr(
                        "no thread filter for '%s' monitoring" % name
                    )
                    continue

                # get function filter #
                target = value["filter"]

                # get task filter #
                task = value["thread"]

                # set event name #
                event = "CMD_NOTIFY:func_%s_%s" % (name, target)

                # get condition for exit #
                if ("oneshot" in value and value["oneshot"] == "true") or (
                    "goneshot" in value and value["goneshot"] == "true"
                ):
                    logExitCond = ",WATCHLOGEXIT"
                    funcExitCond = "|exit"
                else:
                    logExitCond = ""
                    funcExitCond = ""

                # set mute flag #
                if "NOMUTE" in SysMgr.environList:
                    mute = False
                else:
                    mute = True

                # set port opt #
                portOpt = " -X%s" % SysMgr.localServObj.port

                # set handle command #
                handleCmd = "GUIDER event %s%s" % (event, portOpt)

                # set default command #
                if name == "DBUS":
                    common = []
                else:
                    common = ["-g%s" % task]

                # append syscall option #
                if name == "SYSCALL":
                    common += ["-t%s" % target.replace("+", ",")]

                # set filter command #
                if name in ("SIGNAL", "DBUS"):
                    # define mandatory environment variables #
                    addCmd = "-qWATCHLOG:%s,WATCHLOGCMD:%s" % (
                        target,
                        handleCmd,
                    )
                    # append main option #
                    if "main" in value and value["main"] == "true":
                        addCmd += ",ONLYPROC%s" % logExitCond
                    else:
                        addCmd += logExitCond
                    # composite values #
                    common += [addCmd]

                    addCmd = "-c%s" % target.replace("+", ",")
                else:
                    addCmd = "-c"
                    for func in target.split("+"):
                        addCmd += "%s|exec:%s%s," % (
                            func,
                            handleCmd,
                            funcExitCond,
                        )
                    addCmd = addCmd.rstrip(",")

                    # append main option #
                    if "main" in value and value["main"] == "true":
                        common += ["-qONLYPROC"]
                common += [addCmd]

                # append process group option #
                if (
                    name != "DBUS"
                    and "group" in value
                    and value["group"] == "true"
                ):
                    common += ["-P"]

                # set command #
                cmd = [funcList[name]] + common

                # execute watcher tasks #
                ret = SysMgr.launchGuider(
                    cmd, mute=mute, pipe=False, stderr=True, copyOpt=False
                )
                # register the event handling process #
                if ret > 0:
                    SysMgr.eventCommandList.setdefault(event, ret)

    @staticmethod
    def applyThreshold():
        def _getMaxInterval(node, maxVal=0, root=None):
            for key, item in node.items():
                # set root resource #
                if root:
                    res = root
                else:
                    res = key

                if type(item) is list:
                    for subitem in item:
                        # check skip condition #
                        if type(subitem) is not dict:
                            continue
                        elif "apply" in subitem and subitem["apply"] != "true":
                            continue

                        # check sub items #
                        val = _getMaxInterval(subitem, maxVal, res)
                        if maxVal < val:
                            maxVal = val
                elif type(item) is dict:
                    # check skip condition #
                    if "apply" in item and item["apply"] != "true":
                        continue

                    # check items #
                    val = _getMaxInterval(item, maxVal, res)
                    if maxVal < val:
                        maxVal = val
                elif key == "interval" and UtilMgr.isNumber(item):
                    item = long(item)
                    if maxVal < item:
                        maxVal = item

            return maxVal

        def _checkResTask(item, lev=0):
            if (
                type(item) is dict
                and "apply" in item
                and item["apply"] == "true"
            ):
                return True

            # check type #
            if type(item) is list:
                for value in item:
                    if _checkResTask(value, lev + 1):
                        return True
            elif type(item) is dict:
                for key, value in item.items():
                    if lev == 0 and key == "SYSTEM":
                        continue
                    if _checkResTask(value, lev + 1):
                        return True

            return False

        def _checkResource(item):
            if (
                type(item) is dict
                and "apply" in item
                and item["apply"] == "true"
            ):
                return True

            # check type #
            if type(item) is list:
                for value in item:
                    if _checkResource(value):
                        return True
            elif type(item) is dict:
                for key, value in item.items():
                    if _checkResource(value):
                        return True

            return False

        def _checkTask(item, threshold=False):
            def _checkValues(subitem, initFlag):
                if not type(subitem) is dict:
                    return False

                for target, value in subitem.items():
                    # update system flag #
                    if initFlag is None:
                        systemFlag = True if target == "SYSTEM" else False
                    else:
                        systemFlag = initFlag

                    # check apply in dict #
                    if target == "apply":
                        if value != "true":
                            return False
                        elif not systemFlag:
                            return True
                    # check taskmon field #
                    elif (
                        not threshold
                        and target == "taskmon"
                        and value == "true"
                    ):
                        return True
                    # check list value #
                    elif type(value) is list:
                        for subval in value:
                            if _checkValues(subval, systemFlag):
                                return True
                    # check value type #
                    elif type(value) is not dict:
                        continue
                    # check apply for dict value #
                    elif "apply" in value:
                        if value["apply"] != "true":
                            continue
                        elif not systemFlag:
                            return True
                return False

            if not type(item) is dict:
                return True

            for res, cond in item.items():
                # skip commands #
                if res.upper() == "COMMAND":
                    continue
                # no support resources for task monitoring #
                elif res in ("storage", "net", "log", "func"):
                    continue

                if _checkValues(cond, None):
                    return True

            return False

        def _checkPerm(item):
            try:
                if item["apply"] == "true" and item["perm"] == "root":
                    SysMgr.checkRootPerm(msg="check threshold for %s" % item)
            except SystemExit:
                sys.exit(0)
            except:
                pass

            if type(item) is list:
                for value in item:
                    _checkPerm(value)
            elif type(item) is dict:
                for key, value in item.items():
                    _checkPerm(value)

        # check threshold #
        if not "threshold" in ConfigMgr.confData:
            return

        # get threshold dict #
        confData = SysMgr.getConfigItem("threshold")
        if not confData or type(confData) is not dict:
            return
        # check active threshold #
        elif not _checkResource(confData):
            SysMgr.printWarn(
                (
                    "disabled the threshold monitoring "
                    "because of no active threshold"
                ),
                True,
            )
            return
        else:
            SysMgr.thresholdData = confData

        # update threshold data #
        if "UPDATETHRESHOLD" in SysMgr.environList:
            path = SysMgr.environList["UPDATETHRESHOLD"][0]

            # load data from the file #
            try:
                with open(path) as fd:
                    body = fd.read()
                    value = UtilMgr.convStr2Dict(body, True)
                    if not value:
                        return None
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenErr(path, True)
                sys.exit(-1)

            # update threshold condition #
            try:
                SysMgr.thresholdData.update(value)
            except:
                SysMgr.printErr("failed to update threshold data", True)
                sys.exit(-1)

            # print message #
            SysMgr.printInfo("updated the threshold data from '%s'" % path)

        # set report table #
        SysMgr.reportEnable = True
        if SysMgr.findOption("j"):
            SysMgr.rankProcEnable = True
        else:
            SysMgr.rankProcEnable = False

        # check permission #
        _checkPerm(confData)

        # reset activation list #
        SysMgr.thresholdTarget = {}

        # check default resources #
        resourceList = [
            "cpu",
            "gpu",
            "mem",
            "gpumem",
            "swap",
            "block",
            "storage",
            "net",
            "load",
            "fd",
            "sock",
            "task",
        ]

        # check resources for activation #
        for item in resourceList:
            try:
                if _checkResource(confData[item]):
                    SysMgr.thresholdTarget[item] = True
                    SysMgr.thresholdTarget[item] = _checkResTask(
                        confData[item]
                    )
            except SystemExit:
                sys.exit(0)
            except:
                pass

        # print target resources #
        if SysMgr.thresholdTarget:
            SysMgr.printInfo(
                "enabled resource events [ %s ]"
                % ", ".join([res for res in SysMgr.thresholdTarget])
            )

        # check block #
        try:
            for kind, cond in confData["block"].items():
                if kind == "SYSTEM":
                    continue
                elif _checkResource(cond):
                    SysMgr.blockEnable = True
                    SysMgr.sort = "b"
                    break
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # check storage #
        if "storage" in SysMgr.thresholdTarget:
            SysMgr.diskEnable = True

        # check network #
        if "net" in SysMgr.thresholdTarget:
            SysMgr.networkEnable = True

        # check fd #
        if "fd" in SysMgr.thresholdTarget:
            SysMgr.addEnvironVar("ACTUALFD")

        # check log #
        if "log" in SysMgr.thresholdData:
            SysMgr.initLogWatcher(SysMgr.thresholdData["log"])

        # check func #
        if "func" in SysMgr.thresholdData:
            SysMgr.initFuncWatcher(SysMgr.thresholdData["func"])

        # check task monitoring condition #
        try:
            # check normal stats #
            SysMgr.taskEnable = _checkTask(confData)
            if SysMgr.taskEnable:
                # check thresholds #
                SysMgr.taskThresholdEnable = _checkTask(confData, True)
            else:
                SysMgr.taskThresholdEnable = False
                SysMgr.printWarn(
                    (
                        "disabled the task monitoring "
                        "because of no threshold for task"
                    ),
                    True,
                )
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("failed to check task monitoring", reason=True)

        # update maximum interval #
        maxInterval = _getMaxInterval(confData)
        if maxInterval > SysMgr.maxInterval:
            SysMgr.maxInterval = maxInterval

        SysMgr.printInfo("applied thresholds from '%s'" % SysMgr.confFileName)

        # print thresholds #
        if SysMgr.warnEnable:
            SysMgr.printWarn(UtilMgr.convDict2Str(confData))

    @staticmethod
    def doGetAffinity():
        SysMgr.warnEnable = True

        # get argument #
        if SysMgr.hasMainArg():
            value = SysMgr.getMainArgs(False)
        elif SysMgr.filterGroup:
            value = SysMgr.filterGroup
        else:
            SysMgr.printErr(
                "failed to get the CPU affinity of task because of no target"
            )
            sys.exit(-1)

        SysMgr.checkRootPerm()

        sibling = SysMgr.groupProcEnable
        targetList = []

        try:
            for item in value:
                targetList += SysMgr.getTids(item, sibling=sibling)

            if not targetList:
                SysMgr.printErr("no thread related to '%s'" % item)
                sys.exit(-1)

            targetList = list(set(targetList))
            targetList = list(map(long, targetList))

            for tid in targetList:
                mask = SysMgr.getAffinity(tid)
                if not mask:
                    SysMgr.printErr(
                        "failed to get the CPU affinity of %s(%s)"
                        % (SysMgr.getComm(tid), tid)
                    )
                else:
                    SysMgr.printInfo(
                        "the CPU affinity of %s(%s) is %s"
                        % (SysMgr.getComm(tid), tid, mask)
                    )
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to get the CPU affinity of task", True)
            sys.exit(-1)

    @staticmethod
    def setStream(cut=True):
        if "NOCUT" in SysMgr.environList or not cut:
            SysMgr.ttyCols = 0

        SysMgr.streamEnable = True
        SysMgr.encodeEnable = False

    @staticmethod
    def setAffinity(mask, pids, isProcess=False):
        if not SysMgr.isLinux:
            return

        # check root permission #
        if (
            len(pids) == 1
            and str(pids[0]).isdigit()
            and SysMgr.pid == long(pids[0])
        ):
            pass
        else:
            SysMgr.checkRootPerm(exit=False, attr="warn", msg="set affinity")

        # check pid list #
        if UtilMgr.isNumber(pids):
            pids = [long(pids)]
        elif type(pids) is list:
            for pid in pids:
                if not str(pid).isdigit():
                    SysMgr.printErr("failed to recognize pid %s" % pid)
                    return
        else:
            SysMgr.printErr("failed to recognize pid type")
            return

        # check mask type #
        try:
            mask = long(mask, 16)
            if mask == 0:
                SysMgr.printErr(
                    "failed to set mask to 0, use bit mask bigger than 0"
                )
                return
        except:
            SysMgr.printErr("failed to recognize mask type")
            return

        # load libc #
        SysMgr.loadLibcObj(exit=True)

        # get the number of core #
        nrCore = SysMgr.getNrCore()

        threadList = []
        for pid in pids:
            if isProcess:
                threadList += SysMgr.getThreadList(pid)
            else:
                threadList += [pid]

        for pid in list(set(threadList)):
            try:
                if SysMgr.guiderObj:
                    guiderObj = SysMgr.guiderObj
                    ret = guiderObj.sched_setaffinity(
                        long(pid), mask
                    )  # pylint: disable=no-member
            except SystemExit:
                sys.exit(0)
            except:
                pass

            try:
                # define function prototype #
                SysMgr.libcObj.sched_setaffinity.argtypes = [
                    c_int,
                    c_ulong,
                    POINTER(c_ulong),
                ]

                cmask = c_ulong(((0x1 << nrCore) - 1) & mask)

                ret = SysMgr.libcObj.sched_setaffinity(
                    c_int(long(pid)), c_ulong(nrCore), byref(cmask)
                )
            except SystemExit:
                sys.exit(0)
            except:
                ret = -1
                SysMgr.printWarn(
                    "failed to set CPU affinity for %s(%s) to 0x%X"
                    % (SysMgr.getComm(pid), pid, cmask.value),
                    reason=True,
                )

            if ret >= 0:
                SysMgr.printInfo(
                    "CPU affinity of %s(%s) is changed to 0x%X"
                    % (SysMgr.getComm(pid), pid, cmask.value)
                )
            else:
                SysMgr.printErr(
                    "failed to set CPU affinity for %s(%s) to 0x%X"
                    % (SysMgr.getComm(pid), pid, cmask.value)
                )

    @staticmethod
    def getAffinity(pid):
        try:
            return "0x%X" % SysMgr.guiderObj.sched_getaffinity(
                pid
            )  # pylint: disable=no-member
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # get ctypes object #
        if not SysMgr.importPkgItems("ctypes", False):
            return

        try:
            # load libc #
            if not SysMgr.loadLibcObj():
                raise Exception("no libc")

            # define function prototype #
            SysMgr.libcObj.sched_getaffinity.argtypes = [
                c_int,
                c_ulong,
                POINTER(c_ulong),
            ]

            # define variables #
            __cpu_mask = c_ulong
            __CPU_SETSIZE = 1024
            __NCPUBITS = sizeof(c_ulong) * 8
            mask = (c_ulong * long(__CPU_SETSIZE / __NCPUBITS))()
            size = sizeof(mask)

            # get affinity #
            ret = SysMgr.libcObj.sched_getaffinity(
                c_int(long(pid)), c_ulong(size), mask
            )
            if ret < 0:
                raise Exception("wrong affinity")

            return hex(mask[0]).rstrip("L")
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn(
                "failed to get CPU affinity for %s(%s)"
                % (SysMgr.getComm(pid), pid),
                reason=True,
            )

    @staticmethod
    def getMaxThread():
        maxThdPath = "/proc/sys/kernel/threads-max"
        try:
            with open(maxThdPath, "r") as fd:
                return long(fd.readline()[:-1])
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to read %s" % maxThdPath, reason=True)
            return None

    @staticmethod
    def setOOMAdj(pid="self", pri="-17"):
        if not SysMgr.isLinux:
            return

        # check root permission #
        if not SysMgr.isRoot():
            return

        # set path #
        oomPath = "%s/%s/oom_score_adj" % (SysMgr.procPath, pid)
        if not os.path.isfile(oomPath):
            # use deprecated path #
            oomPath = "%s/%s/oom_adj" % (SysMgr.procPath, pid)

        try:
            with open(oomPath, "w") as fd:
                fd.write(pri)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("failed to write %s" % oomPath, reason=True)

    @staticmethod
    def ping(url=[], timeout=None, count=None):
        ICMP_ECHO_REQUEST = 8

        def _checksum(source):
            total = 0
            countTo = (len(source) / 2) * 2
            count = 0
            while count < countTo:
                if isinstance(source[count + 1], (int, long)):
                    data1 = source[count + 1]
                else:
                    data1 = ord(source[count + 1])

                if isinstance(source[count], (int, long)):
                    data2 = source[count]
                else:
                    data2 = ord(source[count])

                thisVal = data1 * 256 + data2
                total += thisVal
                total = total & 0xFFFFFFFF  # Necessary?
                count = count + 2

            if countTo < len(source):
                total += ord(source[len(source) - 1])
                total = total & 0xFFFFFFFF  # Necessary?

            total = (total >> 16) + (total & 0xFFFF)
            total = total + (total >> 16)
            answer = ~total
            answer = answer & 0xFFFF

            # Swap bytes. Bugger me if I know why #
            answer = answer >> 8 | (answer << 8 & 0xFF00)

            return answer

        def _receivePing(sockList, timeout, sockInfo):
            select = SysMgr.getPkg("select")

            timeLeft = timeout
            while 1:
                startedSelect = time.time()

                # wait for event #
                whatReady = select.select(sockList, [], [], timeLeft)

                # check timeout #
                if not whatReady[0]:
                    return

                # get current time #
                timeReceived = time.time()

                howLongInSelect = timeReceived - startedSelect

                # check received packets #
                for sock in whatReady[0]:
                    recPacket, addr = sock.recvfrom(1024)
                    icmpHeader = recPacket[20:28]
                    ptype, code, checksum, packetID, sequence = struct.unpack(
                        "bbHHh", icmpHeader
                    )

                    # get sent ID #
                    ID = sockInfo[sock.fileno()][2]

                    # check sent ID #
                    if packetID != ID:
                        continue

                    # decode packet #
                    bytesInDouble = struct.calcsize("d")
                    timeSent = struct.unpack(
                        "d", recPacket[28 : 28 + bytesInDouble]
                    )[0]

                    # save times #
                    delay = timeReceived - timeSent
                    sockInfo[sock.fileno()].append(delay)
                    sockList.pop(sockList.index(sock))

                # finished #
                if not sockList:
                    return

                # timeout #
                timeLeft = timeLeft - howLongInSelect
                if timeLeft <= 0:
                    return

        def _sendPing(sock, destAddr, ID):
            socket = SysMgr.getPkg("socket")

            # Header: type(8), code(8), checksum(16), id(16), sequence(16) #
            checksumData = 0

            # Make a dummy heder with a 0 checksum #
            header = struct.pack(
                "bbHHh", ICMP_ECHO_REQUEST, 0, checksumData, ID, 1
            )
            bytesInDouble = struct.calcsize("d")
            data = (192 - bytesInDouble) * "Q".encode()
            data = struct.pack("d", time.time()) + data

            # Calculate the checksum on the data and the dummy header. #
            checksumData = _checksum(header + data)

            """
            Now that we have the right checksum,
            we put that in. It's just easier
            to make up a new header than to stuff it into the dummy.
            """
            header = struct.pack(
                "bbHHh",
                ICMP_ECHO_REQUEST,
                0,
                socket.htons(checksumData),
                ID,
                1,
            )
            packet = header + data
            sock.sendto(packet, (destAddr, 0))

        def _convAddrs(addrList):
            def __expandAddrs(addrs, item):
                newAddrs = []
                if item.isdigit():
                    if not addrs:
                        newAddrs.append(item)
                    else:
                        for word in addrs:
                            newAddrs.append("%s.%s" % (word, item))
                elif item.count("-") == 1:
                    start, end = item.split("-")
                    if start.strip().isdigit() and end.strip().isdigit():
                        for idx in xrange(long(start), long(end) + 1):
                            if not addrs:
                                newAddrs.append(idx)
                                continue

                            for word in addrs:
                                newAddrs.append("%s.%s" % (word, idx))
                    elif not addrs:
                        newAddrs.append(item)
                    else:
                        for word in addrs:
                            newAddrs.append("%s.%s" % (word, idx))
                elif item == "*":
                    for idx in xrange(1, 255):
                        if not addrs:
                            newAddrs.append(idx)
                        else:
                            for word in addrs:
                                newAddrs.append("%s.%s" % (word, idx))
                else:
                    if not addrs:
                        newAddrs.append(item)
                    else:
                        for word in addrs:
                            newAddrs.append("%s.%s" % (word, item))

                return newAddrs

            if not addrList:
                return addrList

            newAddrList = []
            for addr in addrList:
                # digit address #
                checkAddr = addr.replace(".", "")
                if checkAddr.isdigit():
                    newAddrList.append(addr)
                    continue

                # name address #
                checkAddr = checkAddr.replace("-", "").replace("*", "")
                if not checkAddr.isdigit():
                    newAddrList.append(addr)
                    continue

                # convert addresses #
                addrs = []
                fields = addr.split(".")
                for item in fields:
                    addrs = __expandAddrs(addrs, item)

                # add addresses #
                newAddrList += addrs

            return newAddrList

        def _doPing(addrList, timeout, seq=None, verb=True):
            socket = SysMgr.getPkg("socket")

            # set attributes #
            try:
                ttl = 64
                icmp = socket.getprotobyname("icmp")
            except:
                SysMgr.printErr("failed to ping", True)
                return 0

            # define socket list #
            sockList = []
            sockInfo = {}

            # send packets #
            for idx, destAddr in enumerate(addrList):
                destIPAddr = socket.gethostbyname(destAddr)

                # create a socket #
                try:
                    sock = socket.socket(socket.AF_INET, socket.SOCK_RAW, icmp)
                    sock.setsockopt(socket.IPPROTO_IP, socket.IP_TTL, ttl)
                except:
                    SysMgr.printErr("failed to ping", True)
                    return 0

                # create an unique ID #
                ICMP_ID = (os.getpid() + idx) & 0xFFFF

                # send packet #
                _sendPing(sock, destIPAddr, ICMP_ID)

                # get address details #
                if destAddr == destIPAddr:
                    addrInfo = destAddr
                else:
                    addrInfo = "%s(%s)" % (destAddr, destIPAddr)

                # save sock info #
                sockList.append(sock)
                sockInfo[sock.fileno()] = [sock, addrInfo, ICMP_ID]

            # receive packet #
            _receivePing(sockList, timeout, sockInfo)

            # add timed out info and close all sockets #
            for name, attr in sockInfo.items():
                if len(attr) <= 3:
                    sockInfo[name].append(timeout)
                try:
                    attr[0].close()
                except:
                    pass

            # check return condition #
            if not verb:
                return

            # set sequence string #
            if seq is not None:
                seqstr = "[%s] " % seq
            else:
                seqstr = ""

            # define json variable #
            if SysMgr.jsonEnable:
                jsonData = {"seq": seq, "success": {}, "fail": {}}
                pretty = not SysMgr.findOption("Q")

            timeoutstr = ""
            timeoutlinestr = ""

            # print results #
            for attr in sorted(sockInfo.values(), key=lambda x: x[3]):
                name = attr[1]
                elapsed = attr[3]

                # success #
                if elapsed < timeout:
                    delay = attr[3] * 1000

                    if SysMgr.jsonEnable:
                        jsonData["success"].setdefault(name, {})
                        jsonData["success"][name]["time"] = delay
                        continue

                    name = UtilMgr.convColor(name, "GREEN", 15, "left")
                    delaystr = UtilMgr.convColor("%.3f" % delay, "YELLOW")

                    SysMgr.printPipe("%s%s: %s ms" % (seqstr, name, delaystr))
                # timeout #
                else:
                    if SysMgr.jsonEnable:
                        jsonData["fail"].setdefault(name, {})
                        jsonData["fail"][name]["time"] = timeout
                        continue

                    name = UtilMgr.convColor(name, "RED", 15, "left")

                    if len(timeoutlinestr) + len(name) >= SysMgr.ttyCols:
                        timeoutstr = "%s %s\n" % (
                            timeoutstr,
                            timeoutlinestr.lstrip(),
                        )
                        timeoutlinestr = name
                    else:
                        timeoutlinestr = "%s %s" % (timeoutlinestr, name)

            # print results in JSON format #
            if SysMgr.jsonEnable:
                SysMgr.printPipe(UtilMgr.convDict2Str(jsonData, pretty=pretty))
            elif timeoutlinestr:
                timeoutstr = "%s %s\n" % (timeoutstr, timeoutlinestr.lstrip())

            # print timeout info #
            if timeoutstr:
                SysMgr.printPipe("%stimeout:\n%s" % (seqstr, timeoutstr))

        # check root permission for Linux #
        if SysMgr.isLinux and not SysMgr.checkRootPerm(exit=False, msg="ping"):
            return

        # get address list #
        urlList = []
        if url:
            urlList = url
        elif SysMgr.hasMainArg():
            urlList = SysMgr.getMainArgs()
        elif SysMgr.inputParam:
            try:
                files = SysMgr.inputParam.split(",")
                files = UtilMgr.cleanItem(files)
                for fname in files:
                    with open(fname, "r") as fd:
                        urlList += fd.readlines()
                urlList = UtilMgr.cleanItem(urlList)
            except:
                SysMgr.printErr(
                    "failed to read addresses from '%s'" % ",".join(files),
                    True,
                )
                sys.exit(-1)

        # check input #
        if not urlList:
            SysMgr.printErr("no input for address")
            sys.exit(-1)

        # convert addresses #
        urlList = _convAddrs(urlList)

        # set repeat count #
        if not count:
            if SysMgr.repeatInterval == 0:
                count = sys.maxsize
            else:
                count = SysMgr.repeatInterval

        # set count string #
        if count == sys.maxsize or count == SysMgr.maxSize:
            countStr = "INFINITE"
        else:
            countStr = "%s" % UtilMgr.convNum(count)

        SysMgr.printInfo("set repeat count to %s" % countStr)

        # set timeout #
        if not timeout:
            timeout = SysMgr.getOption("T")
            if timeout:
                try:
                    timeout = float(timeout)
                except:
                    SysMgr.printErr(
                        "failed to set timeout '%s'" % timeout, True
                    )
                    sys.exit(-1)
            else:
                timeout = 3

        # set interval #
        interval = SysMgr.getOption("i")
        try:
            interval = float(interval)
        except:
            interval = 1

        # print timeout info #
        timeoutstr = "%f" % timeout
        timeoutstr = timeoutstr.rstrip("0")
        if timeoutstr.endswith("."):
            timeoutstr = timeoutstr[:-1]
        SysMgr.printInfo("set timeout to %s sec\n" % timeoutstr)

        # ping #
        for seq in xrange(count):
            try:
                _doPing(urlList, timeout, seq=seq)
                time.sleep(interval)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("failed to send ping to %s", True)

    @staticmethod
    def getExeCmd(pid):
        cmd = SysMgr.getCmdline(pid, retList=True)[:2]
        if cmd[1][0] != "/":
            pwd = SysMgr.getPwd(pid)
            if not pwd:
                pwd = ""
            cmd[1] = os.path.realpath(os.path.join(pwd, cmd[1]))
        return cmd

    @staticmethod
    def getNetDevData():
        # read net buf #
        netBuf = SysMgr.readProcStat(
            SysMgr.netdevFd, "net/dev", SysMgr, "netdevFd"
        )
        if netBuf:
            return netBuf[2:]
        else:
            netBuf

    @staticmethod
    def getConfigItem(name, itype="dict"):
        if name in ConfigMgr.confData:
            confData = ConfigMgr.confData[name]
        else:
            return None

        if itype == "dict":
            if type(confData) is list:
                confData = UtilMgr.convStr2Dict("\n".join(confData), True)

            if type(confData) is dict:
                return confData
            else:
                return None
        elif itype == "list":
            if type(confData) is list:
                confData = ['{"array":'] + confData + ["}"]
                confData = UtilMgr.convStr2Dict("\n".join(confData), True)
                if not confData or not "array" in confData:
                    return None
                else:
                    return confData["array"]
            else:
                return None
        else:
            return confData

    @staticmethod
    def updateConfigPath():
        if os.path.exists(SysMgr.confFileName):
            return

        for path in [
            os.getcwd(),
            os.path.dirname(os.environ["CMDLINE"])
            if "CMDLINE" in os.environ
            else ".",
            os.path.dirname(SysMgr.getPyPath()),
            os.path.join(sys.prefix, "local/guider"),
            "/usr/share/guider",
        ]:
            fullPath = os.path.realpath(os.path.join(path, "guider.conf"))
            if os.path.exists(fullPath):
                SysMgr.confFileName = fullPath
                break

        # no path #
        if not os.path.exists(SysMgr.confFileName):
            SysMgr.printErr("no file for config")
            sys.exit(-1)

    @staticmethod
    def loadConfig(fname, verb=True):
        try:
            fname = os.path.realpath(fname)

            targetList = []
            fd = None
            skip = False
            fd = open(fname, "r")
            for line in fd.readlines():
                if not line:
                    continue

                line = line.strip()
                if not line or line == "\n":
                    continue
                elif line.startswith("#") or line.startswith("//"):
                    continue
                elif skip:
                    if line.startswith("'''") or line.startswith("*/"):
                        skip = False
                    continue
                elif line.startswith("'''") or line.startswith("/*"):
                    skip = True
                    continue
                elif line.startswith("<") and line.endswith(">"):
                    entry = line[1:-1]
                    ConfigMgr.confData.setdefault(entry, [])
                    targetList = ConfigMgr.confData[entry]
                    continue
                else:
                    targetList.append(line)

            if ConfigMgr.confData:
                SysMgr.printInfo("loaded config from '%s'" % fname)

            return ConfigMgr.confData
        except SystemExit:
            sys.exit(0)
        except:
            if verb:
                SysMgr.printErr(
                    "failed to load config from '%s'" % fname, reason=True
                )
            return None
        finally:
            if fd:
                fd.close()

    @staticmethod
    def getPyLibPath(load=True):
        if SysMgr.pyLibPath:
            return SysMgr.pyLibPath

        try:
            # set library name #
            exePath = SysMgr.getExeName(SysMgr.pid)
            exeName = os.path.basename(exePath)
            libName = "lib%s" % exeName
            if not load:
                return libName

            # search ld.so.cache #
            if not SysMgr.pyLibPath:
                SysMgr.pyLibPath = SysMgr.findLib(libName, inc=True)[0]
            # search standard path #
            else:
                libName = SysMgr.loadLib(libName)._name
                if libName:
                    SysMgr.pyLibPath = FileAnalyzer.getMapFilePath(
                        SysMgr.pid, libName
                    )

            return SysMgr.pyLibPath
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn(
                "failed to get path for python library", reason=True
            )

    @staticmethod
    def getExeName(pid, verb=True):
        # use psutil #
        if not SysMgr.isLinux:
            try:
                psutil = SysMgr.getPkg("psutil", False)
                if psutil:
                    return psutil.Process(long(pid)).exe()
                else:
                    return None
            except SystemExit:
                sys.exit(0)
            except:
                return None

        try:
            exePath = "%s/%s/exe" % (SysMgr.procPath, pid)
            return os.readlink(exePath)
        except SystemExit:
            sys.exit(0)
        except:
            if verb:
                SysMgr.printWarn(
                    "failed to get binary path for %s process" % pid,
                    reason=True,
                )
            return None

    @staticmethod
    def getPyPath():
        return os.path.realpath(__file__)

    @staticmethod
    def getCmdline(pid, retList=False):
        # use psutil #
        if not SysMgr.isLinux:
            try:
                psutil = SysMgr.getPkg("psutil", False)
                if not psutil:
                    raise Exception()

                cmdline = psutil.Process(long(pid)).cmdline()
                if retList:
                    return cmdline
                else:
                    return " ".join(cmdline)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn(
                    "failed to get cmdline for task %s" % pid, reason=True
                )
                if retList:
                    return []
                else:
                    return ""

        cmdlinePath = "%s/%s/cmdline" % (SysMgr.procPath, pid)

        try:
            with open(cmdlinePath, "r") as fd:
                res = fd.readline()
                if retList:
                    return res.split("\x00")
                else:
                    return res.replace("\x00", " ").strip()
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenWarn(cmdlinePath)
            if retList:
                return []
            else:
                return ""

    @staticmethod
    def getTracerId(pid):
        try:
            statusPath = "%s/%s/status" % (SysMgr.procPath, pid)
            with open(statusPath, "r") as fd:
                for line in fd.readlines():
                    if line.startswith("TracerPid"):
                        return long(line.split(":")[1].split()[0])
        except SystemExit:
            sys.exit(0)
        except:
            return 0

    @staticmethod
    def getUid(pid, itype="real"):
        try:
            path = "%s/status" % pid
            data = SysMgr.procReadlines(path)

            for line in data:
                if line.startswith("Uid"):
                    if itype == "real":
                        idx = 0
                    elif itype == "effective":
                        idx = 1
                    elif itype == "saved":
                        idx = 2
                    elif itype == "filesystem":
                        idx = 3

                    return long(line.split(":")[1].split()[idx])
        except SystemExit:
            sys.exit(0)
        except:
            comm = SysMgr.getComm(pid)
            SysMgr.printErr(
                "failed to get UID for %s(%s)" % (comm, pid), reason=True
            )

        return 0

    @staticmethod
    def getPpid(pid):
        statusPath = "%s/%s/status" % (SysMgr.procPath, pid)
        try:
            with open(statusPath, "r") as fd:
                for line in fd.readlines():
                    if line.startswith("PPid"):
                        return line.split(":")[1].split()[0]
        except SystemExit:
            sys.exit(0)
        except:
            return None

    @staticmethod
    def getTgid(pid):
        statusPath = "%s/%s/status" % (SysMgr.procPath, pid)
        try:
            with open(statusPath, "r") as fd:
                for line in fd.readlines():
                    if line.startswith("Tgid"):
                        return line.split(":")[1].split()[0]
        except SystemExit:
            sys.exit(0)
        except:
            return None

    @staticmethod
    def resizeShm(shm, size):
        mmap = SysMgr.getPkg("mmap", False)
        if not mmap:
            return

        mmap.resize(size)

    @staticmethod
    def createShm(path=None, size=PAGESIZE):
        if not SysMgr.isLinux:
            return

        mmap = SysMgr.getPkg("mmap", False)
        if not mmap:
            return

        # create a memory segment #
        mem = mmap.mmap(-1, size)

        # initialize the memory #
        if sys.version_info < (3, 0, 0):
            mem.write(bytes("0") * size)

        return mem

    @staticmethod
    def getCommList(pidList):
        try:
            commList = [
                "%s(%s)" % (SysMgr.getComm(pid), pid) for pid in pidList
            ]
            return ", ".join(commList)
        except SystemExit:
            sys.exit(0)
        except:
            return ", ".join(pidList)

    @staticmethod
    def getFdName(pid, fd):
        if not SysMgr.isLinux:
            return None

        try:
            fdPath = "%s/%s/fd/%s" % (SysMgr.procPath, pid, fd)
            return os.readlink(fdPath)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn(
                "failed to read file name from fd(%s) for %s(%s)"
                % (fd, SysMgr.getComm(pid), pid),
                reason=True,
            )
            return None

    @staticmethod
    def getPwd(pid):
        if not SysMgr.isLinux:
            try:
                psutil = SysMgr.getPkg("psutil", False)
                if psutil:
                    return psutil.Process(long(pid)).environ()["PWD"]
                else:
                    return None
            except SystemExit:
                sys.exit(0)
            except:
                return None

        try:
            pwdPath = "%s/%s/cwd" % (SysMgr.procPath, pid)
            pwd = os.readlink(pwdPath)
        except SystemExit:
            sys.exit(0)
        except:
            return None

        return pwd

    @staticmethod
    def getComm(pid, cache=False, save=False):
        if pid in SysMgr.commCache:
            return SysMgr.commCache[pid]

        # linux #
        try:
            if pid in SysMgr.commFdCache:
                fd = SysMgr.commFdCache[pid]
                fd.seek(0)
                comm = fd.readlines()[0][:-1]
                if save:
                    SysMgr.commCache[pid] = comm
                return comm
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # use psutil #
        if not SysMgr.isLinux:
            try:
                psutil = SysMgr.getPkg("psutil", False)
                if psutil:
                    return psutil.Process(long(pid)).name()
                else:
                    return None
            except SystemExit:
                sys.exit(0)
            except:
                return None

        comm = None
        commPath = "%s/%s/comm" % (SysMgr.procPath, pid)

        try:
            fd = open(commPath, "r")

            comm = fd.readline()[:-1]

            # cache comm #
            if save:
                SysMgr.commCache[pid] = comm

            # flush fd cache #
            if SysMgr.maxKeepFd < fd.fileno():
                SysMgr.commFdCache = {}
            # cache fd #
            elif cache:
                SysMgr.commFdCache[pid] = fd
            else:
                fd.close()
        except SystemExit:
            sys.exit(0)
        except:
            return None

        return comm

    @staticmethod
    def getPyConfig(item="all", var=None):
        # pylint: disable=undefined-variable
        try:
            SysMgr.importPkgItems("sysconfig")

            if item == "path":
                varDict = get_paths()
            else:
                varDict = get_config_vars()

            if var:
                return varDict[var]
            else:
                return varDict
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("failed to get python config", True, True)
            return None

    @staticmethod
    def getMyBacktrace():
        # load libc #
        SysMgr.loadLibcObj(exit=True)

        # define functions #
        libcObj = SysMgr.libcObj

        libcObj.backtrace.argtypes = [c_void_p, c_int]
        libcObj.backtrace.restype = c_int

        libcObj.backtrace_symbols.argtypes = [c_void_p, c_int]
        libcObj.backtrace_symbols.restype = POINTER(c_char_p)

        # define buffers #
        buf = (c_void_p * 1024)()

        # call backtrace #
        ret = libcObj.backtrace(byref(buf), c_int(1024))
        syms = libcObj.backtrace_symbols(byref(buf), c_int(ret))

        sys.exit(0)

    @staticmethod
    def isBlkDev(path):
        stat = SysMgr.getPkg("stat")

        try:
            return stat.S_ISBLK(os.stat(path).st_mode)
        except:
            return False

    @staticmethod
    def dlopen(path):
        # load libc #
        if not SysMgr.loadLibcObj():
            return

        try:
            path = path.encode()
        except:
            pass

        try:
            func = "__libc_dlopen_mode"
            funcp = getattr(SysMgr.libcObj, func)
            funcp.argtypes = [c_void_p, c_int]
            funcp.restype = c_ulong
            return funcp(path, 1)
        except:
            SysMgr.printErr("failed to call dlopen", reason=True)
            return None

    @staticmethod
    def setComm(comm):
        if not SysMgr.isLinux:
            return

        # try to set comm using native lib #
        try:
            SysMgr.guiderObj.prctl(
                15, comm, 0, 0, 0
            )  # pylint: disable=no-member
            return
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # load libc #
        if not SysMgr.loadLibcObj():
            return

        try:
            SysMgr.libcObj.prctl(15, c_char_p(comm.encode("utf-8")), 0, 0, 0)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn(
                "failed to set comm to '%s'" % comm, True, reason=True
            )

    @staticmethod
    def getPicklePkg(isExit=True):
        pickle = SysMgr.getPkg("cPickle", isExit)
        if not pickle:
            pickle = SysMgr.getPkg("pickle", isExit)
            if not pickle:
                return None
        return pickle

    @staticmethod
    def invalidateFile(path=None, fd=None, pos=0, size=0):
        try:
            if path:
                f = open(path, "br")
                fd = f.fileno()
            elif not fd:
                SysMgr.printErr(
                    "failed to invalidate file because neither path nor fd"
                )
                sys.exit(0)

            # get whole file size #
            if size == 0:
                size = os.fstat(fd).st_size

            os.posix_fadvise(fd, pos, size, os.POSIX_FADV_DONTNEED)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to invalidate '%s'" % path, True)

    @staticmethod
    def isAlive(tid):
        try:
            statPath = "%s/%s/stat" % (SysMgr.procPath, tid)
            with open(statPath, "r") as fd:
                stat = fd.read()

            # convert string to list #
            statList = stat.split(") ", 1)[1].split()

            if statList[0] == "Z":
                return False
            else:
                return True
        except SystemExit:
            sys.exit(0)
        except:
            return False

    @staticmethod
    def getPkg(name, isExit=True, isTemp=False, isRoot=True):
        # check cache #
        try:
            return SysMgr.impPkg[name]
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # check blacklist #
        if not isExit and name in SysMgr.skipImpPkg:
            return None

        # import package #
        try:
            obj = __import__(name, fromlist=[name] if isRoot else [None])
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn(
                "failed to import python package: %s " % name, isExit
            )

            # register to blacklist #
            SysMgr.skipImpPkg[name] = True

            # check return condition #
            if isExit:
                sys.exit(-1)
            return None

        # save package object #
        if not isTemp:
            SysMgr.impPkg[name] = obj

        return obj

    @staticmethod
    def getIowaitTime(dev=None):
        if not SysMgr.diskStats or not SysMgr.prevDiskStats:
            return "0/0"

        flist = {}
        dlist = {}
        curReadMsTotal = prevReadMsTotal = 0
        curWriteMsTotal = prevWriteMsTotal = 0
        curNrReadTotal = prevNrReadTotal = 0
        curNrWriteTotal = prevNrWriteTotal = 0
        curIoMsTotal = prevIoMsTotal = 0
        curWIoMsTotal = prevWIoMsTotal = 0

        # get total iowait time for read #
        for line in SysMgr.diskStats:
            items = line.split()
            dev = items[2]

            if not dev[-1].isdigit():
                flist[dev] = None
            else:
                skip = False
                for item in flist:
                    if item != dev and dev.startswith(item):
                        skip = True

                if skip:
                    continue

            dlist[dev] = {}
            dlist[dev]["curNrRead"] = long(items[3])
            dlist[dev]["curNrWrite"] = long(items[7])
            dlist[dev]["curReadMs"] = long(items[6])
            dlist[dev]["curWriteMs"] = long(items[10])
            dlist[dev]["curIoMs"] = long(items[12])
            dlist[dev]["curWIoMs"] = long(items[13])

            curNrReadTotal += long(items[3])
            curNrWriteTotal += long(items[7])
            curReadMsTotal += long(items[6])
            curWriteMsTotal += long(items[10])
            curIoMsTotal += long(items[12])
            curWIoMsTotal += long(items[13])

        # get total iowait time for write #
        for line in SysMgr.prevDiskStats:
            items = line.split()
            dev = items[2]

            skip = False
            for item in flist:
                if item != dev and dev.startswith(item):
                    skip = True

            if skip:
                continue

            dlist[dev]["prevNrRead"] = long(items[3])
            dlist[dev]["prevNrWrite"] = long(items[7])
            dlist[dev]["prevReadMs"] = long(items[6])
            dlist[dev]["prevWriteMs"] = long(items[10])
            dlist[dev]["prevIoMs"] = long(items[12])
            dlist[dev]["prevWIoMs"] = long(items[13])

            prevNrReadTotal += long(items[3])
            prevNrWriteTotal += long(items[7])
            prevReadMsTotal += long(items[6])
            prevWriteMsTotal += long(items[10])
            prevIoMsTotal += long(items[12])
            prevWIoMsTotal += long(items[13])

        for dev, stat in dlist.items():
            read = stat["curNrRead"] - stat["prevNrRead"]
            write = stat["curNrWrite"] - stat["prevNrWrite"]
            io = read + write

        readMsTotal = curReadMsTotal - prevReadMsTotal
        writeMsTotal = curWriteMsTotal - prevWriteMsTotal

        """
        nrReadTotal = curNrReadTotal - prevNrReadTotal
        nrWriteTotal = curNrWriteTotal - prevNrWriteTotal
        ioMsTotal = curIoMsTotal - prevIoMsTotal
        wIoMsTotal = curWIoMsTotal - prevWIoMsTotal
        """

        retstr = "%s/%s" % (
            UtilMgr.convSize2Unit(readMsTotal),
            UtilMgr.convSize2Unit(writeMsTotal),
        )

        return retstr

    def updateNodeInfo(self):
        if self.devNodeInfo:
            return

        try:
            nodePath = "/dev/block"
            for item in os.listdir(nodePath):
                path = os.path.join(nodePath, item)
                if os.path.islink(path):
                    path = os.path.realpath(
                        os.path.join(nodePath, os.readlink(path))
                    )
                self.devNodeInfo[item] = path
        except SystemExit:
            sys.exit(0)
        except:
            pass

    @staticmethod
    def updateDiskStats():
        try:
            SysMgr.diskStatsFd.seek(0)
            SysMgr.prevDiskStats = SysMgr.diskStats
            SysMgr.diskStats = SysMgr.diskStatsFd.readlines()
        except SystemExit:
            sys.exit(0)
        except:
            try:
                diskstatPath = "%s/diskstats" % SysMgr.procPath
                SysMgr.diskStatsFd = open(diskstatPath, "r")
                SysMgr.diskStats = SysMgr.diskStatsFd.readlines()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenWarn(diskstatPath)

    @staticmethod
    def getMountData(pid="self"):
        try:
            if pid != "self":
                raise Exception()

            SysMgr.mountFd.seek(0)
            return SysMgr.mountFd.readlines()
        except SystemExit:
            sys.exit(0)
        except:
            try:
                mountPath = "%s/%s/mountinfo" % (SysMgr.procPath, pid)
                mountFd = open(mountPath, "r")
                if pid == "self":
                    SysMgr.mountFd = mountFd
                return mountFd.readlines()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenWarn(mountPath)

    @staticmethod
    def convMemStat(mlist):
        vssIdx = ConfigMgr.STATM_TYPE.index("TOTAL")
        rssIdx = ConfigMgr.STATM_TYPE.index("RSS")
        return {
            "vss": long(mlist[vssIdx]) << 12,
            "rss": long(mlist[rssIdx]) << 12,
        }

    @staticmethod
    def getMemStat(pid):
        try:
            statmPath = "%s/%s/statm" % (SysMgr.procPath, pid)
            with open(statmPath, "r") as fd:
                return fd.readlines()[0].split()
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenWarn(statmPath)
            return

    @staticmethod
    def getPidFilter(name="common_pid", comm=True, force=True):
        if SysMgr.pidFilter and force:
            return SysMgr.pidFilter

        cmd = ""
        for cond in list(SysMgr.filterGroup):
            try:
                # add comm #
                if comm:
                    cmd += """%scomm == "*%s*" || """ % (cmd, cond)

                # just PID #
                if cond.isdigit():
                    cmd += "%s == %s || " % (name, long(cond))
                # PID bigger or lesser #
                elif cond.startswith(">") or cond.endswith("<"):
                    cmd += "%s >= %s || " % (name, long(cond.strip("<>")))
                    continue
                # PID bigger or lesser #
                elif cond.startswith("<") or cond.endswith(">"):
                    cmd += "%s <= %s || " % (name, long(cond.strip("<>")))
                    continue
            except SystemExit:
                sys.exit(0)
            except:
                pass

        if cmd != "":
            cmd = "(" + cmd[: cmd.rfind("||")] + ")"

        if force:
            SysMgr.pidFilter = cmd

        return cmd

    @staticmethod
    def isExceptTarget(tid, tdata, comm=None, plist=[]):
        tlist = SysMgr.filterGroup

        # check filter #
        if tlist == []:
            return False

        # get comm #
        if not comm:
            comm = tdata[tid]["comm"]

        # check a thread #
        for item in tlist:
            if (
                item == tid
                or item == ""
                or SysMgr.isValidTid(tid, item)
                or UtilMgr.isValidStr(item, [comm])
            ):
                return False

        # check all threads in a same process #
        if SysMgr.groupProcEnable:
            tgid = tdata[tid]["tgid"]

            # check tgid in process list by tid #
            if str(tgid) in plist:
                return False

            # check tgid in filter list by tid #
            for item in tlist:
                try:
                    if item == tgid or SysMgr.isValidTid(tgid, item):
                        return False
                    elif tgid == "0" or tgid.startswith("-"):
                        continue
                    elif (
                        tgid == tdata[item]["tgid"]
                        or tgid == SysMgr.savedProcTree[item]
                    ):
                        return False
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

        return True

    @staticmethod
    def getTraceItem(string):
        if SysMgr.tgidEnable:
            # record-tgid option #
            m = re.match(
                (
                    r"^\s*(?P<comm>\S+)-(?P<thread>[0-9]+)\s+"
                    r"\[(?P<core>[0-9]+)\]\s+\(\s*(?P<tgid>.+)\)\s+"
                    r"(?P<time>\S+):\s+(?P<func>\S+)(?P<etc>.+)"
                ),
                string,
            )
            if not m:
                # print-tgid option #
                m = re.match(
                    (
                        r"^\s*(?P<comm>.+)-(?P<thread>[0-9]+)\s+"
                        r"\(\s*(?P<tgid>\S+)\)\s+\[(?P<core>[0-9]+)\]\s+"
                        r"(?P<time>\S+):\s+(?P<func>\S+)(?P<etc>.+)"
                    ),
                    string,
                )

            return m

        m = re.match(
            (
                r"^\s*(?P<comm>.+)-(?P<thread>[0-9]+)\s+\[(?P<core>[0-9]+)\]"
                r"\s+(?P<time>\S+):\s+(?P<func>\S+)(?P<etc>.+)"
            ),
            string,
        )

        return m

    @staticmethod
    def isValidEnableOption(options):
        if not options:
            return False

        optionList = "BCDEFGHILMNPRSTWYabcdefghijklmnopqrrstuvwxy"
        for opt in options:
            if not opt in optionList:
                return False

        return True

    @staticmethod
    def isValidOption(option):
        optionList = "ABCDEFGHIJKLMNOPQRSTUWXYZabcdefgijklmnopqrstuvwxy"
        if option in optionList:
            return True
        elif option.isdigit():
            return True
        else:
            return False

    @staticmethod
    def isValidTid(tid, cond):
        try:
            tid = long(tid)

            ldir = cond.find(">")
            if ldir == 0 and tid >= long(cond[1:]):
                return True
            elif ldir == len(cond) - 1 and tid <= long(cond[:-1]):
                return True

            rdir = cond.find("<")
            if rdir == 0 and tid <= long(cond[1:]):
                return True
            elif rdir == len(cond) - 1 and tid >= long(cond[:-1]):
                return True

            if tid == cond or tid == long(cond):
                return True

            return False
        except SystemExit:
            sys.exit(0)
        except:
            return False

    @staticmethod
    def printBacktrace():
        traceback = SysMgr.getPkg("traceback")
        traceback.print_stack(file=SysMgr.stderr)

    @staticmethod
    def waitEvent(ignChldSig=True, exit=False, forceExit=False, block=True):
        # ignore SIGCHLD #
        if ignChldSig:
            signal.signal(signal.SIGCHLD, signal.SIG_IGN)

        # backup SIGINT handler and set new handler #
        if SysMgr.waitEnable and block:
            handle = signal.getsignal(signal.SIGINT)
            signal.signal(signal.SIGINT, SysMgr.defaultHandler)

        # pause task #
        try:
            signal.pause()
        except SystemExit:
            if exit:
                sys.exit(0)
            elif forceExit:
                os._exit(0)
        except:
            pass

        # restore SIGINT handler #
        if SysMgr.waitEnable and block:
            signal.signal(signal.SIGINT, handle)

    @staticmethod
    def backupFile(origFile):
        if not origFile or not os.path.isfile(origFile):
            return None

        try:
            newFile = "%s.old" % origFile

            # delete old backup file #
            if os.path.exists(newFile):
                os.remove(newFile)

            # rename old target file #
            os.rename(origFile, newFile)
            os.chmod(newFile, 0o777)

            SysMgr.printInfo(
                "renamed '%s' to '%s' for backup" % (origFile, newFile)
            )

            return newFile
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to backup '%s' to '%s'" % (origFile, newFile), True
            )
            return None

    @staticmethod
    def convRealPath(flist):
        if UtilMgr.isString(flist):
            flist = [flist]

        nlist = []
        for fpath in flist:
            fpath = fpath.strip()

            # check exception character #
            if fpath.startswith("^"):
                fpath = fpath[1:]
                exflag = True
            else:
                exflag = False

            # check files #
            items = UtilMgr.convPath(fpath, warn=False)
            for path in items:
                try:
                    rpath = os.path.realpath(path)
                    if not rpath.startswith("/"):
                        dirname = os.path.dirname(path)
                        rpath = os.path.join(dirname, rpath)
                        rpath = os.path.realpath(rpath)

                    if exflag:
                        rpath = "^" + rpath

                    nlist.append(rpath)
                except SystemExit:
                    sys.exit(0)
                except:
                    if os.path.exists(path):
                        if exflag:
                            path = "^" + path

                        nlist.append(path)
                    else:
                        SysMgr.printWarn(
                            "failed to convert '%s' to real path" % path,
                            reason=True,
                            always=True,
                        )

        return nlist

    @staticmethod
    def getErrReason():
        # pylint: disable=not-callable
        if not SysMgr.geterrnoFunc:
            # load libc #
            ret = SysMgr.loadLibcObj()
            if not ret:
                SysMgr.geterrnoFunc = -1
                return "N/A"

            # check function #
            if not hasattr(SysMgr.libcObj, "__errno_location"):
                SysMgr.geterrnoFunc = -1
                return "N/A"

            # define function #
            SysMgr.geterrnoFunc = getattr(SysMgr.libcObj, "__errno_location")
            SysMgr.geterrnoFunc.restype = POINTER(c_int)

        # check again #
        if SysMgr.geterrnoFunc == -1:
            return "N/A"

        # error code #
        try:
            num = SysMgr.geterrnoFunc()[0]
            if num == 0:
                return "N/A"
            elif not num in errno.errorcode:
                raise Exception("no errorno")
            code = errno.errorcode[num]
            return "%s (%s)" % (code, os.strerror(num))
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("failed to get error reason", reason=True)
            return "N/A"

    @staticmethod
    def getProcTree():
        procTree = {}

        # get process list in proc filesystem #
        pids = SysMgr.getPidList()
        for pid in pids:
            try:
                long(pid)
            except SystemExit:
                sys.exit(0)
            except:
                continue

            # make path of tid #
            procPath = "%s/%s" % (SysMgr.procPath, pid)
            taskPath = "%s/%s" % (procPath, "task")

            # update comm of main thread #
            comm = SysMgr.getComm(pid, save=True)

            try:
                tids = os.listdir(taskPath)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenWarn(taskPath)
                continue

            for tid in tids:
                try:
                    # main task #
                    if tid == pid:
                        procTree[tid] = "%s(%s)" % (pid, comm)
                    # sibling task #
                    else:
                        # update comm of thread #
                        SysMgr.getComm(tid, save=True)

                        procTree[tid] = pid
                except SystemExit:
                    sys.exit(0)
                except:
                    continue

        return procTree

    @staticmethod
    def setSortValue(values):
        if not values:
            value = cond = None
        else:
            values = values.split(":")
            if len(values) == 1:
                value = values[0]
                cond = None
            elif len(values) > 1:
                value, cond = values[:2]

        if value == "c":
            SysMgr.printInfo("sorted by CPU")
        elif value == "N":
            SysMgr.printInfo("sorted by NAME")
        elif value == "m":
            SysMgr.printInfo("sorted by MEMORY")
        elif value == "b":
            SysMgr.printInfo("sorted by BLOCK")
            if SysMgr.checkDiskTopCond():
                SysMgr.blockEnable = True
            else:
                sys.exit(-1)
        elif value == "w":
            SysMgr.printInfo("sorted by CHILD")
            SysMgr.wfcEnable = True
        elif value == "p":
            SysMgr.printInfo("sorted by PID")
        elif value == "n":
            SysMgr.printInfo("sorted by NEW")
        elif value == "e":
            SysMgr.printInfo("sorted by EXECTIME")
            SysMgr.schedEnable = True
        elif value == "d":
            SysMgr.printInfo("sorted by DELAY")
            SysMgr.schedEnable = True
        elif value == "r":
            SysMgr.printInfo("sorted by RUNTIME")
        elif value == "o":
            SysMgr.printInfo("sorted by OOMSCORE")
            TaskAnalyzer.setLastField("oom")
        elif value == "P":
            SysMgr.printInfo("sorted by PRIORITY")
        elif value == "f":
            SysMgr.printInfo("sorted by FILE")
            SysMgr.fileTopEnable = True
        elif value == "s":
            SysMgr.printInfo("sorted by SWAP")
        elif value == "C":
            if not SysMgr.checkMode("ttop"):
                SysMgr.printErr(
                    "failed to sort by CONTEXTSWITCH because "
                    "it is supported on thread mode"
                )
                sys.exit(-1)
            SysMgr.printInfo("sorted by CONTEXTSWITCH")
        elif not value:
            value = None
        elif SysMgr.checkMode("printslab"):
            pass
        else:
            SysMgr.printErr("wrong option value '%s' for sort" % value)
            return False

        # set values #
        SysMgr.sort = value
        if cond and len(cond) > 1:
            if cond[0] == ">":
                SysMgr.sortCondOp = ">"
                cond = cond[1:]
            elif cond[0] == "<":
                SysMgr.sortCondOp = "<"
                cond = cond[1:]
        SysMgr.sortCond = cond

        return True

    @staticmethod
    def readMemoryMap():
        try:
            res = {}
            lines = SysMgr.procReadlines("iomem")
            for item in lines:
                addrs, name = item.split(":", 1)
                start, end = UtilMgr.cleanItem(
                    addrs.rstrip().split("-"), False
                )
                startaddr = long(start, 16)
                size = long(end, 16) - startaddr
                sizeUnit = "%s (%7s)" % (
                    UtilMgr.convNum(size),
                    UtilMgr.convSize2Unit(size),
                )

                res[startaddr] = {
                    "name": name.strip(),
                    "start": start,
                    "end": end,
                    "size": size,
                    "sizeUnit": sizeUnit,
                }
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("failed to read memory map", reason=True)

        return res

    @staticmethod
    def readSchedFeatures():
        try:
            path = "/sys/kernel/debug/sched_features"
            fd = open(path, "r")
            return sorted(fd.readline().split())
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenWarn(path)
            return []

    @staticmethod
    def readProcData(tid, path, num=-1):
        path = "%s/%s/%s" % (SysMgr.procPath, tid, path)

        try:
            f = open(path, "r")
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenErr(path)
            return None

        if num == -1:
            return f.readlines()
        elif num == 0:
            return f.readline().replace("\n", "")
        else:
            return f.readline().replace("\n", "").split()[num - 1]

    @staticmethod
    def hasMainArg(dash=False):
        if len(sys.argv) <= 2 or (not dash and sys.argv[2].startswith("-")):
            return False
        else:
            return True

    @staticmethod
    def getMainArgs(union=True, token=",", path=False):
        args = SysMgr.getMainArg(path)
        if type(args) is not list:
            args = args.split(token)
        return UtilMgr.cleanItem(args, union)

    @staticmethod
    def getMainArg(path=False):
        if len(sys.argv) <= 2:
            return None
        elif not path:
            return sys.argv[2]
        else:
            return UtilMgr.convPath(sys.argv[2], retStr=True, separator=",")

    @staticmethod
    def checkEnv():
        def _checkMode():
            # check args #
            if len(sys.argv) == 1:
                return True

            # get command #
            cmd = sys.argv[1]

            # common commands for all OS #
            if cmd in (
                "addr2sym",
                "bgtop",
                "cli",
                "comp",
                "convert",
                "cputest",
                "ctop",
                "decomp",
                "disktop",
                "drawreq",
                "exec",
                "flush",
                "iotest",
                "list",
                "mkcache",
                "ntop",
                "ping",
                "print",
                "printdir",
                "printext",
                "pstree",
                "readelf",
                "report",
                "req",
                "rtop",
                "strings",
                "sym2addr",
                "tail",
                "top",
                "topdiff",
                "topsum",
            ):
                return True
            # only commands for MacOS #
            elif SysMgr.isDarwin and cmd in (
                "dlttop",
                "ftop",
                "kill",
                "printdlt",
                "server",
            ):
                return True
            # specific commands for all OS #
            elif SysMgr.isDrawMode() or SysMgr.isHelpMode():
                return True

            return False

        # Linux #
        if sys.platform.startswith("linux"):
            SysMgr.isLinux = True

            # environment variables #
            try:
                # set default terminal to xterm #
                os.environ["TERM"] = "xterm"

                # set run type #
                if "REMOTERUN" in os.environ:
                    SysMgr.encodeEnable = False
                    SysMgr.remoteRun = True
                    SysMgr.colorEnable = False
                else:
                    SysMgr.colorEnable = True

                # check encode condition #
                if not "LANG" in os.environ or "tty" in os.ttyname(
                    sys.stdout.fileno()
                ):
                    SysMgr.encodeEnable = False
            except SystemExit:
                sys.exit(0)
            except:
                pass

            # set force color flag #
            SysMgr.forceColorEnable = SysMgr.isTraceMode()

            # android #
            if "ANDROID_ROOT" in os.environ and not "NO_ANDROID" in os.environ:
                SysMgr.isAndroid = True
                SysMgr.libcPath = "libc"
                SysMgr.libcppPath = "libstdc++"
                SysMgr.libdemanglePath = "libgccdemangle"
                SysMgr.cacheDirPath = "/data/log/guider"

        # Windows #
        elif sys.platform.startswith("win"):
            SysMgr.isLinux = False
            SysMgr.isWindows = True

            if len(sys.argv) == 1:
                pass
            elif not _checkMode():
                SysMgr.printErr(
                    "'%s' is not supported on '%s' platform"
                    % (sys.argv[1], sys.platform)
                )
                sys.exit(-1)

            # set default SIGINT handler #
            signal.signal(signal.SIGINT, SysMgr.stopHandler)

            # set color flag #
            SysMgr.colorEnable = False

        # MacOS #
        elif sys.platform.startswith("darwin"):
            SysMgr.isLinux = False
            SysMgr.isDarwin = True
            ConfigMgr.SIG_LIST = ConfigMgr.SIG_LIST_MACOS

            if len(sys.argv) == 1:
                pass
            elif not _checkMode():
                SysMgr.printErr(
                    "'%s' is not supported on '%s' platform"
                    % (sys.argv[1], sys.platform)
                )
                sys.exit(-1)

            # set color flag #
            SysMgr.colorEnable = True
        else:
            SysMgr.printErr("'%s' platform is not supported" % sys.platform)
            sys.exit(-1)

        # check locale #
        try:
            if not SysMgr.encodeEnable:
                pass
            elif "NO_ENCODE" in os.environ:
                SysMgr.encodeEnable = False
            else:
                lang = os.getenv("LANG")
                if not lang or not "UTF" in lang:
                    SysMgr.encodeEnable = False
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # check python #
        if sys.version_info < (2, 6):
            SysMgr.printWarn(
                "some features may not work on python %d.%d"
                % (sys.version_info[0], sys.version_info[1]),
                True,
            )

    @staticmethod
    def onAlarmExit(signum, frame):
        SysMgr.updateTimer()

        sys.exit(0)

    @staticmethod
    def onAlarm(signum, frame):
        SysMgr.progressCnt += 1
        if SysMgr.repeatCount <= SysMgr.progressCnt:
            SysMgr.printWarn("terminated by timer\n", True)
            sys.exit(0)

        SysMgr.updateTimer()

    @staticmethod
    def checkProgress():
        if not SysMgr.countEnable:
            return

        # check uptime deadline #
        exitCond = SysMgr.progressCnt > 0 and (
            0 < SysMgr.deadlineUptime <= SysMgr.uptime
            or 0 < SysMgr.exitCondCpuMore <= SysMgr.cpuUsage
            or 0 < SysMgr.exitCondCpuLess >= SysMgr.cpuUsage
            or 0 < SysMgr.exitCondMemMore <= SysMgr.memAvail
            or 0 < SysMgr.exitCondMemLess >= SysMgr.memAvail
        )

        # check reason #
        if exitCond:
            reason = "condition"
        elif SysMgr.progressCnt >= SysMgr.repeatCount > 0:
            reason = "timer"
        else:
            reason = None

        if reason:
            # remove progress #
            UtilMgr.deleteProgress()

            # send signal to myself #
            try:
                SysMgr.printWarn("terminated by %s\n" % reason, True)
                os.kill(SysMgr.pid, signal.SIGINT)
                os.kill(SysMgr.pid, signal.SIGKILL)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printSigError(SysMgr.pid, "SIGINT")

        if SysMgr.repeatCount > 1:
            UtilMgr.printProgress(SysMgr.progressCnt, SysMgr.repeatCount)

        SysMgr.progressCnt += 1

    @staticmethod
    def getCmdString():
        cmdList = SysMgr.getCmdList()

        cmdbuf = ""
        for ctype, tvalue in sorted(cmdList.items()):
            prefix = ctype
            for cmd, cvalue in sorted(tvalue.items()):
                if prefix:
                    types = "[%s]" % prefix.upper()
                else:
                    types = " "

                cmdbuf = "%s%4s%-12s%4s%-14s%4s%-15s (%-s)\n" % (
                    cmdbuf,
                    " ",
                    types,
                    " ",
                    cmd,
                    " ",
                    "<%s>" % cvalue[0],
                    cvalue[1],
                )
                prefix = ""
            cmdbuf = "%s\n" % cmdbuf

        return cmdbuf[:-1]

    @staticmethod
    def getCmdList():
        return {
            "monitor": {
                "atop": ("All", "Linux"),
                "bgtop": ("Background", "Linux/MacOS/Windows"),
                "btop": ("Function", "Linux"),
                "cgtop": ("Cgroup", "Linux"),
                "ctop": ("Threshold", "Linux/MacOS/Windows"),
                "dbustop": ("D-Bus", "Linux"),
                "disktop": ("Storage", "Linux/MacOS/Windows"),
                "dlttop": ("DLT", "Linux/MacOS"),
                "ftop": ("File", "Linux/MacOS"),
                "ktop": ("Function", "Linux"),
                "mtop": ("Memory", "Linux"),
                "ntop": ("Network", "Linux/MacOS/Windows"),
                "ptop": ("PMU", "Linux"),
                "pytop": ("Python", "Linux"),
                "rtop": ("JSON", "Linux/MacOS/Windows"),
                "slabtop": ("Slab", "Linux"),
                "stacktop": ("Stack", "Linux"),
                "systop": ("Syscall", "Linux"),
                "top": ("Process", "Linux/MacOS/Windows"),
                "ttop": ("Thread", "Linux"),
                "utop": ("Function", "Linux"),
                "vtop": ("Memory", "Linux"),
                "wtop": ("WSS", "Linux"),
            },
            "trace": {
                "btrace": ("Function", "Linux"),
                "leaktrace": ("Leak", "Linux"),
                "pytrace": ("Python", "Linux"),
                "sigtrace": ("Signal", "Linux"),
                "strace": ("Syscall", "Linux"),
                "utrace": ("Function", "Linux"),
            },
            "profile": {
                "filerec": ("File", "Linux"),
                "funcrec": ("Function", "Linux"),
                "genrec": ("System", "Linux"),
                "iorec": ("I/O", "Linux"),
                "mem": ("Page", "Linux"),
                "rec": ("Thread", "Linux"),
                "report": ("Report", "Linux"),
                "sysrec": ("Syscall", "Linux"),
            },
            "visual": {
                "convert": ("Text", "Linux/MacOS/Windows"),
                "draw": ("System", "Linux/MacOS/Windows"),
                "drawavg": ("Average", "Linux/MacOS/Windows"),
                "drawbitmap": ("Bitmap", "Linux/MacOS/Windows"),
                "drawcpu": ("CPU", "Linux/MacOS/Windows"),
                "drawcpuavg": ("CPU", "Linux/MacOS/Windows"),
                "drawdelay": ("Delay", "Linux/MacOS/Windows"),
                "drawflame": ("Function", "Linux/MacOS/Windows"),
                "drawio": ("I/O", "Linux/MacOS/Windows"),
                "drawleak": ("Leak", "Linux/MacOS/Windows"),
                "drawmem": ("Memory", "Linux/MacOS/Windows"),
                "drawmemavg": ("Memory", "Linux/MacOS/Windows"),
                "drawreq": ("URL", "Linux/MacOS/Windows"),
                "drawrss": ("RSS", "Linux/MacOS/Windows"),
                "drawrssavg": ("RSS", "Linux/MacOS/Windows"),
                "drawtime": ("Timeline", "Linux/MacOS/Windows"),
                "drawvss": ("VSS", "Linux/MacOS/Windows"),
                "drawvssavg": ("VSS", "Linux/MacOS/Windows"),
            },
            "control": {
                "freeze": ("Thread", "Linux"),
                "hook": ("Function", "Linux"),
                "kill/tkill": ("Signal", "Linux/MacOS"),
                "limitcpu": ("CPU", "Linux"),
                "pause": ("Thread", "Linux"),
                "remote": ("Command", "Linux"),
                "rlimit": ("Resource", "Linux"),
                "setafnt": ("Affinity", "Linux"),
                "setcpu": ("Clock", "Linux"),
                "setsched": ("Priority", "Linux"),
            },
            "util": {
                "addr2sym": ("Symbol", "Linux/MacOS/Windows"),
                "cgroup": ("Cgroup", "Linux"),
                "comp": ("Compress", "Linux/MacOS/Windows"),
                "decomp": ("Decompress", "Linux/MacOS/Windows"),
                "dump": ("Memory", "Linux"),
                "exec": ("Command", "Linux/MacOS/Windows"),
                "flush": ("Memory", "Linux"),
                "getafnt": ("Affinity", "Linux"),
                "mkcache": ("Cache", "Linux/MacOS/Windows"),
                "mount": ("Mount", "Linux"),
                "ping": ("ICMP", "Linux/MacOS/Windows"),
                "print": ("File", "Linux/MacOS/Windows"),
                "printbind": ("function", "Linux"),
                "printcg": ("Cgroup", "Linux"),
                "printdbus": ("D-Bus", "Linux"),
                "printdbusintro": ("D-Bus", "Linux"),
                "printdbusstat": ("D-Bus", "Linux"),
                "printdbussub": ("D-Bus", "Linux"),
                "printdir": ("Dir", "Linux/MacOS/Windows"),
                "printenv": ("Env", "Linux"),
                "printext": ("Ext4", "Linux/MacOS/Windows"),
                "printinfo": ("System", "Linux"),
                "printkconf": ("kernel", "Linux"),
                "printns": ("Namespace", "Linux"),
                "printsig": ("Signal", "Linux"),
                "printslab": ("Slab", "Linux"),
                "printsvc": ("systemd", "Linux"),
                "printvma": ("Vmalloc", "Linux"),
                "pstree": ("Process", "Linux/MacOS/Windows"),
                "readahead": ("File", "Linux"),
                "readelf": ("File", "Linux/MacOS/Windows"),
                "req": ("URL", "Linux/MacOS/Windows"),
                "strings": ("Text", "Linux/MacOS/Windows"),
                "sym2addr": ("Address", "Linux/MacOS/Windows"),
                "systat": ("Status", "Linux"),
                "topdiff": ("Diff", "Linux/MacOS/Windows"),
                "topsum": ("Summary", "Linux/MacOS/Windows"),
                "umount": ("Unmount", "Linux"),
                "watch": ("File", "Linux"),
            },
            "log": {
                "logdlt": ("DLT", "Linux"),
                "logjrl": ("Journal", "Linux"),
                "logkmsg": ("Kernel", "Linux"),
                "logsys": ("Syslog", "Linux"),
                "printdlt": ("DLT", "Linux/MacOS"),
                "printjrl": ("Journal", "Linux"),
                "printkmsg": ("Kernel", "Linux"),
                "printsys": ("Syslog", "Linux"),
            },
            "network": {
                "cli": ("Client", "Linux/MacOS/Windows"),
                "event": ("Event", "Linux"),
                "list": ("List", "Linux/MacOS/Windows"),
                "send": ("Signal", "Linux"),
                "server": ("Server", "Linux/MacOS"),
                "start": ("Signal", "Linux"),
            },
            "test": {
                "cputest": ("CPU", "Linux/MacOS/Windows"),
                "iotest ": ("Storage", "Linux/MacOS/Windows"),
                "memtest": ("Memory", "Linux/MacOS/Windows"),
                "nettest ": ("Network", "Linux"),
            },
        }

    @staticmethod
    def printHelp(force=False):
        printPipe = SysMgr.printPipe

        # help #
        if force or len(sys.argv) <= 1 or SysMgr.isHelpMode():
            # get environment variable from launcher #
            if "CMDLINE" in os.environ:
                cmd = os.environ["CMDLINE"]
            else:
                cmd = sys.argv[0]

            # remove pyc file extension #
            if ".pyc" in cmd:
                cmd = cmd[: cmd.find(".pyc")]

            # disable extended ascii code support #
            SysMgr.encodeEnable = False

            defStr = """
Usage:
    $ {0:1} COMMAND|FILE [OPTIONS] [--help]
                """.format(
                cmd
            )

            # command help #
            if force or (len(sys.argv) > 1 and SysMgr.isHelpMode()):
                # get command #
                mode = sys.argv[1]

                topCommonStr = """
    -o  <DIR|FILE>              set output path
    -u                          run in the background
    -W  <SEC>                   wait for input
    -f                          force execution
    -b  <SIZE:KB>               set buffer size
    -T  <PROC>                  set process number
    -j  <DIR|FILE>              set report path
    -w  <TIME:FILE{:VALUE}>     set additional command
    -x  <IP:PORT>               set local address
    -X  <REQ@IP:PORT>           set request address
    -N  <REQ@IP:PORT>           set report address
    -S  <CHARACTER{:VALUE}>     sort by key
          [ c:cpu / m:mem / p:pid / N:name / b:block / w:wfc
            n:new / f:file / r:runtime / s:swap / e:exectime
            P:prio / C:contextswitch / o:oomscore ]
    -P                          group threads in a same process
    -I  <CMD|FILE>              set input command or file
    -m  <ROWS:COLS:SYSTEM>      set terminal size
    -a                          show all stats and events
    -g  <COMM|TID{:FILE}>       set task filter
    -i  <SEC>                   set interval
    -R  <INTERVAL:TIME:TERM>    set repeat count
    -C  <PATH>                  set config file
    -c  <CMD>                   set hot command
    -Q                          print all rows in a stream
    -q  <NAME{:VALUE}>          set environment variables
    -J                          print in JSON format
    -L  <PATH>                  set log file
    -l  <TYPE>                  set log type
          [ d:DLT / k:KMSG / j:JOURNAL / s:SYSLOG ]
    -E  <DIR>                   set cache dir
    -H  <LEVEL>                 set function depth level
    -G  <KEYWORD>               set ignore list
    -k  <COMM|TID:SIG{:CONT}>   set signal
    -z  <COMM|TID:MASK{:CONT}>  set CPU affinity
    -Y  <POLICY:PRIO|TIME       set sched
         {:TID|COMM:CONT}>
        <CLASS:{{WHICH:}}PRIO
         :TID|COMM>
    -v                          verbose
                """

                topSubStr = """
Options:
    -e  <CHARACTER>             enable options
          [ a:affinity | b:block | B:bar | c:cpu
            C:compress | d:disk | D:DWARF | e:encode
            E:exec | f:float | F:wfc | G:cgroup
            h:sigHandler | H:sched | i:irq | I:elastic
            l:threshold | L:cmdline | m:mem | M:min
            n:net | N:namespace | o:oomScore
            p:pipe | P:perf | q:quit | r:report
            R:reportFile | s:stack | S:pss| t:thread
            T:total | u:uss | w:wss | W:wchan
            x:fixTarget | Y:delay ]
    -d  <CHARACTER>             disable options
          [ a:memAvailable | A:Average | b:buffer
            B:bar | c:cpu | C:clone | D:DWARF
            e:encode | E:exec | g:general | G:gpu
            L:log | O:color | p:print | t:truncate
            T:task | x:event ]
                """

                jitProfStr = """\
        * Qt:
            - run the target with "QV4_PROFILE_WRITE_PERF_MAP=1" environment variable (version >= 5.6.0)
        * Node:
            - run the target with "--perf-basic-prof" option (version >= 0.11.13, map file growth endlessly)
            - run the target with "--perf-basic-prof-only-functions" option (version >= 4.4.0)
        * Java:
            1. install perf-map-agent
            2. run the target with "-XX:+PreserveFramePointer -XX:+UnlockDiagnosticVMOptions -XX:+DebugNonSafepoints" option
            3. set environment with "export JAVA_HOME=$(readlink -f /usr/bin/java | sed "s:bin/java::")" command
            4. create a map file with "perf-map-agent/bin/create-java-perf-map.sh PID" command
        * Mono:
            - run the target with "--jitmap" option
        * .NET Core:
            - run the target with "COMPlus_PerfMapEnabled=1" environment variable
                """

                drawSubStr = """
Options:
    -e  <CHARACTER>             enable options
          [ d:disk | n:network ]
    -d  <CHARACTER>             disable options
          [ A:average ]
    -g  <COMM|TID{:FILE}>       set task filter
    -o  <DIR>                   set output path
    -a                          show all stats and events
    -T  <NUM>                   set top number
    -L  <RES:PER>               set graph layout (TOTAL PER: 6)
          [ C:CPU | D:Delay | M:Memory | I:IO ]
    -l  <BOUNDARY>              set boundary lines
    -F  [svg/png/pdf/ps/eps]    set image format
    -E  <DIR>                   set cache dir path
    -C  <PATH>                  set config file
    -O  <CORE>                  set core filter
    -q  <NAME{:VALUE}>          set environment variables
    -v                          verbose

Segments:
    Long Color   : Run
    Upper Black  : Wait
    Upper Red    : Preempted
    Lower Purple : Read
    Lower Cyan   : Write
    Horizon Gray : Off
                """

                if SysMgr.checkMode("ttop"):
                    target = "threads"
                else:
                    target = "processes"

                topExamStr = """
Examples:
    - {3:1} {2:2} used CPU resource more than 1% every interval
        # {0:1} {1:1}

    - {3:1} {2:2} having TID 1234 or COMM 1234
        # {0:1} {1:1} -g 1234

    - {3:1} {2:2} newly executed
        # {0:1} {1:1} -I ./a.out

    - {3:1} {2:2} having COMM starting with kworker
        # {0:1} {1:1} -g "kworker*"
        # {0:1} {1:1} -g "*kworker"

    - {3:1} {2:2} with cmdline
        # {0:1} {1:1} -e L
        # {0:1} {1:1} -e L -g apps

    - {3:1} {2:2} except the one having COMM test
        # {0:1} {1:1} -g ^test

    - {3:1} {2:2} using CPU more than 1%
        # {0:1} {1:1} -g -S c:1

    - {3:1} {2:2} used system resource totally
        # {0:1} {1:1} -e T

    - {3:1} all {2:2} on linux, not android
        # NO_ANDROID=1 {0:1} {1:1} -a

    - {3:1} maximum 20 {2:2}
        # {0:1} {1:1} -a -q NRTOPRANK:20

    - {3:1} all {2:2} with specific cores
        # {0:1} {1:1} -e c -O 0:4, 10, 12

    - {3:1} all {2:2} with bar graphs for all cores
        # {0:1} {1:1} -a -e B

    - {3:1} all {2:2} without bar graphs for all cores
        # {0:1} {1:1} -a -d B

    - {3:1} all {2:2} with minimal stats
        # {0:1} {1:1} -a -e M

    - {3:1} all {2:2} after user input
        # {0:1} {1:1} -a -W

    - {3:1} all {2:2} and execute specific commands when terminated
        # {0:1} {1:1} -a -q EXITCMD:"ls -lha"

    - {3:1} all {2:2} and quit when specific {2:2} are terminated
        # {0:1} {1:1} -a -q EXITCONDTERM:"a.out"

    - {3:1} all {2:2} and quit when specific {2:2} are executed
        # {0:1} {1:1} -a -q EXITCONDNEW:"a.out"

    - {3:1} all {2:2} and quit when specific files are found
        # {0:1} {1:1} -a -q EXITCONDFILE:"/tmp/term"

    - {3:1} all {2:2} and quit when specific files are not found
        # {0:1} {1:1} -a -q EXITCONDNOFILE:"/tmp/term"

    - {3:1} all {2:2} and quit when specific functions return true
        # {0:1} {1:1} -a -q EXITCONDFUNC:"/tmp/check.py":"checkFunc":"123"

    - {3:1} all {2:2} after 5 seconds
        # {0:1} {1:1} -a -W 5s

    - {3:1} {2:2} that use CPU more than 1% except for system in a stream
        # {0:1} {1:1} -a -q TASKSTREAM -S c:1

    - {3:1} all {2:2} from 100 seconds of uptime
        # {0:1} {1:1} -a -q STARTCONDTIME:100 -W

    - {3:1} all {2:2} until 100 seconds of uptime
        # {0:1} {1:1} -a -q EXITCONDTIME:100 -R

    - {3:1} all {2:2} with specific condition
        # {0:1} {1:1} -a -q STARTCONDCPUMORE:10 -R
        # {0:1} {1:1} -a -q STARTCONDCPULESS:90 -R
        # {0:1} {1:1} -a -q STARTCONDMEMMORE:1000 -R
        # {0:1} {1:1} -a -q STARTCONDMEMLESS:90 -R
        # {0:1} {1:1} -a -q EXITCONDCPUMORE:10 -R
        # {0:1} {1:1} -a -q EXITCONDCPULESS:90 -R
        # {0:1} {1:1} -a -q EXITCONDMEMMORE:1000 -R
        # {0:1} {1:1} -a -q EXITCONDMEMLESS:90 -R

    - {3:1} all {2:2} with the number of actual file descriptors
        # {0:1} {1:1} -a -q ACTUALFD

    - {3:1} all {2:2} with GPU memory
        # {0:1} {1:1} -a -q GPUMEM
        # {0:1} {1:1} -a -q GPUMEMSUM

    - {3:1} all {2:2} with GPU temperature
        # {0:1} {1:1} -a -q GPUTEMP

    - {3:1} all {2:2} sorted by memory(RSS)
        # {0:1} {1:1} -S m
        # {0:1} {1:1} -S m:500
        # {0:1} {1:1} -S "m:<10" -q ORDERASC

    - {3:1} all {2:2} sorted by execution time
        # {0:1} {1:1} -S e
        # {0:1} {1:1} -S e:2h
        # {0:1} {1:1} -S "e:<2h" -q ORDERASC

    - {3:1} {2:2} with fastest initialization
        # {0:1} {1:1} -q FASTINIT

    - {3:1} {2:2} without size-unit converting
        # {0:1} {1:1} -q NOSIZEUNIT

    - {3:1} threads context-switched more than 5000 after sorting by context switch
        # {0:1} {1:1} -S C:5000
        # {0:1} {1:1} -S C:5000 -q ORDERDESC

    - {3:1} all {2:2} with changing the CPU scheduling priority every second
        # {0:1} {1:1} -Y "c:-20::CONT" -a

    - {3:1} {2:2} and change the CPU scheduling priority for specific threads having COMM a.out every second
        # {0:1} {1:1} -g a.out -Y "c:-20:a.out:CONT"

    - {3:1} the fixed list for {2:2} to save CPU resource for monitoring
        # {0:1} {1:1} -g a.out -e x

    - {3:1} {2:2} and report the result to ./guider.out when SIGINT arrives
        # {0:1} {1:1} -o .

    - {3:1} all {2:2} once and report the result including cgroup info to ./guider.out
        # {0:1} {1:1} -e G -a -o . -R 1

    - {3:1} {2:2} and print standard or special logs to specific logging systems
        * d:DLT / k:KMSG / j:JOURNAL / s:SYSLOG
        # {0:1} {1:1} -l dkjs
        # {0:1} {1:1} -q STDLOG:dkjs
        # {0:1} {1:1} -q OPSLOG:dkjs

    - {3:1} {2:2} with the cpu limitation in % unit using cgroup
        # {0:1} {1:1} -q LIMITCPU:20
        # {0:1} {1:1} -q LIMITCPU:20@"*yes*|a.out"

    - {3:1} {2:2} with the memory limitation using cgroup
        # {0:1} {1:1} -q LIMITMEM:50M
        # {0:1} {1:1} -q LIMITMEM:50M@"*yes*|a.out"

    - {3:1} {2:2} with the block I/O limitation using cgroup
        # {0:1} {1:1} -q LIMITREAD:50M
        # {0:1} {1:1} -q LIMITWRITE:50M
        # {0:1} {1:1} -q LIMITREAD:50M@"*yes*|a.out"
        # {0:1} {1:1} -q LIMITWRITE:50M@"*yes*|a.out"
        # {0:1} {1:1} -q LIMITWRITE:50M@"*yes*|a.out", EACHTASK

    - {3:1} {2:2} and report the result to ./guider.out with 100 line of kernel messages when SIGINT arrives
        # {0:1} {1:1} -o . -q NRKLOG:100

    - {3:1} {2:2} and report the result to ./guider.out with memo when SIGINT arrives
        # {0:1} {1:1} -o . -q MEMO:"monitoring result for server peak time"

    - {3:1} {2:2} and report the result to ./guider.out with unlimited memory buffer
        # {0:1} {1:1} -o . -b 0

    - {3:1} {2:2} and report the result to ./guider.out with limited memory buffer 50MB
        # {0:1} {1:1} -o . -b 50m

    - {3:1} {2:2} and report the result to ./guider.out with limited memory buffer 50MB loss possible
        # {0:1} {1:1} -o . -b 50m -d b

    - {3:1} {2:2} and report the result to ./guider.out without event handling
        # {0:1} {1:1} -o . -d x

    - {3:1} {2:2} and report the result to ./guider.out in real-time until SIGINT signal arrives
        # {0:1} {1:1} -o . -e p

    - {3:1} {2:2} and save the result composed only of raw data to ./guider.out in real-time until SIGINT signal arrives
        # {0:1} {1:1} -o . -e p -q NOSUMMARY

    - {3:1} {2:2} and save the result except for the interval summary to ./guider.out in real-time until SIGINT signal arrives
        # {0:1} {1:1} -o . -q NOINTSUMMARY

    - {3:1} {2:2} and report the result collected every 3 seconds for total 5 minutes to ./guider.out
        # {0:1} {1:1} -R 3s:5m -o .

    - {3:1} {2:2} and report the result collected every 3 seconds for 5 times to ./guider.out
        # {0:1} {1:1} -R 3s:5 -o .

    - {3:1} {2:2} and report the result collected every 10 seconds for 60 minutes to ./guider.out
        # {0:1} {1:1} -i 10 -R 60m -o .

    - {3:1} {2:2} and report the result collected every 3 seconds for 5 minutes to ./guider.out continuously
        # {0:1} {1:1} -R 3s:5m: -o .

    - {3:1} {2:2} with memory(PSS)
        # {0:1} {1:1} -e S

    - {3:1} {2:2} with memory(USS)
        # {0:1} {1:1} -e u

    - {3:1} newly executed {2:2} with memory(USS)
        # {0:1} {1:1} -I ./a.out -e u

    - {3:1} {2:2} with unique physical memory (RSS - Text - Shm)
        # {0:1} {1:1} -q EXCEPTSHM

    - {3:1} all {2:2} including block usage every 2 seconds
        # {0:1} {1:1} -e b -i 2 -a

    - {3:1} {2:2} with the name including system and their siblings
        # {0:1} {1:1} -g "*system*" -P

    - {3:1} {2:2} named gdbus among {2:2} with the name including system and their siblings
        # {0:1} {1:1} -g "*system*" -P -q FILTER:"gdbus"

    - {3:1} {2:2} and print stats if only system resource usage exceeds specific threshold
        # {0:1} {1:1} -q CPUCOND:10
        # {0:1} {1:1} -q MEMFREECOND:100
        # {0:1} {1:1} -q MEMAVLCOND:100
        # {0:1} {1:1} -q BLKRDCOND:1
        # {0:1} {1:1} -q BLKWRCOND:1

    - {3:1} {2:2} with the specific length for thread name
        # {0:1} {1:1} -q COMMLEN:16

    - {3:1} {2:2} on the minimum terminal
        # {0:1} {1:1} -m

    - {3:1} {2:2} on the optimized terminal
        # {0:1} {1:1} -m :

    - {3:1} {2:2} after optimizing system terminal
        # {0:1} {1:1} -m ::system

    - {3:1} {2:2} and report to elastic search
        # {0:1} {1:1} -e I

    - {3:1} {2:2} with elapsed times for each step
        # {0:1} {1:1} -q PRINTDELAY

    - {3:1} {2:2} and report the results to both ./guider.out and console
        # {0:1} {1:1} -o . -Q

    - {3:1} {2:2} and report the results to ./guider.out after freeing up space in the target directories
        # {0:1} {1:1} -o . -q LIMITDIR:./:100M, LIMITDIR:/home:1G

    - {3:1} {2:2} and execute special commands
        # {0:1} {1:1} -w AFTER:/tmp/touched:1, AFTER:ls

    - {3:1} {2:2} through the local server having 5555 port
        # {0:1} {1:1} -X 5555

    - {3:1} {2:2} and report to 192.168.0.5:5555 in real-time
        # {0:1} {1:1} -e r -N REPORT@192.168.0.5:5555

    - {3:1} {2:2} with sending signals to specific {2:2}
        # {0:1} {1:1} -k a.out:SIGKILL
        # {0:1} {1:1} -k a.out:SIGKILL:CONT

    - {3:1} {2:2} with changing CPU affinity for specific {2:2}
        # {0:1} {1:1} -z a.out:3
        # {0:1} {1:1} -z a.out:3:CONT

    - {3:1} {2:2} with the number in front of the name
        # {0:1} {1:1} -c index

    - {3:1} {2:2} after setting hot commands in advance
        # {0:1} {1:1} -c "GUIDER utop -g PID"
        # {0:1} {1:1} -c "GUIDER btrace -g PID *write*|getret\, __write_nocancel|getret"

    - {3:1} {2:2} and execute specific commands for all or a few tasks shown automatically
        # {0:1} {1:1} -c "GUIDER utop -g PID" -e E
        # {0:1} {1:1} -c "GUIDER utop -g PID" -e E -q NRTOPRANK:1
        # {0:1} {1:1} -c "GUIDER btrace -g PID *write*|getret\, __write_nocancel|getret" -e E

    - {3:1} {2:2} after setting config from guider.conf
        # {0:1} {1:1} -C guider.conf

    - {3:1} {2:2} with no encoding for output
        # {0:1} {1:1} -d e
        # NO_ENCODE=1 {0:1} {1:1} -d e

    - {3:1} system only
        # {0:1} {1:1} -d T
                """.format(
                    cmd, mode, target, "Monitor the status of"
                )

                drawExamStr = """
Examples:
    - Draw items for specific files
        # {0:1} {1:1} guider.out
        # {0:1} {1:1} guider.out guider2.out "guider data.out"
        # {0:1} {1:1} "data/*"
        # {0:1} {1:1} guider.dat

    - Draw items for specific files from current directory to all sub-directories
        # {0:1} {1:1} "**/*"

    - Draw items that haven't been summarized yet for specific files
        # {0:1} {1:1} guider.out -q TOPSUM

    - Draw items for each file
        # {0:1} {1:1} guider.out -q NOMERGE

    - Draw items except for call samples in wait status
        # {0:1} {1:1} guider.out -q EXCEPTWAIT

    - Draw items for specific tasks
        # {0:1} {1:1} guider.dat -g task3
        # {0:1} {1:1} guider.dat -g "*"
        # {0:1} {1:1} guider.dat -g "*java*" -a
        # {0:1} {1:1} guider.dat -g "*java*" -q NOTOTAL

    - Draw items for specific tasks and their siblings
        # {0:1} {1:1} guider.dat -g task3 -P

    - Draw items after concatenating specific files
        # {0:1} {1:1} guider.out -q CONCATENATE
        # {0:1} {1:1} guider.out -q CONCATENATE, ONLYTOTAL

    - Draw items after concatenating specific files and converting unique physical memory (RSS - Text - Shm)
        # {0:1} {1:1} guider.out -q CONCATENATE, EXCEPTSHM

    - Draw items except for specific resources after concatenating specific files
        # {0:1} {1:1} guider.out -q CONCATENATE, NOCPUSUMMARY, NOGPUSUMMARY
        # {0:1} {1:1} guider.out -q CONCATENATE, NODELAYSUMMARY
        # {0:1} {1:1} guider.out -q CONCATENATE, NOVSSSUMMARY, NORSSSUMMARY
        # {0:1} {1:1} guider.out -q CONCATENATE, NOBLOCKSUMMARY
        # {0:1} {1:1} guider.out -q CONCATENATE, NOSTORAGESUMMARY, NONETSUMMARY

    - Draw specific items including the specific word
        # {0:1} {1:1} timeline.json -q FILTER:"test*"
        # {0:1} {1:1} timeline.json -q FILTER:"*test"
        # {0:1} {1:1} timeline.json -q FILTER:"*test*"

    - Draw items for all events and tasks
        # {0:1} {1:1} guider.dat -a

    - Draw items except for load plots including CPU and I/O usage
        # {0:1} {1:1} guider.dat -q NOLOADPLOT

    - Draw items except for specific cpu plots
        # {0:1} {1:1} guider.dat -q MAXCPUCOND:10
        # {0:1} {1:1} guider.dat -q AVGCPUCOND:10
        # {0:1} {1:1} guider.dat -q MINCPUCOND:10

    - Draw items including system memory plots
        # {0:1} {1:1} guider.dat -q MEMSYSPLOT

    - Draw items except for specific memory plots
        # {0:1} {1:1} guider.dat -q NOMEMFREEPLOT
        # {0:1} {1:1} guider.dat -q NOMEMANONPLOT
        # {0:1} {1:1} guider.dat -q NOMEMCACHEPLOT
        # {0:1} {1:1} guider.dat -q NOMEMPROCPLOT
        # {0:1} {1:1} guider.dat -q NOMEMSWAPPLOT
        # {0:1} {1:1} guider.dat -q MAXVSSCOND:1024
        # {0:1} {1:1} guider.dat -q MAXRSSCOND:1024

    - Draw items except for syscalls for timeline segments
        # {0:1} {1:1} guider.dat -q NOSYSCALL

    - Draw items forcefully
        # {0:1} {1:1} guider.dat -f

    - Draw items using uptime for perf graph
        # {0:1} {1:1} guider.dat -q NOTIMEFORMAT

    - Draw items with task life events for perf graph
        # {0:1} {1:1} guider.dat -q DRAWLIFE, LFONTSIZE:2

    - Draw items with specific task life events for perf graph
        # {0:1} {1:1} guider.dat -q DRAWLIFE, INEVENT:"*system*", INEVENT:"*cat*"

    - Draw items with task life events except for specific ones for perf graph
        # {0:1} {1:1} guider.dat -q DRAWLIFE, EXEVENT:"*arp*", EXEVENT:"*pkill*"

    - Draw items in us time-unit for timeline segments
        # {0:1} {1:1} guider.dat -q TIMEUNIT:us

    - Draw items except for labels of timeline segments lesser than 100ms
        # {0:1} {1:1} guider.dat -q LABELMIN:100

    - Draw items with label setting
        # {0:1} {1:1} guider.dat -q LABEL
        # {0:1} {1:1} guider.dat -q NOLABEL

    - Draw items with stroke only for specific tasks
        # {0:1} {1:1} guider.dat -q STROKE:"*"
        # {0:1} {1:1} guider.dat -q STROKE:"screen*", STROKE:"a.out(1234)"

    - Draw items and event markers on specific points
        # {0:1} {1:1} guider.dat -q EVENT:14:90:EVENT_1:CPU
        # {0:1} {1:1} guider.dat -q EVENT:30:100:EVENT_2:MEM
        # {0:1} {1:1} guider.dat -q EVENT:30:100:EVENT_3:CIRCLE
        # {0:1} {1:1} guider.dat -q EVENT:30:100:EVENT_4:LARROW
        # {0:1} {1:1} guider.dat -q EVENT:30:100:EVENT_5:RARROW

    - Draw items only for specific groups or cores
        # {0:1} {1:1} guider.dat -O 1, 4, 10
        # {0:1} {1:1} guider.dat -O 1:10, 14

    - Draw items with changed groups or cores for timeline segments
        # {0:1} {1:1} guider.dat -q CONVGROUP:0:1, CONVGROUP:1:0

    - Draw items to specific image format
        # {0:1} {1:1} guider.out -F png
        # {0:1} {1:1} guider.out -F pdf
        # {0:1} {1:1} guider.out -F svg

    - Draw items with config file
        # {0:1} {1:1} guider.dat -C config.json

    - Draw items excluding chrome process
        # {0:1} {1:1} guider.out -g ^chrome

    - Draw items with some boundary lines
        # {0:1} {1:1} guider.out worstcase.out -l 80, 100, 120

    - Draw items within specific interval range in second unit
        # {0:1} {1:1} guider.out -q TRIM:9:15
        # {0:1} {1:1} guider.out -q TRIM:0.9:1.5
        # {0:1} {1:1} guider.out -q TRIM:11.9:13.5, ABSTIME

    - Draw items on absolute timeline
        # {0:1} {1:1} guider.out -q ABSTIME

    - Draw items on relative timeline
        # {0:1} {1:1} guider.out -q RELTIME

    - Draw items only having backtrace for flamegraph
        # {0:1} {1:1} guider.out -q ONLYBTSTACK

    - Draw items within specific interval range in index unit
        # {0:1} {1:1} guider.out -q TRIMIDX:0:3

    - Draw items with y range 1-100
        # {0:1} {1:1} guider.out worstcase.out -q YRANGE:1:100
        # {0:1} {1:1} guider.out worstcase.out -q YRANGE:10:
        # {0:1} {1:1} guider.out worstcase.out -q YRANGE::100

    - Draw items with specific font size
        # {0:1} {1:1} guider.out worstcase.out -q FONTSIZE:15
        # {0:1} {1:1} guider.out worstcase.out -q XFONTSIZE:2
        # {0:1} {1:1} guider.out worstcase.out -q LFONTSIZE:5
        # {0:1} {1:1} guider.out worstcase.out -q GROUPFONTSIZE:30

    - Draw items of top 5 processes
        # {0:1} {1:1} guider.out worstcase.out -T 5

    - Draw items of total CPU usage by applying the multiplication of the number of CPUs
        # {0:1} {1:1} guider.out worstcase.out -d A

    - Draw items on customized layout
        # {0:1} {1:1} guider.out -L c:3, d:3
        # {0:1} {1:1} guider.out -L c:2, m:2, i:2
        # {0:1} {1:1} guider.out -L c:4, r:1, v:1

    - Draw items for block and network resources
        # {0:1} {1:1} guider.out -e d n

    - Draw items with multiple files for comparison
        # {0:1} {1:1} "guider*.out" worstcase.out

    - Draw items of total resource usage with multiple files for comparison
        # {0:1} {1:1} "guider*.out" worstcase.out -a -g TOTAL

    - Draw fixed-size items for timeline segments
        # {0:1} {1:1} timeline.json -q DURATION:500

    - Draw per-task items for timeline segments
        # {0:1} {1:1} timeline.json -q PERTASK

    - Draw items with minimum fixed-size for timeline segments
        # {0:1} {1:1} timeline.json -q DURATIONMIN:500

    - Draw items with stroke only for specific interval bigger than 3000 for timeline segments
        # {0:1} {1:1} guider.dat -q STROKEINTERVAL:3000

    - Draw items with stroke only for specific duration bigger than 5000 for timeline segments
        # {0:1} {1:1} guider.dat -q STROKEDURATION:5000
                """.format(
                    cmd, mode
                )

                cmdListStr = """
Commands:
    acc      print accumulation stats for specific values [NAME:VAR|REG|VAL]
    add      add breakpoints
    check    check context and execute next commands [VAR|ADDR|REG:OP(EQ/DF/INC/BT/LT):VAR|VAL:SIZE:EVT]
    condexit exit if tracing was started
    dist     print distribution stats for specific values [NAME:VAR|REG|VAL]
    dump     dump specific memory range to a file [NAME|ADDR:FILE]
    event    write ftrace log [MESSAGE]
    exec     execute the external command [CMD]
    exit     exit tracing
    filter   print only filtered context [VAR|ADDR|REG|RETTIME|RETVAL:OP(EQ/DF/INC/BT/LT):VAR|VAL:SIZE]
    getarg   print specific registers [REGS]
    getenv   print specific environment variable [VAR]
    getret   print return value [CMD]
    hide     hide tracing
    hidden   hide the function call
    setinter print interval time between specific function calls
    inter    print interval stats for the function call
    jump     jump to specific function with specific arguments [FUNC#ARGS]
    kill     terminate the target task
    load     load specific library [PATH]
    log      print specific message [MESSAGE]
    map      print memory map
    print    print context [VAR]
    pyfile   execute specific python file [PATH:SYNC]
    pyscript execute python function [PATH:FUNC:ARGS]
    pystr    execute python code [CODE:SYNC]
    remove   remove breakpoints [FUNC]
    rdmem    print specific memory or register [VAR|ADDR|REG:SIZE]
    repeat   call again repeatedly [CNT]
    ret      return specific value immediately [VAL]
    save     save previous value [VAR]
    setarg   change value for specific register [REG#VAR|VAL]
    setenv   change specific environment variable [VAR:VAR|VAL]
    setret   change return value [VAL:CMD]
    show     show tracing
    sleep    sleep for seconds [SEC]
    start    start tracing
    stop     pause tracing
    syscall  call a syscall [FUNC#ARGS]
    thread   create a new thread
    proctop  print total resource usage for processes [PID|COMM]
    proctopg print total resource usage for process groups [PID|COMM]
    thrtop   print total resource usage for threads [PID|COMM]
    thrtopg  print total resource usage for thread groups [PID|COMM]
    usercall call a specific function [FUNC#ARGS]
    wrmem    change specific memory or register [VAR|ADDR|REG:VAL:SIZE]
                """

                brkExamStr = """{2:1}
Examples:
    - {3:1} {7:1}
        # {0:1} {1:1} -g 1234
        # {0:1} {1:1} -g a.out

    - {3:1} {8:1}
        # {0:1} {1:1} "ls"
        # {0:1} {1:1} "sh -c \\"while [ 1 ]; do echo "OK"; done;\\""
        # {0:1} {1:1} -I "ls"

    - {3:1} and JIT-compiled function calls {7:1}
{6:1}
        # {0:1} {1:1} -g node -q JITSYM

    - {3:1} and standard output {8:1}
        # {0:1} {1:1} "ls" -q NOMUTE

    - {3:1} {7:1} with call interval info
        # {0:1} {1:1} -g a.out -q INTERCALL
        # {0:1} {1:1} -g a.out -c "QAnimationDriver::advanceAnimation*" -q INTERCALL
        # {0:1} {1:1} -g a.out -c "QSGThreadedRenderLoop::polishAndSync*" -q INTERCALL
        # {0:1} {1:1} -g a.out -c "QCoreApplication::notifyInterval2*" -q INTERCALL -H
        # {0:1} {1:1} -g a.out -c "QOpenGLContext::swapBuffers*" -q INTERCALL

    - {3:1} {7:1} with call interval info including stdev
        # {0:1} {1:1} -g a.out -q INTERCALL, STDEV

    - {3:1} {7:1} with call interval info including stdev, histogram
        # {0:1} {1:1} -g a.out -q INTERCALL, STDEV, PRINTHIST

    - {3:1} {8:1} excluding specific environment variable
        # {0:1} {1:1} "ls" -q REMOVEENV:MAIL

    - {3:1} using merged symbols {8:1}
        # {0:1} {1:1} "ls" -q ALLSYM

    - {3:1} {8:1} after preloading ELF files from the specific file list
        # {0:1} {1:1} "ls" -q ELFFILE:./mem.out

    - {3:1} {8:1} with target process monitoring
        # {0:1} {1:1} "ls" -w BEFORE:"GUIDER top -g ls -Q &"

    - {3:1} {7:1} without file loading messages
        # {0:1} {1:1} -g a.out

    - {3:1} {7:1} with printing tracing overhead
        # {0:1} {1:1} -g a.out -q PRINTDELAY

    - {3:1} {7:1} including profiling overhead time
        # {0:1} {1:1} -g a.out -q INCOVERHEAD

    - {3:1} {8:1} and redirect standard I/O of child tasks to specific files
        # {0:1} {1:1} "ls" -q STDIN:"./stdin"
        # {0:1} {1:1} "ls" -q STDOUT:"./stdout"
        # {0:1} {1:1} "ls" -q STDERR:"/dev/null"

    - {3:1} and convert syscall args {7:1}
        # {0:1} {1:1} -g a.out -q CONVARG

    - {3:1} for specific processes
        # {0:1} {1:1} -g a.out -q ONLYPROC

    - {3:1} {7:1} (wait for new target if no task)
        # {0:1} {1:1} -g a.out -q WAITTASK
        # {0:1} {1:1} -g a.out -q WAITTASK:1
        # {0:1} {1:1} -g a.out -q WAITTASK, NOPIDCACHE

    - {3:1} only for child tasks created by specific threads
        # {0:1} {1:1} -g a.out -q WAITCLONE

    - {3:1} except for wait status {7:1}
        # {0:1} {1:1} -g a.out -q EXCEPTWAIT

    - {3:1} except for register info {7:1}
        # {0:1} {1:1} -g a.out -q NOCONTEXT

    - {3:1} {7:1} consumed CPU more than 10%
        # {0:1} {1:1} -g a.out -q CPUCOND:10

    - {3:1} {7:1} even if the master tracer is terminated
        # {0:1} {1:1} -g a.out -q CONTALONE

    - {3:1} {7:1} after loading all symbols in stop status
        # {0:1} {1:1} -g a.out -q STOPTARGET

    - {3:1} {7:1} without file loading messages
        # {0:1} {1:1} -g a.out -q NOLOADMSG

    - {3:1} {7:1} with task sync for clone event
        # {0:1} {1:1} -g a.out -q SYNCTASK

    - {3:1} except for no symbol functions {7:1}
        # {0:1} {1:1} -g a.out -q ONLYSYM

    - {3:1} except for arguments {7:1}
        # {0:1} {1:1} -g a.out -q NOARG

    - {3:1} except for file info {7:1}
        # {0:1} {1:1} -g a.out -q NOFILE

    - {3:1} except for ld {7:1}
        # {0:1} {1:1} -g a.out -q EXCEPTLD

    - {3:1} {7:1} except for DWARF table of specific files
        # {0:1} {1:1} -g a.out -q EXCEPTDWARF:"*deno"

    - {3:1} and their injection info {7:1}
        # {0:1} {1:1} -g a.out -q TRACEBP

    - {3:1} without using file cache {7:1}
        # {0:1} {1:1} -g a.out -q NOFILECACHE

    - {3:1} and print context combined both entry and exit
        # {0:1} {1:1} -g a.out -c "*|getret' -q COMPLETECALL

    - {3:1} for 4th and 5th new threads in each new processes {8:1}
        # {0:1} {1:1} a.out -q TARGETNUM:4, TARGETNUM:5
        # {0:1} {1:1} -I a.out -q TARGETNUM:4, TARGETNUM:5

    - {3:1} from a specific binary with DWARF info
        # {0:1} {1:1} "ls" -eD
        # {0:1} {1:1} -I "ls" -eD

    - {3:1} {8:1} including specific environment variables
        # {0:1} {1:1} a.out -q ENV:TEST=1, ENV:PATH=/data
        # {0:1} {1:1} a.out -q ENVFILE:/data/env.sh
        # {0:1} {1:1} a.out -q ENVPROC:systemd

    - {3:1} with backtrace {7:1}
        # {0:1} {1:1} -g a.out -H

    - {3:1} with python backtrace {7:1}
        # {0:1} {1:1} -g a.out -H -q PYSTACK

    - {3:1} with arguments using DWARF {7:1}
        # {0:1} {1:1} -g a.out -q DEBUGINFO, PRINTARG

    - {3:1} with backtrace including arguments using DWARF {7:1}
        # {0:1} {1:1} -g a.out -H -q DEBUGINFO, PRINTBTARG

    - {5:1} {7:1}
        # {0:1} {1:1} -g 1234 -c printPeace

    - {3:1} except for printPeace {7:1}
        # {0:1} {1:1} -g 1234 -c "^printPeace"
        # {0:1} {1:1} -g 1234 -c "^g_mutex_*, ^pthread_mutex_*"

    - {5:1} from a specific binary
        # {0:1} {1:1} ~/test/mutex -c "std::_Vector_base<unsigned long\, std::allocator<unsigned long> >::~_Vector_base()"

    - {5:1} {7:1} only for 2 seconds
        # {0:1} {1:1} -g a.out -c printPeace -R 2s

    - {5:1} {7:1} and report the result to ./guider.out
        # {0:1} {1:1} -g a.out -c printPeace -o .
        # {0:1} {1:1} -g a.out -c printPeace -o . -q FORCESUMMARY

    - {5:1} {7:1} with monitoring threads and report the result to ./guider.out
        # {0:1} {1:1} -g a.out -c printPeace -o . -w "BEFORE:{0:1} ttop -Q &"

    - {5:1} including specific word {7:1}
        # {0:1} {1:1} -g 1234 -c "*printPeace"
        # {0:1} {1:1} -g 1234 -c "printPeace*"
        # {0:1} {1:1} -g 1234 -c "*printPeace*"

    - {3:1} related to specific files {7:1}
        # {0:1} {1:1} -g a.out -c -T /usr/bin/yes
        # {0:1} {1:1} -g a.out -c -T "/usr/lib/*"
        # {0:1} {1:1} -g a.out -c -q TARGETFILE:"/usr/lib/*"

    - {3:1} except for specific files {7:1}
        # {0:1} {1:1} -g a.out -c -T ^/usr/bin/yes
        # {0:1} {1:1} -g a.out -c -T "^/usr/lib/*"
        # {0:1} {1:1} -g a.out -c -q EXCEPTFILE:"/usr/lib/*"

    - {5:1} including specific word in a hidden state
        # {0:1} {1:1} -g a.out -c "*printPeace|hidden"

    - {5:1} including specific word {7:1} until {4:1}
        # {0:1} {1:1} -g a.out -c "*, *printPeace|stop"
        # {0:1} {1:1} -g a.out -c "*, printPeace*|hide"
        # {0:1} {1:1} -g a.out -c "*, *printPeace*|hide"

    - {3:1} and sleep for 0.1 second {4:1}
        # {0:1} {1:1} -g a.out -c "*|sleep:0.1"

    - {5:1} and sleep for 0.1 second only one time {7:1} {4:1}
        # {0:1} {1:1} -g a.out -c "write|oneshot:sleep:0.1"

    - {5:1} {7:1} and kill the target thread {4:1}
        # {0:1} {1:1} -g a.out -c "write|kill"

    - {5:1} {7:1} and modify memory {4:1}
        # {0:1} {1:1} -g a.out -c "write|wrmem:0x1234:aaaa:4"

    - {5:1} {7:1} and modify memory pointed by 1st argument {4:1}
        # {0:1} {1:1} -g a.out -c "write|wrmem:0:aaaa:4"

    - {5:1} {7:1} and print 10-length string pointed by 1st argument {4:1}
        # {0:1} {1:1} -g a.out -c "printf|rdmem:0:10"

    - {5:1} {7:1} and print 10-length string from the specific address {4:1}
        # {0:1} {1:1} -g a.out -c "printf|rdmem:0x1234:10"

    - {5:1} {7:1} and return a specific value immediately {4:1}
        # {0:1} {1:1} -g a.out -c "write|ret:3"

    - {5:1} {7:1} and add breakpoints for specific symbols
        # {0:1} {1:1} -g a.out -c "*loadData*|add:*close*"
        # {0:1} {1:1} -g a.out -c "*loadData*|getret|add:func1;func2"
        # {0:1} {1:1} -g a.out -c "*loadData*|getret|add:*close*"
        # {0:1} {1:1} -g a.out -c "*loadData*|getret|add:^*close*"

    - {5:1} {7:1} and remove breakpoints for specific symbols
        # {0:1} {1:1} -g a.out -c "*loadData*|remove:*"
        # {0:1} {1:1} -g a.out -c "*loadData*|getret|remove:func1;func2"
        # {0:1} {1:1} -g a.out -c "*loadData*|getret|remove:^*loadData*"

    - {5:1} {7:1} and write event info of specific symbols into ftrace buffer
        # {0:1} {1:1} -g a.out -c "*loadData*|event:LOG"

    - {5:1} {7:1} and run multiple commands when specific function calls return
        # {0:1} {1:1} -g a.out -c "write|getret:sleep:1\\$exec:ls\\$stop"

    - {5:1} {7:1} and print resource usage for tasks
        # {0:1} {1:1} -g a.out -c "*loadData*|getret:proctop:a.out|proctop:a.out"
        # {0:1} {1:1} -g a.out -c "*loadData*|getret:proctop:a.out\\,guider|proctop:a.out\\,guider"
        # {0:1} {1:1} -g a.out -c "*loadData*|getret:thrtopg:a.out|thrtopg:a.out"

    - {5:1} {7:1} and dump thread stack to the specific file {4:1}
        # {0:1} {1:1} -g a.out -c "write|dump:stack:stack.out"

    - {5:1} {7:1} and dump specific memory range to the specific file {4:1}
        # {0:1} {1:1} -g a.out -c "write|dump:0x1234-0x4567:dump.out"

    - {5:1} {7:1} and print return value {4:1}
        # {0:1} {1:1} -g a.out -c "write|getret"
        # {0:1} {1:1} -g a.out -c "write|getret" -q NORETBT

    - {5:1} {7:1} until {4:1} and save return value to the specific variable
        # {0:1} {1:1} -g a.out -c "write|getret:stop\\$print"

    - {5:1} {7:1} from when specific function calls return
        # {0:1} {1:1} -g a.out -c "write|getret:start, *"

    - {5:1} {7:1} without truncation
        # {0:1} {1:1} -g a.out -q NOCUT

    - {5:1} with colorful elapsed time exceeds 0.1 second {4:1} {7:1}
        # {0:1} {1:1} -g a.out -c "write|getret" -q ELAPSED:0.1

    - {5:1} and call them again repeatedly {4:1} {7:1}
        # {0:1} {1:1} -g a.out -c "write|repeat"
        # {0:1} {1:1} -g a.out -c "write|repeat:5"

    - {5:1} and modify return value {4:1} {7:1}
        # {0:1} {1:1} -g a.out -c "write|setret:3"
        # {0:1} {1:1} -g a.out -c "write|setret:3:print"

    - {5:1} and modify 1st and 2nd arguments {4:1} {7:1}
        # {0:1} {1:1} -g a.out -c "write|setarg:0#2:1#5"

    - {5:1} and print call contexts {4:1} {7:1}
        # {0:1} {1:1} -g a.out -c "write|print"

    - {5:1} and print call contexts {4:1} {7:1}
        # {0:1} {1:1} -g a.out -c "write|print"

    - {5:1} and print python contexts {4:1} {7:1}
        # {0:1} {1:1} -g a.out -c "write|print" -q PYSTACK

    - {5:1} and save specific values to specific variables {4:1} {7:1}
        # {0:1} {1:1} -g a.out -c "write|save:VAR1|print:VAR1|save:VAR2:123"
        # {0:1} {1:1} -g a.out -c "write|save:ARG1:1:arg|print:VAR1"

    - {5:1} and print call contexts if specific conditions are met {4:1} {7:1}
        # {0:1} {1:1} -g a.out -c "write|filter:2:EQ:4096"
        # {0:1} {1:1} -g a.out -c "write|filter:2:BT:0x1000"
        # {0:1} {1:1} -g a.out -c "write|filter:*1:EQ:HELLO"
        # {0:1} {1:1} -g a.out -c "write|filter:*1:INC:HE"
        # {0:1} {1:1} -g a.out -c "write|filter:2:BT:1|filter:1:EQ:1"

    - {5:1} and print call contexts if only the elapsed time exceed 0.0005 second {7:1} {4:1}
        # {0:1} {1:1} -g a.out -c "write|filter:RETTIME:BT:0.0005"
        # {0:1} {1:1} -g a.out -c "write|getret|filter:RETTIME:BT:0.0005" -q COMPLETECALL -a
        # {0:1} {1:1} -g a.out -c "write|filter:RETTIME:BT:0.0005" -H -a
        # {0:1} {1:1} -g a.out -c "write|filter:RETTIME:BT:0.0005|filter:0:BT:0"
        # {0:1} {1:1} -g a.out -c "write|filter:RETTIME:BT:0.0005:exit"
        # {0:1} {1:1} -g a.out -c "write|filter:RETTIME:BT:0.0005:sleep:1"
        # {0:1} {1:1} -g a.out -c "write|filter:RETTIME:BT:0.0005:dist:0"

    - {5:1} and print call contexts if only the return value is bigger than 1 {4:1} {7:1}
        # {0:1} {1:1} -g a.out -c "write|filter:RETVAL:BT:0.0005"
        # {0:1} {1:1} -g a.out -c "write|filter:RETVAL:BT:0.0005" -H -a
        # {0:1} {1:1} -g a.out -c "write|filter:RETVAL:BT:0.0005|filter:0:BT:0"
        # {0:1} {1:1} -g a.out -c "write|filter:RETVAL:BT:0.0005:exit"
        # {0:1} {1:1} -g a.out -c "write|filter:RETVAL:BT:0.0005:sleep:1"

    - {5:1} and check specific conditions {4:1} {7:1}
        # {0:1} {1:1} -g a.out -c "write|check:2:EQ:4096"
        # {0:1} {1:1} -g a.out -c "write|check:2:BT:0x1000"
        # {0:1} {1:1} -g a.out -c "write|check:*1:EQ:HELLO"
        # {0:1} {1:1} -g a.out -c "write|check:*1:INC:HE"
        # {0:1} {1:1} -g a.out -c "write|check:0:EQ:1|sleep:1"
        # {0:1} {1:1} -g a.out -c "write|check:@RET1:EQ:@RET2:EVENT_CONT"

    - {5:1} and print 1st and 2nd arguments {4:1} {7:1}
        # {0:1} {1:1} -g a.out -c "write|getarg:0:1"

    - {5:1} and print 1st and 2nd arguments and save its return value to the specific variable {4:1}
        # {0:1} {1:1} -g a.out -c "write|getarg:0:1|save:writeRet"

    - {5:1} from {4:1} {7:1}
        # {0:1} {1:1} -g a.out -c "write|start, *"
        # {0:1} {1:1} -g a.out -c "write|show, *" -q HIDESYM

    - {5:1} and terminate the target thread {4:1}
        # {0:1} {1:1} -g a.out -c "write|exit"

    - {5:1} within a specific range {4:1} {7:1}
        # {0:1} {1:1} -g a.out -c "open|start|getret:stop, *"
        # {0:1} {1:1} -g a.out -c "open|start|getret:exit, *"
        # {0:1} {1:1} -g a.out -c "open|start, *, close|getret:condexit"

    - {5:1} and call specific functions every time {4:1} {7:1}
        # {0:1} {1:1} -g a.out -c "write|usercall:sleep#3"
        # {0:1} {1:1} -g a.out -c "write|usercall:printf#PEACE\\n"
        # {0:1} {1:1} -g a.out -c "write|usercall:printf#12345\\n"
        # {0:1} {1:1} -g a.out -c "write|usercall:getenv#PATH, usercall:write#1#@getenv#1024"

    - {5:1} and call specific syscalls {4:1} {7:1}
        # {0:1} {1:1} -g a.out -c "write|syscall:getpid"
        # {0:1} {1:1} -g a.out -c "write|syscall:open#test.out#1"

    - {5:1} and load specific library {4:1} {7:1}
        # {0:1} {1:1} -g a.out -c "write|load:/usr/lib/preload.so"

    - {5:1} and create a new thread {4:1} {7:1}
        # {0:1} {1:1} -g a.out -c "write|thread"

    - {5:1} and execute specific python function {4:1} {7:1}
        # {0:1} {1:1} -g a.out -c "write|pyscript:test.py:test_func"
        # {0:1} {1:1} -g a.out -c "write|pyscript:test.py:test_func:1:2:3"

    - {5:1} and execute specific python code {4:1} {7:1}
        # {0:1} {1:1} -g a.out -c "write|pystr:print('OK')" -q LIBPYTHON:/usr/lib/x86_64-linux-gnu/libpython3.8.so.1.0
        # {0:1} {1:1} -g a.out -c "write|pyfile:test.py:false" -q LIBPYTHON:/usr/lib/x86_64-linux-gnu/libpython3.8.so.1.0

    - {5:1} and print accumulated stats for a specific argument {4:1} {7:1}
        # {0:1} {1:1} -g a.out -c "malloc|acc:CHUNK:0"

    - {5:1} and print distribution stats for a specific argument {4:1} {7:1}
        # {0:1} {1:1} -g a.out -c "malloc|dist:CHUNK:0"

    - {5:1} and print interval time between specific function calls {4:1} {7:1}
        # {0:1} {1:1} -g a.out -c "malloc|setinter:_exit, _exit"
        # {0:1} {1:1} -g a.out -c "malloc|setinter:_exit, _exit" -q ELAPSED:0.1

    - {5:1} and print interval stats for the function call {4:1} {7:1}
        # {0:1} {1:1} -g a.out -c "malloc|inter"
        # {0:1} {1:1} -g a.out -c "malloc|inter" -q ELPASED:0.001

    - {5:1} and jump to specific function with specific arguments {4:1} {7:1}
        # {0:1} {1:1} -g a.out -c "write|jump:sleep#5"

    - {3:1} and execute specific commands {4:1} {7:1}
        # {0:1} {1:1} -g a.out -c "*|exec:ls -lha;sleep 1"
        # {0:1} {1:1} -g a.out -c "*|exec:ls -lha &"

    - {3:1} {7:1} and draw timeline segments for all function calls
        # {0:1} {1:1} -g a.out -q TIMELINE, TIMEUNIT:ms, INTERCALL, DURATION:10
        # {0:1} {1:1} -g a.out -q TIMELINE, TIMEUNIT:us, INTERCALL, DURATION:100 -H -a
        # {0:1} {1:1} -g a.out -c "*|getret" -q TIMELINE, TIMEUNIT:ms, COMPLETECALL
        # {0:1} {1:1} -g a.out -c "*|getret" -q TIMELINE, TIMEUNIT:us, COMPLETECALL, GROUPFONTSIZE:30
                """.format(
                    cmd,
                    mode,
                    cmdListStr,
                    "Trace all native calls",
                    "when specific calls detected",
                    "Trace specific native calls",
                    jitProfStr,
                    "for specific threads",
                    "from a specific binary",
                )

                logCommonStr = """
Usage:
    # {0:1} {1:1} -I <MESSAGE>

Description:
    Log a message

Options:
    -v                          verbose
    -R  <INTERVAL:TIME>         set repeat count
    -I  <LOG>                   set log message

Examples:
    - Log a message
        # {0:1} {1:1} "Hello World!"
        # {0:1} {1:1} -I "Hello World!"

    - Log a message 5 times
        # {0:1} {1:1} "Hello World!" -R 5
                    """.format(
                    cmd, mode
                )

                printCommonStr = """
Usage:
    # {0:1} {1:1}

Description:
    Print logs in real-time

Options:
    -v                          verbose
    -g  <WORD|TID>              set filter
    -c  <LEVEL>                 set log level
    -I  <FILE|FIELD>            set path / field
    -J                          print in JSON format
    -R  <TIME>                  set timer
    -o  <DIR|FILE>              set output path
    -X  <REQ@IP:PORT>           set request address
    -Q                          print all rows in a stream
    -q  <NAME{{:VALUE}}>          set environment variables

Examples:
    - Print logs in real-time
        # {0:1} {1:1}

    - Print logs to the specific file
        # {0:1} {1:1} -o log.out

    - Print logs in real-time for 3 seconds
        # {0:1} {1:1} -R 3s

    - Print logs in real-time until no log
        # {0:1} {1:1} -Q

    - Print logs generated since now in real-time
        # {0:1} {1:1} -q TAIL

    - Print logs in real-time until a log containing a specific word is detected
        # {0:1} {1:1} -q WATCHLOG:"*oops*"

    - Print logs in real-time until a log containing a specific word is detected and execute specific commands when terminated
        # {0:1} {1:1} -q WATCHLOG:"*oops*", WATCHLOGCMD:"ls -lha"
                    """.format(
                    cmd, mode
                )

                # function record #
                if SysMgr.checkMode("funcrec"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Record function events
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Options:
  [collect]
    -e  <CHARACTER>             enable options
          [ b:block | c:cgroup | e:encode | g:graph
            h:heap | L:lock | m:mem | p:pipe | u:user ]
    -d  <CHARACTER>             disable options
          [ a:all | c:cpu | C:compress | e:encode
            g:general | l:latency | L:log ]
    -s  <DIR|FILE>              save trace data
    -f                          force execution
    -u                          run in the background
    -b  <SIZE:KB>               set buffer size
    -t  <SYSCALL>               trace syscall
    -B  <DIR|FILE>              set command script path
    -W  <SEC>                   wait for input
    -w  <TIME:FILE{:VALUE}>     set additional command
    -U  <NAME:FUNC|ADDR:FILE>   set user event
    -K  <NAME:FUNC|ADDR:ARGS>   set kernel event

  [report]
    -o  <DIR|FILE>              set output path
    -S  <CHARACTER>             sort by key
          [ c:cpu / m:memory / p:pid / b:block / w:wfc
            n:new / r:runtime /file ]
    -P                          group threads in a same process
    -O  <CORE>                  set core filter
    -r  <DIR>                   set root path
    -m  <ROWS:COLS:SYSTEM>      set terminal size

  [common]
    -a                          show all stats and events
    -C  <PATH>                  set config path
    -g  <COMM|TID{:FILE}>       set task filter
    -R  <INTERVAL:TIME:TERM>    set repeat count
    -Q                          print all rows in a stream
    -q  <NAME{:VALUE}>          set environment variables
    -A  <ARCH>                  set CPU type
    -c  <EVENT:COND>            set custom event
    -E  <DIR>                   set cache dir path
    -H  <LEVEL>                 set function depth level
    -k  <COMM|TID:SIG{:CONT}>   set signal
    -z  <COMM|TID:MASK{:CONT}>  set CPU affinity
    -Y  <POLICY:PRIO|TIME       set sched
         {:TID|COMM:CONT}>
        <CLASS:{{WHICH:}}PRIO
         :TID|COMM>
    -v                          verbose
                    """

                    helpStr += """
Examples:
    - {2:1} for all threads to ./guider.dat
        # {0:1} {1:1} -s .

    - {2:1} including user-level call-stacks for all threads to ./guider.dat
        # {0:1} {1:1} -s .

    - {2:1} for all threads to ./guider.dat for only 3 minutes
        # {0:1} {1:1} -s . -R 3m

    - {2:1} for all threads to ./guider.dat every 3 minutes continuously
        # {0:1} {1:1} -s . -R 3m:1:1

    - {2:1} for specific threads having TID bigger than 1024 to ./guider.dat in the background
        # {0:1} {1:1} -s . -g 1024\< -u

    - {2:1} including memory, block, heap for all threads to ./guider.dat
        # {0:1} {1:1} -s . -e m, b, h

    - {2:1} including all syscalls for all threads to ./guider.dat
        # {0:1} {1:1} -s . -t

    - {2:1} for all threads and save recording commands to specific script file
        # {0:1} {1:1} -B guider.cmd

    - {2:1} including softirq_entry event for all threads to ./guider.dat
        # {0:1} {1:1} -s . -c "softirq_entry:vec==1"

    - {2:1} including segmentation fault for all threads to ./guider.dat in real-time
        # {0:1} {1:1} -s . -d c -K "segflt:bad_area" -e p

    - {2:1} including blocking for all threads to ./guider.dat
        # {0:1} {1:1} -s . -d c -K "block:schedule"

    - {2:1} for all threads to ./guider.dat and execute user commands
        # {0:1} {1:1} -s . -w BEFORE:/tmp/started:1, BEFORE:ls

    - {3:1} for all threads and print the result
        # {0:1} {1:1} -e g
        # {0:1} {1:1} -e g -R 3s
        # {0:1} {1:1} -e g -s -R 3s:9s

    - {3:1} for all threads and print the result only for specific cores
        # {0:1} {1:1} -e g -O 1, 2

    - {3:1} for all threads and report the result to ./guider.dat with the compression
        # {0:1} {1:1} -e g -s .

    - {3:1} for all threads and report the result to ./guider.dat without the compression
        # {0:1} {1:1} -e g -s . -d C

    - {3:1} for all threads and print the result to ./guider.out
        # {0:1} {1:1} -e g -o .

    - {3:1} for specific threads to ./guider.out
        # {0:1} {1:1} -e g -o . -g 1022, 1211
        # {0:1} {1:1} -e g -o . -g "thread*" -P

    - Record specific kernel function calls for all threads to ./guider.out
        # {0:1} {1:1} -e g -o . -c "mutex_*"

    - {3:1} that took at least 100 us or longer for all threads to ./guider.out
        # {0:1} {1:1} -e g -o . -q ELAPSED:100

    - report the results of analyzing the recorded data
        => See report command
                    """.format(
                        cmd,
                        mode,
                        "Record function events",
                        "Record all kernel function calls",
                    )

                # file record #
                elif SysMgr.checkMode("filerec"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Report the size of the files loaded on memory
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Options:
    -e  <CHARACTER>             enable options
          [ p:pipe | e:encode ]
    -d  <CHARACTER>             disable options
          [ e:encode | g:general ]
    -s  <DIR|FILE>              save trace data
    -u                          run in the background
    -W  <SEC>                   wait for input
    -w  <TIME:FILE{:VALUE}>     set additional command
    -o  <DIR|FILE>              set output path
    -m  <ROWS:COLS:SYSTEM>      set terminal size
    -a                          show all stats and events
    -r                          set recursive traversal of directories
    -g  <COMM|TID{:FILE}>       set task filter
    -c  <PATH>                  set target path
    -Q                          print all rows in a stream
    -q  <NAME{:VALUE}>          set environment variables
    -E  <DIR>                   set cache dir path
    -v                          verbose
                    """

                    helpStr += """
Examples:
    - {2:1} of on-memory files for all processes to ./guider.out
        # {0:1} {1:1} -o . -a

    - {2:1} of on-memory files for specific threads
        # {0:1} {1:1} -g a.out

    - {2:1} of specific on-memory files
        # {0:1} {1:1} -c "/home/test/BIN, /home/work/DATA"
        # {0:1} {1:1} -c "/home/test/*"

    - {2:1} of specific on-memory files from specific directories recursively
        # {0:1} {1:1} -c "/usr/share" -r

    - {2:1} on each intervals of on-memory files for all processes to ./guider.out
        # {0:1} {1:1} -o . -i

    - {2:1} of on-memory files for all processes to ./guider.out and make the readahead list to readahead.list
        # {0:1} {1:1} -o . -q RALIST
        # {0:1} {1:1} -o . -q RALIST:/data/readahead2.list
        # {0:1} {1:1} -o . -q RALIST, RAMIN:4096
        # {0:1} {1:1} -o . -q RALIST, RAMERGE
        # {0:1} {1:1} -o . -q RALIST, RAALLOWLIST:allow.list
        # {0:1} {1:1} -o . -q RALIST, RADENYLIST:deny.list
        # {0:1} {1:1} -o . -q RALIST, RAADDLIST:add.list
                    """.format(
                        cmd, mode, "Report the analysis result"
                    )

                # report #
                elif SysMgr.checkMode("report"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Report the results of analyzing the recorded data
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Options:
    -e  <CHARACTER>             enable options
          [ p:pipe | e:encode ]
    -d  <CHARACTER>             disable options
          [ e:encode | g:general | l:latency | u:user ]
    -o  <DIR|FILE>              set output path
    -m  <ROWS:COLS:SYSTEM>      set terminal size
    -a                          show all stats and events
    -g  <COMM|TID{:FILE}>       set task filter
    -I  <DIR|FILE>              set input path
    -q  <NAME{:VALUE}>          set environment variables
    -E  <DIR>                   set cache dir path
    -v                          verbose
                    """

                    helpStr += """
Examples:
    - {3:1} based on ./guider.dat to ./guider.out
        # {0:1} {1:1}

    - {3:1} based on trace.dat
        # {0:1} {1:1} trace.dat

    - {3:1} based on ./guider.dat except for user-level call-stacks to ./guider.out
        # {0:1} {1:1} -d u

    - {3:1} based on ./guider.dat to ./guider.out and draw the flame graph
        # {0:1} {1:1} -q DRAWFLAME

    - Report all the analysis result {2:1} having TID 1234 or COMM including a.out to ./guider.out
        # {0:1} {1:1} -o . -g "1234, a.out" -a

    - {3:1} based on ./guider.dat to ./guider.out with sched block time
        # {0:1} {1:1} -d l

    - {3:1} based on ./guider.dat to ./guider.out with higher time resolution
        # {0:1} {1:1} -q PRECISE

    - Convert the compressed recording data to the original one
        # {0:1} {1:1} ./guider.dat -s .

    - Report all the analysis result including interval information for all threads to ./guider.out
        # {0:1} {1:1} -o . -a -i

    - {3:1} including preemption info {2:1} to ./guider.out
        # {0:1} {1:1} -o . -p 1234, 4567

    - {3:1} {2:1} to ./guider.out within specific interval range in second unit
        # {0:1} {1:1} -o . -q TRIM:2:9
        # {0:1} {1:1} -o . -q TRIM::9
        # {0:1} {1:1} -o . -q TRIM:2:

    - {3:1} {2:1} to ./guider.out after converting all target inodes to paths from specific directory
        # {0:1} {1:1} -o . -q CONVINODE
        # {0:1} {1:1} -o . -q CONVINODE:/data

    - {3:1} {2:1} to ./guider.out and make the readahead list to readahead.list
        # {0:1} {1:1} -o . -q RALIST
        # {0:1} {1:1} -o . -q RALIST:/data/readahead2.list
        # {0:1} {1:1} -o . -q RALIST, CONVINODE:/data
        # {0:1} {1:1} -o . -q RALIST, RAMIN:4096
        # {0:1} {1:1} -o . -q RALIST, RAMERGE
        # {0:1} {1:1} -o . -q RALIST, TRIM:2:
        # {0:1} {1:1} -o . -q RALIST, RAALLOWLIST:allow.list
        # {0:1} {1:1} -o . -q RALIST, RADENYLIST:deny.list
        # {0:1} {1:1} -o . -q RALIST, RAADDLIST:add.list

    - {3:1} {2:1} and their siblings to ./guider.out
        # {0:1} {1:1} -o . -P -g 1234, 4567 -a

    - Report the function analysis result with maximum 3-depth {2:1} to ./guider.out
        # {0:1} {1:1} -o . -g 1234 -H 3
                    """.format(
                        cmd,
                        mode,
                        "for specific threads",
                        "Report the analysis result",
                    )

                # general record #
                elif SysMgr.checkMode("genrec"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Record system status
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Options:
    -e  <CHARACTER>             enable options
          [ p:pipe | e:encode ]
    -d  <CHARACTER>             disable options
          [ e:encode | g:general ]
    -s  <DIR|FILE>              save trace data
    -u                          run in the background
    -W  <SEC>                   wait for input
    -o  <DIR|FILE>              set output path
    -m  <ROWS:COLS:SYSTEM>      set terminal size
    -Q                          print all rows in a stream
    -q  <NAME{:VALUE}>          set environment variables
    -R  <INTERVAL:TIME:TERM>    set repeat count
    -E  <DIR>                   set cache dir path
    -v                          verbose
                    """

                    helpStr += """
Examples:
    - Report the analysis result of system to ./guider.out
        # {0:1} {1:1} -o .

    - Report the analysis result of system to ./guider.out for 3 seconds
        # {0:1} {1:1} -o . -R 3s
                    """.format(
                        cmd, mode
                    )

                # record #
                elif (
                    SysMgr.checkMode("rec")
                    or SysMgr.checkMode("iorec")
                    or SysMgr.checkMode("sysrec")
                ):

                    # thread #
                    if SysMgr.checkMode("rec"):
                        helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Record thread events
                        """.format(
                            cmd, mode
                        )
                    # syscall #
                    elif SysMgr.checkMode("sysrec"):
                        helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Record syscall events
                        """.format(
                            cmd, mode
                        )
                    # I/O #
                    else:
                        helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Record I/O events
                        """.format(
                            cmd, mode
                        )

                    helpStr += """
Options:
  [collect]
    -e  <CHARACTER>             enable options
          [ b:block | B:binder | c:cgroup | d:disk
            e:encode | f:fs | g:graph | i:irq | I:i2c
            k:kvm | L:lock | m:mem | n:net | o:io_uring
            p:pipe | r:reset | P:power | w:workqueue ]
    -d  <CHARACTER>             disable options
          [ a:all | c:cpu | C:compress | e:encode
            g:general ]
    -s  <DIR|FILE>              save trace data
    -f                          force execution
    -u                          run in the background
    -W  <SEC>                   wait for input
    -b  <SIZE:KB>               set buffer size
    -D                          trace task dependency
    -t  <SYSCALL>               trace syscall
    -B  <DIR|FILE>              set command script path
    -w  <TIME:FILE{:VALUE}>     set additional command
    -U  <NAME:FUNC|ADDR:FILE>   set user event
    -K  <NAME:FUNC|ADDR:ARGS>   set kernel event
    -R  <INTERVAL:TIME:TERM>    set repeat count
    -L  <PATH>                  set log file

  [report]
    -a                          show all stats and events
    -o  <DIR|FILE>              set output path
    -S  <CHARACTER>             sort by key
          [ c:cpu / m:memory / p:pid / b:block
            w:wfc / n:new / r:runtime / f:file ]
    -P                          group threads in a same process
    -p  <TID>                   show preemption info
    -O  <CORE>                  set core filter
    -L  <RES:PER>               set graph layout (TOTAL PER: 6)
    -m  <ROWS:COLS:SYSTEM>      set terminal size
    -i  <SEC>                   set interval
    -Q                          print all rows in a stream
    -q  <NAME{:VALUE}>          set environment variables

  [common]
    -g  <COMM|TID{:FILE}>       set task filter
    -C  <PATH>                  set config path
    -A  <ARCH>                  set CPU type
    -c  <EVENT:COND>            set custom event
    -E  <DIR>                   set cache dir path
    -k  <COMM|TID:SIG{:CONT}>   set signal
    -z  <COMM|TID:MASK{:CONT}>  set CPU affinity
    -Y  <POLICY:PRIO|TIME       set sched
         {:TID|COMM:CONT}>
        <CLASS:{{WHICH:}}PRIO
         :TID|COMM>
    -v                          verbose
                    """

                    helpStr += """
Examples:
    - {2:1} of all threads to ./guider.dat
        # {0:1} {1:1} -s .

    - {2:1} of specific threads that having TID bigger than 1234 to ./guider.dat
        # {0:1} {1:1} -s . -g ">1234"

    - {2:1} of all threads and their commands
        # {0:1} {1:1} -s . -B

    - {2:1} of all threads to ./guider.dat for only 3 seconds
        # {0:1} {1:1} -s . -R 3

    - {2:1} of all threads to ./guider.dat every 3 seconds continuously
        # {0:1} {1:1} -s . -R 3:1:1

    - {2:1} of all threads to ./guider.dat with fastest initialization
        # {0:1} {1:1} -s . -q FASTINIT

    - record specific events including memory, block, irq of all threads to ./guider.dat in the background
        # {0:1} {1:1} -s . -e m, b, i -u

    - {2:1} including specific syscalls of all threads to ./guider.dat
        # {0:1} {1:1} -s . -t sys_read, write
        # {0:1} {1:1} -s . -t "write*", "*64"

    - {2:1} including lock of all threads to ./guider.dat
        # {0:1} {1:1} -s . -e L

    - {2:1} including specific user function of all threads to ./guider.dat
        # {0:1} {1:1} -s . -U "evt1:func1:/tmp/a.out, evt2:0x1234:/tmp/b.out" -q OBJDUMP:/usr/bin/objdump

    - {2:1} including specific kernel function of all threads to ./guider.dat
        # {0:1} {1:1} -s . -d c -K "evt1:func1:u32, evt2:0x1234:s16, evt3:func2:x16"

    - {2:1} including specific kernel function with args of all threads on x86 to ./guider.dat
        # {0:1} {1:1} -s . -d c -K "open:do_sys_open:dfd=%ax filename=%bx;u64 flags=%cx;s32 mode=+4(\$stack):NONE"

    - {2:1} including specific kernel function with register values of all threads on x86 to ./guider.dat
        # {0:1} {1:1} -s . -d c -K "strace32:func1:%bp/u32.%sp/s64, strace:0x1234:\$stack:NONE"

    - {2:1} including specific kernel function with the return value of all threads to ./guider.dat
        # {0:1} {1:1} -s . -d c -K "openfile:getname::*string, access:0x1234:NONE:*string"
        # {0:1} {1:1} -s . -d c -K "openfile:getname::**string, access:0x1234:NONE:*string"

    - {2:1} of all threads to ./guider.dat and execute user commands
        # {0:1} {1:1} -s . -w BEFORE:/tmp/started:1, BEFORE:ls

    - Report the results of analyzing the recorded data
        => See report command
                    """.format(
                        cmd, mode, "Record thread events"
                    )

                # file top #
                elif SysMgr.checkMode("ftop"):
                    fileTopStr = topCommonStr

                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Monitor the status of open files, sockets, pipes
                        """.format(
                        cmd, mode
                    )

                    examStr = """
Examples:
    - Monitor all processes sorted by the number of file descriptors
        # {0:1} {1:1}

    - Monitor open files, sockets, pipes for the specific process newly executed
        # {0:1} {1:1} -I ./a.out

    - Monitor open files, sockets, pipes for all processes
        # {0:1} {1:1} -a
        # {0:1} {1:1} -a -Q

    - Monitor open files, sockets, pipes for all processes and print about them in JSON format
        # {0:1} {1:1} -J
        # {0:1} {1:1} -J -Q
        # {0:1} {1:1} -a -J

    - Monitor open files, sockets, pipes for specific processes
        # {0:1} {1:1} "test"
        # {0:1} {1:1} "test*"
        # {0:1} {1:1} "*test"

    - Monitor open files, sockets, pipes including null for all processes
        # {0:1} {1:1} -g :"*null*"

    - Monitor open files, sockets, pipes including 8000 for the process having COMM test
        # {0:1} {1:1} -g test:"*8000*"

    - Monitor open files, sockets, pipes of specific processes including system
        # {0:1} {1:1} -g system

    - Monitor open files, sockets, pipes for all processes with cmdline
        # {0:1} {1:1} -a -e L
        # {0:1} {1:1} -a -e L -g apps

    - Report analysis result of open files, sockets, pipes to ./guider.out
        # {0:1} {1:1} -o .
        # {0:1} {1:1} -a -o .

    See the top COMMAND help for more examples.
                    """.format(
                        cmd, mode
                    )

                    helpStr += fileTopStr + examStr

                # thread top #
                elif SysMgr.checkMode("ttop"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Monitor the status of threads
                        """.format(
                        cmd, mode
                    )

                    helpStr += topSubStr + topCommonStr + topExamStr

                # cgroup top #
                elif SysMgr.checkMode("cgtop"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Monitor the status of cgroup
                        """.format(
                        cmd, mode
                    )

                    helpStr += topSubStr + topCommonStr + topExamStr

                # vmalloc top #
                elif SysMgr.checkMode("vtop"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Monitor the status of vmalloc
                    """.format(
                        cmd, mode
                    )

                    examStr = """
Examples:
    - Monitor the status of vmalloc
        # {0:1} {1:1}

    - Monitor the status of vmalloc using filter
        # {0:1} {1:1} -g fork

    See the top COMMAND help for more examples.
                    """.format(
                        cmd, mode
                    )

                    helpStr += topSubStr + topCommonStr + examStr

                # slab top #
                elif SysMgr.checkMode("slabtop"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Monitor the status of slab

Sort:
    size:    the size of an object
    active:  the number of active objects
    actsize: the size of active objects
    total:   the size of all objects
                        """.format(
                        cmd, mode
                    )

                    examStr = """
Examples:
    - Monitor the status of slab
        # {0:1} {1:1}

    - Monitor the status of slab using type filter
        # {0:1} {1:1} -g dentry

    - Monitor the status of slab sorted by specific values
        # {0:1} {1:1} -S size
        # {0:1} {1:1} -S active
        # {0:1} {1:1} -S actsize
        # {0:1} {1:1} -S total

    See the top COMMAND help for more examples.
                    """.format(
                        cmd, mode
                    )

                    helpStr += topSubStr + topCommonStr + examStr

                # syscall top #
                elif SysMgr.checkMode("systop"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -g <TARGET> [OPTIONS] [--help]

Description:
    Monitor syscalls for a specific thread
                        """.format(
                        cmd, mode
                    )

                    examStr = """
Examples:
    - {2:1} {3:1}
        # {0:1} {1:1} -g a.out

    - {2:1} with stdev for elapsed time {3:1}
        # {0:1} {1:1} -g a.out -q STDEV

    - {2:1} with stdev and histogram for elapsed time {3:1}
        # {0:1} {1:1} -g a.out -q STDEV, PRINTHIST

    - {2:1} with backtrace {3:1}
        # {0:1} {1:1} -g a.out -H

    - {2:1} with python backtrace {3:1}
        # {0:1} {1:1} -g a.out -H -q PYSTACK

    - {2:1} for child tasks created by specific threads
        # {0:1} {1:1} -g a.out -W

    - {2:1} {3:1} and report the result in JSON format
        # {0:1} {1:1} -g a.out -J
        # {0:1} {1:1} -g a.out -J -Q

    - {2:1} {3:1} every 2 second
        # {0:1} {1:1} -g 1234 -R 2:

    - Monitor CPU usage on whole system of syscalls for a specific thread
        # {0:1} {1:1} -g a.out -e c

    - {2:1} {3:1} with colorful elapsed time exceeds 0.1 second
        # {0:1} {1:1} -g a.out -q ELAPSED:0.1

    - Monitor only successful syscalls {3:1}
        # {0:1} {1:1} -g a.out -q ONLYOK

    - {2:1} for child tasks created by a specific thread
        # {0:1} {1:1} -g a.out -q WAITCLONE

    - Monitor only failed syscalls {3:1}
        # {0:1} {1:1} -g a.out -q ONLYFAIL

    - {2:1} {4:1} and print standard output for child tasks
        # {0:1} {1:1} a.out -q NOMUTE

    - {2:1} {4:1} excluding specific environment variable
        # {0:1} {1:1} a.out -q REMOVEENV:MAIL

    - {2:1} {4:1} using merged symbols
        # {0:1} {1:1} a.out -q ALLSYM

    - {2:1} from a specific binary and redirect standard I/O of child tasks to specific files
        # {0:1} {1:1} "ls" -q STDIN:"./stdin"
        # {0:1} {1:1} "ls" -q STDOUT:"./stdout"
        # {0:1} {1:1} "ls" -q STDERR:"/dev/null"

    - {2:1} and report the result to ./guider.out when SIGINT arrives
        # {0:1} {1:1} -o .

    - {2:1} {3:1} (wait for new target if no task)
        # {0:1} {1:1} -g a.out -q WAITTASK
        # {0:1} {1:1} -g a.out -q WAITTASK, NOPIDCACHE

    - {2:1} {3:1} even if the master tracer is terminated
        # {0:1} {1:1} -g a.out -q CONTALONE

    - {2:1} except for wait status {3:1}
        # {0:1} {1:1} -g a.out -q EXCEPTWAIT

    - {2:1} except for register info {3:1}
        # {0:1} {1:1} -g a.out -q NOCONTEXT

    - {2:1} {3:1} consumed CPU more than 10%
        # {0:1} {1:1} -g a.out -q CPUCOND:10

    - {2:1} except for no symbol backtraces {3:1}
        # {0:1} {1:1} -g a.out -H -q ONLYSYM

    - {2:1} {3:1} with call interval info
        # {0:1} {1:1} -g a.out -q INTERCALL

    - {2:1} {3:1} with call interval info including stdev
        # {0:1} {1:1} -g a.out -q INTERCALL, STDEV

    - {2:1} {3:1} after loading all symbols in stop status
        # {0:1} {1:1} -g a.out -q STOPTARGET

    - {2:1} for 4th and 5th new threads in each new processes {4:1}
        # {0:1} {1:1} a.out -g a.out -q TARGETNUM:4, TARGETNUM:5
        # {0:1} {1:1} -I a.out -g a.out -q TARGETNUM:4, TARGETNUM:5

    - {2:1} {4:1} including specific environment variables
        # {0:1} {1:1} a.out -q ENV:TEST=1, ENV:PATH=/data
        # {0:1} {1:1} a.out -q ENVFILE:/data/env.sh

    - {2:1} with breakpoint for read syscalls {3:1}
        # {0:1} {1:1} -g 1234 -c read
        # {0:1} {1:1} -g 1234 -c read -a

    See the top COMMAND help for more examples.
                    """.format(
                        cmd,
                        mode,
                        "Monitor syscalls",
                        "for specific threads",
                        "from a specific binary",
                    )

                    helpStr += topSubStr + topCommonStr + examStr

                # python top #
                elif SysMgr.checkMode("pytop"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -g <TARGET> [OPTIONS] [--help]

Description:
    Monitor python calls
                        """.format(
                        cmd, mode
                    )

                    examStr = """
Examples:
    - {2:1} {3:1} using 100 us sampling
        # {0:1} {1:1} -g iotop

    - {2:1} for child tasks created by a specific thread
        # {0:1} {1:1} -g iotop -W

    - {2:1} with backtrace {3:1} (merged native stack and python stack from python 3.7)
        # {0:1} {1:1} -g iotop -H

    - {2:1} with backtrace including native symbols {3:1} (merged native stack and python stack from python 3.7)
        # {0:1} {1:1} -g iotop -H -q INCNATIVE

    - {2:1} {3:1} every 2 second for 1 minute with 1 ms sampling
        # {0:1} {1:1} -g 1234 -T 1000 -i 2 -R 1m

    - {2:1} from a specific binary and print standard output for child tasks
        # {0:1} {1:1} iotop -q NOMUTE
        # {0:1} {1:1} "python -c \"while 1: print('OK')\""

    - {2:1} from a specific binary and redirect standard I/O of child tasks to specific files
        # {0:1} {1:1} "ls" -q STDIN:"./stdin"
        # {0:1} {1:1} "ls" -q STDOUT:"./stdout"
        # {0:1} {1:1} "ls" -q STDERR:"/dev/null"

    - {2:1} {3:1} (wait for new target if no task)
        # {0:1} {1:1} iotop -g iotop -q WAITTASK
        # {0:1} {1:1} iotop -g iotop -q WAITTASK:1
        # {0:1} {1:1} iotop -g iotop -q WAITTASK, NOPIDCACHE

    - {2:1} {3:1} even if the master tracer is terminated
        # {0:1} {1:1} iotop -g iotop -q CONTALONE

    - {2:1} except for wait status {3:1}
        # {0:1} {1:1} iotop -g iotop -q EXCEPTWAIT

    - {2:1} except for register info {3:1}
        # {0:1} {1:1} iotop -g iotop -q NOCONTEXT

    - {2:1} {3:1} consumed CPU more than 10%
        # {0:1} {1:1} -g iotop -q CPUCOND:10

    - {2:1} except for no symbol functions {3:1}
        # {0:1} {1:1} iotop -g iotop -q ONLYSYM

    - {2:1} {3:1} after loading all symbols in stop status
        # {0:1} {1:1} iotop -g iotop -q STOPTARGET

    - {2:1} for 4th and 5th new threads in each new processes from a specific binary
        # {0:1} {1:1} iotop -g iotop -q TARGETNUM:4, TARGETNUM:5
        # {0:1} {1:1} -I iotop -g iotop -q TARGETNUM:4, TARGETNUM:5

    - {2:1} for a specific binary execution with environment variables
        # {0:1} {1:1} iotop -q ENV:TEST=1, ENV:PATH=/data
        # {0:1} {1:1} iotop -q ENVFILE:/data/env.sh

    - Monitor CPU usage on whole system of python calls {3:1}
        # {0:1} {1:1} -g iotop -e c

    - {2:1} with breakpoint for peace {3:1}
        # {0:1} {1:1} -g 1234 -c peace
        # {0:1} {1:1} -g 1234 -c peace -a

    - {2:1} {3:1} and draw timeline segments for all python call samples
        # {0:1} {1:1} -g iotop -q TIMELINE, TIMEUNIT:ms, INTERCALL, DURATION:10 -a
        # {0:1} {1:1} -g iotop -q TIMELINE, TIMEUNIT:us, INTERCALL, DURATION:100 -H -a

    See the top COMMAND help for more examples.
                    """.format(
                        cmd,
                        mode,
                        "Monitor python calls",
                        "for specific threads",
                    )

                    helpStr += topSubStr + topCommonStr + examStr

                # kernel top #
                elif SysMgr.checkMode("ktop"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -g <TARGET> [OPTIONS] [--help]

Description:
    Monitor kernel function calls
                        """.format(
                        cmd, mode
                    )

                    examStr = """
Examples:
    - {2:1} {3:1}
        # {0:1} {1:1} -g a.out

    - {2:1} {4:1}
        # {0:1} {1:1} a.out
        # {0:1} {1:1} "sh -c \\"while [ 1 ]; do echo "OK"; done;\\""
        # {0:1} {1:1} -I a.out

    - {2:1} and report the result to ./guider.out when SIGINT arrives
        # {0:1} {1:1} -o .

    - {2:1} and report the result in JSON format
        # {0:1} {1:1} -J
        # {0:1} {1:1} -J -Q

    - {2:1} {3:1} having specific TID
        # {0:1} {1:1} -g 1234 -q ONLYPID

    - {2:1} {3:1} having specific task name
        # {0:1} {1:1} -g 1234 -q ONLYCOMM

    - {2:1} for specific processes having specific task name
        # {0:1} {1:1} -g 1234 -q ONLYPROC

    - {2:1} using compressed cache {3:1}
        # {0:1} {1:1} -g a.out -q COMPCACHE

    - {2:1} without using previous sample cache {3:1}
        # {0:1} {1:1} -g a.out -q NOSAMPLECACHE

    - {2:1} and standard output {4:1}
        # {0:1} {1:1} a.out -q NOMUTE

    - {2:1} from a specific binary and redirect standard I/O of child tasks to specific files
        # {0:1} {1:1} "ls" -q STDIN:"./stdin"
        # {0:1} {1:1} "ls" -q STDOUT:"./stdout"
        # {0:1} {1:1} "ls" -q STDERR:"/dev/null"

    - {2:1} {4:1} excluding specific environment variable
        # {0:1} {1:1} a.out -q REMOVEENV:MAIL

    - {2:1} {3:1} {4:1}
        # {0:1} {1:1} a.out -g a.out
        # {0:1} {1:1} -I a.out -g a.out

    - {2:1} for child tasks created by a specific thread
        # {0:1} {1:1} -g a.out -q WAITCLONE

    - {2:1} {3:1} (wait for new target if no task) {4:1}
        # {0:1} {1:1} a.out -g a.out -q WAITTASK
        # {0:1} {1:1} a.out -g a.out -q WAITTASK:1
        # {0:1} {1:1} a.out -g a.out -q WAITTASK, NOPIDCACHE

    - {2:1} {3:1} {4:1} even if the master tracer is terminated
        # {0:1} {1:1} a.out -g a.out -q CONTALONE

    - {2:1} {4:1} except for wait status {3:1}
        # {0:1} {1:1} a.out -g a.out -q EXCEPTWAIT

    - {2:1} {3:1} consumed CPU more than 10%
        # {0:1} {1:1} -g a.out -q CPUCOND:10

    - {2:1} for 4th and 5th new threads in each new processes {4:1}
        # {0:1} {1:1} a.out -g a.out -q TARGETNUM:4, TARGETNUM:5
        # {0:1} {1:1} -I a.out -g a.out -q TARGETNUM:4, TARGETNUM:5

    - {2:1} {4:1} including specific environment variables
        # {0:1} {1:1} a.out -q ENV:TEST=1, ENV:PATH=/data
        # {0:1} {1:1} a.out -q ENVFILE:/data/env.sh

    - {2:1} {3:1} after user input
        # {0:1} {1:1} -g a.out -W

    - {2:1} {3:1} after 5 seconds
        # {0:1} {1:1} -g a.out -W 5s

    - {2:1} {3:1} from 100 seconds of uptime
        # {0:1} {1:1} -g a.out -q STARTCONDTIME:100 -W

    - {2:1} {3:1} until 100 seconds of uptime
        # {0:1} {1:1} -g a.out -q EXITCONDTIME:100 -R

    - {2:1} {3:1} every 2 second for 1 minute with 1 ms sampling
        # {0:1} {1:1} -g 1234 -T 1000 -i 2 -R 1m

    - Monitor CPU usage on whole system of native function calls {3:1}
        # {0:1} {1:1} -g a.out -e c

    See the top COMMAND help for more examples.
                    """.format(
                        cmd,
                        mode,
                        "Monitor kernel function calls",
                        "for specific threads",
                        "from a specific binary",
                    )

                    helpStr += topSubStr + topCommonStr + examStr

                # usercall top #
                elif SysMgr.checkMode("utop"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -g <TARGET> [OPTIONS] [--help]

Description:
    Monitor native function calls
                        """.format(
                        cmd, mode
                    )

                    examStr = """
Examples:
    - {3:1} {4:1}
        # {0:1} {1:1} -g a.out

    - {3:1} {5:1}
        # {0:1} {1:1} a.out
        # {0:1} {1:1} "sh -c \\"while [ 1 ]; do echo "OK"; done;\\""
        # {0:1} {1:1} -I a.out

    - Monitor native and JIT-compiled function calls {4:1}
{2:1}
        # {0:1} {1:1} -g node -q JITSYM
        # {0:1} {1:1} -g java -q JITSYM

    - {3:1} and report the result to ./guider.out when SIGINT arrives
        # {0:1} {1:1} -o .
        # {0:1} {1:1} -o . -q FORCESUMMARY

    - {3:1} with monitoring processes and report the result to ./guider.out when SIGINT arrives
        # {0:1} {1:1} -o . -w "BEFORE:{0:1} top -Q &"

    - {3:1} and report the result in JSON format
        # {0:1} {1:1} -J
        # {0:1} {1:1} -J -Q

    - {3:1} {4:1} having specific TID
        # {0:1} {1:1} -g 1234 -q ONLYPID

    - {3:1} {4:1} having specific task name
        # {0:1} {1:1} -g 1234 -q ONLYCOMM

    - {3:1} for specific processes having specific task name
        # {0:1} {1:1} -g 1234 -q ONLYPROC

    - {3:1} using merged symbols {4:1}
        # {0:1} {1:1} -g a.out -q ALLSYM

    - {3:1} without using incremental sampling rate {4:1}
        # {0:1} {1:1} -g a.out -q FIXSAMPLING

    - {3:1} using compressed cache {4:1}
        # {0:1} {1:1} -g a.out -q COMPCACHE

    - {3:1} without using previous sample cache {4:1}
        # {0:1} {1:1} -g a.out -q NOSAMPLECACHE

    - {3:1} {4:1} without file loading messages
        # {0:1} {1:1} -g a.out -q NOLOADMSG

    - {3:1} {4:1} with task sync for clone event
        # {0:1} {1:1} -g a.out -q SYNCTASK

    - {3:1} without using file cache {4:1}
        # {0:1} {1:1} -g a.out -q NOFILECACHE

    - {3:1} with debug info {4:1}
        # {0:1} {1:1} -g a.out -q DEBUGINFO
        # {0:1} {1:1} -g a.out -q DEBUGINFO -H
        # {0:1} {1:1} -g a.out -q DEBUGINFO:/usr/lib/libc.so

    - {3:1} and standard output {5:1}
        # {0:1} {1:1} a.out -q NOMUTE

    - {3:1} from a specific binary and redirect standard I/O of child tasks to specific files
        # {0:1} {1:1} "ls" -q STDIN:"./stdin"
        # {0:1} {1:1} "ls" -q STDOUT:"./stdout"
        # {0:1} {1:1} "ls" -q STDERR:"/dev/null"

    - {3:1} {5:1} excluding specific environment variable
        # {0:1} {1:1} a.out -q REMOVEENV:MAIL

    - {3:1} {4:1} with lazy cache loading
        # {0:1} {1:1} -g a.out -q LAZYCACHE

    - {3:1} {4:1} except for DWARF table of specific files
        # {0:1} {1:1} -g a.out -q EXCEPTDWARF:"*deno"

    - {3:1} {4:1} {5:1}
        # {0:1} {1:1} a.out -g a.out
        # {0:1} {1:1} -I a.out -g a.out

    - {3:1} for child tasks created by a specific thread
        # {0:1} {1:1} -g a.out -q WAITCLONE

    - {3:1} {4:1} (wait for new target if no task)
        # {0:1} {1:1} -g a.out -q WAITTASK
        # {0:1} {1:1} -g a.out -q WAITTASK:1
        # {0:1} {1:1} -g a.out -q WAITTASK, NOPIDCACHE

    - {3:1} {4:1} even if the master tracer is terminated {5:1}
        # {0:1} {1:1} a.out -g a.out -q CONTALONE

    - {3:1} except for samples for wait status {4:1}
        # {0:1} {1:1} -g a.out -q EXCEPTWAIT

    - {3:1} {4:1} after the target task awakened
        # {0:1} {1:1} -g a.out -q WAITWAKEUP

    - {3:1} except for register info {4:1}
        # {0:1} {1:1} -g a.out -q NOCONTEXT

    - {3:1} {4:1} consumed CPU more than 10%
        # {0:1} {1:1} -g a.out -q CPUCOND:10

    - {3:1} except for no symbol functions {4:1}
        # {0:1} {1:1} -g a.out -q ONLYSYM

    - {3:1} {4:1} after loading all symbols in stop status
        # {0:1} {1:1} -g a.out -q STOPTARGET

    - {3:1} for 4th and 5th new threads in each new processes {5:1}
        # {0:1} {1:1} a.out -g a.out -q TARGETNUM:4, TARGETNUM:5
        # {0:1} {1:1} -I a.out -g a.out -q TARGETNUM:4, TARGETNUM:5

    - {3:1} {5:1} including specific environment variables
        # {0:1} {1:1} a.out -q ENV:TEST=1, ENV:PATH=/data
        # {0:1} {1:1} a.out -q ENV:LD_DEBUG=libs, ENV:LD_DEBUG=bindings
        # {0:1} {1:1} a.out -q ENV:LD_DEBUG=detail, ENV:LD_DEBUG=files
        # {0:1} {1:1} a.out -q ENV:LD_DEBUG=reloc, ENV:LD_DEBUG=symbols
        # {0:1} {1:1} a.out -q ENV:LD_DEBUG_OUTPUT=./ld.out
        # {0:1} {1:1} a.out -q ENVFILE:/data/env.sh

    - {3:1} {4:1} with DWARF info
        # {0:1} {1:1} -g a.out -eD

    - {3:1} {4:1} after user input
        # {0:1} {1:1} -g a.out -W

    - {3:1} {4:1} after 5 seconds
        # {0:1} {1:1} -g a.out -W 5s

    - {3:1} {4:1} from 100 seconds of uptime
        # {0:1} {1:1} -g a.out -q STARTCONDTIME:100 -W

    - {3:1} {4:1} until 100 seconds of uptime
        # {0:1} {1:1} -g a.out -q EXITCONDTIME:100 -R

    - {3:1} with backtrace {4:1}
        # {0:1} {1:1} -g a.out -H

    - {3:1} with backtrace (no-use-libcorkscrew) {4:1}
        # {0:1} {1:1} -g a.out -H -q NOLIBCORK

    - {3:1} with python backtrace {4:1}
        # {0:1} {1:1} -g a.out -H -q PYSTACK

    - {3:1} with arguments using DWARF {4:1}
        # {0:1} {1:1} -g a.out -q DEBUGINFO, PRINTARG

    - {3:1} with backtrace including arguments using DWARF {4:1}
        # {0:1} {1:1} -g a.out -H -q DEBUGINFO, PRINTBTARG

    - {3:1} {4:1} every 2 second for 1 minute with 1 ms sampling
        # {0:1} {1:1} -g 1234 -T 1000 -i 2 -R 1m

    - Monitor CPU usage on whole system of native function calls {4:1}
        # {0:1} {1:1} -g a.out -e c

    - {3:1} with breakpoint for peace {4:1}
        # {0:1} {1:1} -g 1234 -c peace
        # {0:1} {1:1} -g 1234 -c peace -a

    See the top COMMAND help for more examples.
                    """.format(
                        cmd,
                        mode,
                        jitProfStr,
                        "Monitor native function calls",
                        "for specific threads",
                        "from a specific binary",
                    )

                    helpStr += topSubStr + topCommonStr + examStr

                # break top #
                elif SysMgr.checkMode("btop"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -g <TARGET> [OPTIONS] [--help]

Description:
    Monitor function calls
                        """.format(
                        cmd, mode
                    )

                    examStr = """
    {0:1}

    See the top COMMAND help for more examples.
                    """.format(
                        brkExamStr
                    )

                    helpStr += topSubStr + topCommonStr + examStr

                # all top #
                elif SysMgr.checkMode("atop"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Monitor all system resources
                        """.format(
                        cmd, mode
                    )

                    examStr = """
Examples:
    - Monitor system resource
        # {0:1} {1:1}

    See the top COMMAND help for more examples.
                    """.format(
                        cmd, mode
                    )

                    helpStr += topCommonStr + examStr

                # condition top #
                elif SysMgr.checkMode("ctop"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Monitor resources with threshold
                        """.format(
                        cmd, mode
                    )

                    examStr = """
Examples:
    - {2:1} with threshold condition
        # {0:1} {1:1}
        # {0:1} {1:1} -C /tmp/guider.conf

    - {2:1} with threshold condition and report also in JSON format
        # {0:1} {1:1} -j -Q -q TEXTREPORT
        # {0:1} {1:1} -j -o /tmp -q TEXTREPORT
        # {0:1} {1:1} -C /tmp/guider.conf -j -o /tmp -q TEXTREPORT

    - {2:1} with threshold condition and report the compressed monitoring results to a specific file in the specific directory, and if the directory size exceeds the limit then remove old report files first.
        # {0:1} {1:1} -o /tmp -e C -b 1M -q TEXTREPORT, LIMITREPDIR:10M

    - {2:1} with threshold condition and report the monitoring results to a specific file in the specific directory, and if the directory size exceeds the limit then remove existing files.
        # {0:1} {1:1} -o /tmp -b 1M -q TEXTREPORT, LIMITREPDIR:10M, REMOVEOTHERS

    - {2:1} including normal tasks with threshold condition
        # {0:1} {1:1} -j -q SAVEJSONSTAT

    - {2:1} without threshold condition until CMD_RELOAD event is received
        # {0:1} {1:1} -q NOTHRESHOLD

    - {2:1} after updating original threshold data from the specific file
        # {0:1} {1:1} -q UPDATETHRESHOLD:guider2.conf

    - {2:1} with threshold condition with the cpu limitation in % unit using cgroup
        # {0:1} {1:1} -q LIMITCPU:20
        # {0:1} {1:1} -q LIMITCPU:20@"*yes*|a.out"

    - {2:1} with threshold condition with the memory limitation using cgroup
        # {0:1} {1:1} -q LIMITMEM:50M
        # {0:1} {1:1} -q LIMITMEM:50M@"*yes*|a.out"

    - {2:1} with threshold condition with the block I/O limitation using cgroup
        # {0:1} {1:1} -q LIMITREAD:50M
        # {0:1} {1:1} -q LIMITWRITE:50M
        # {0:1} {1:1} -q LIMITREAD:50M@"*yes*|a.out"
        # {0:1} {1:1} -q LIMITWRITE:50M@"*yes*|a.out"
        # {0:1} {1:1} -q LIMITWRITE:50M@"*yes*|a.out", EACHTASK

    - {2:1} with threshold condition and print the output of child tasks
        # {0:1} {1:1} -q NOMUTE

    - {2:1} without socket profiling
        # {0:1} {1:1} -q NOSOCKPROF

    See the top COMMAND help for more examples.
                    """.format(
                        cmd, mode, "Monitor resources"
                    )

                    helpStr += topSubStr + topCommonStr + examStr

                # stack top #
                elif SysMgr.checkMode("stacktop"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -g <TARGET> [OPTIONS] [--help]

Description:
    Monitor kernel stacks for threads
                        """.format(
                        cmd, mode
                    )

                    examStr = """
Examples:
    - Monitor kernel stacks for specific threads
        # {0:1} {1:1} -g chrome

    See the top COMMAND help for more examples.
                    """.format(
                        cmd, mode
                    )

                    helpStr += topSubStr + topCommonStr + examStr

                # perf top #
                elif SysMgr.checkMode("ptop"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Monitor performance stats using PMU(Performance Monitoring Unit)
                        """.format(
                        cmd, mode
                    )

                    examStr = """
Examples:
    - Monitor performance stats of specific threads
        # {0:1} {1:1} -g chrome

    See the top COMMAND help for more examples.
                    """.format(
                        cmd, mode
                    )

                    helpStr += topSubStr + topCommonStr + examStr

                # mem top #
                elif SysMgr.checkMode("mtop"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Monitor memory details
                        """.format(
                        cmd, mode
                    )

                    examStr = """
Examples:
    - Monitor memory details for specific processes
        # {0:1} {1:1} -g chrome

    - Monitor memory details without smaps info for specific processes
        # {0:1} {1:1} -g chrome -q NOSMAPS

    - Monitor memory details including 30 lines of active slabs for specific processes
        # {0:1} {1:1} -g chrome -q NRSLAB:30

    - Monitor memory details including total slabs for specific processes
        # {0:1} {1:1} -g chrome -q TOTALSLAB

    See the top COMMAND help for more examples.
                    """.format(
                        cmd, mode
                    )

                    helpStr += topSubStr + topCommonStr + examStr

                # wss top #
                elif SysMgr.checkMode("wtop"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -g <TARGET> [OPTIONS] [--help]

Description:
    Monitor WSS(Working Set Size) of specific processes after clearing their all page reference bits
                        """.format(
                        cmd, mode
                    )

                    examStr = """
Examples:
    - Monitor WSS(Working Set Size) of specific processes and reset WSS when SIGQUIT(Ctrl+\) arrives
        # {0:1} {1:1} chrome

    - Monitor WSS(Working Set Size) of specific processes with all footprints
        # {0:1} {1:1} chrome -a

    See the top COMMAND help for more examples.
                    """.format(
                        cmd, mode
                    )

                    helpStr += topSubStr + topCommonStr + examStr

                # report top #
                elif SysMgr.checkMode("rtop"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Report system status in JSON format
                        """.format(
                        cmd, mode
                    )

                    examStr = """
Examples:
    - {2:1} /tmp/guider.report
        # {0:1} {1:1}

    - {2:1} console standard output
        # {0:1} {1:1} -Q

    - {2:1} /tmp/guider.report with maximum 20 task items
        # {0:1} {1:1} -q NRTOPRANK:20

    - Report system status including threshold events in JSON format to /tmp/guider.report
        # {0:1} {1:1} -C ./guider.conf
        # {0:1} {1:1} -C ./guider.conf -e l

    - {2:1} ./guider.report in the background every second
        # {0:1} {1:1} -j . -u

    - Report system status with the return value of external functions in JSON format to /tmp/guider.report
        # {0:1} {1:1} -q REPORTFUNC:test.py:test

    - Stop reporting in the background
        # {0:1} stop

    See the top COMMAND help for more examples.
                    """.format(
                        cmd, mode, "Report system status in JSON format to"
                    )

                    helpStr += topSubStr + topCommonStr + examStr

                # background top #
                elif SysMgr.checkMode("bgtop"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Collect system status in the background until get a stop signal
                        """.format(
                        cmd, mode
                    )

                    examStr = """
Examples:
    - Collect system status to ./guider.out in the background
        # {0:1} {1:1} -o .

    - Stop collecting processes in the background and let them report system analysis result
        # {0:1} stop

    See the top COMMAND help for more examples.
                    """.format(
                        cmd, mode
                    )

                    helpStr += topSubStr + topCommonStr + examStr

                # disk top #
                elif SysMgr.checkMode("disktop"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Monitor the status of storage devices
                        """.format(
                        cmd, mode
                    )

                    examStr = """
Examples:
    - Monitor the status of all storage devices
        # {0:1} {1:1}

    See the top COMMAND help for more examples.
                    """.format(
                        cmd, mode
                    )

                    helpStr += topSubStr + topCommonStr + examStr

                # DLT top #
                elif SysMgr.checkMode("dlttop"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Monitor DLT logs
                        """.format(
                        cmd, mode
                    )

                    examStr = """
Examples:
    - {2:1}
        # {0:1} {1:1}

    - {2:1} using libdlt.so from specific path
        # {0:1} {1:1} -q LIBDLT:/home/iipeace/test/libdlt.so

    - Change default log level to be printed
        # {0:1} {1:1} -c INFO

    - {2:1} including specific string
        # {0:1} {1:1} -g test

    - {2:1} from specific address for dlt-daemon
        # {0:1} {1:1} -X 127.0.0.1:12345

    - {2:1} with connection retry to dlt-daemon every 1,000 ms
        # {0:1} {1:1} -q RETRYCONN:1000

    - {2:1} generated since now
        # {0:1} {1:1} -q TAIL

    See the top COMMAND help for more examples.
                    """.format(
                        cmd, mode, "Monitor DLT logs"
                    )

                    helpStr += topSubStr + topCommonStr + examStr

                # dbus top #
                elif SysMgr.checkMode("dbustop"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Monitor D-Bus messages
                        """.format(
                        cmd, mode
                    )

                    examStr = """
Examples:
    - {2:1}
        # {0:1} {1:1}

    - {2:1} including DBus interfaces
        # {0:1} {1:1} -g dbus-daemon

    - {2:1} for dbus-client process
        # {0:1} {1:1} -g dbus-client

    - {2:1} including specific word
        # {0:1} {1:1} -c test

    - {2:1} and erase specific words in live messages
        # {0:1} {1:1} -G sendData

    - {2:1} for a specific session bus
        # DBUS_SESSION_BUS_ADDRESS=$(cat addr) {0:1} {1:1}

    See the top COMMAND help for more examples.
                    """.format(
                        cmd, mode, "Monitor D-Bus messages"
                    )

                    helpStr += topSubStr + topCommonStr + examStr

                # network top #
                elif SysMgr.checkMode("ntop"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Monitor the status of network devices
                        """.format(
                        cmd, mode
                    )

                    examStr = """
Examples:
    - Monitor the status of all network devices
        # {0:1} {1:1}

    See the top COMMAND help for more examples.
                    """.format(
                        cmd, mode
                    )

                    helpStr += topSubStr + topCommonStr + examStr

                # process top #
                elif SysMgr.isTopMode():
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Monitor the status of processes
                        """.format(
                        cmd, mode
                    )

                    helpStr += topSubStr + topCommonStr + topExamStr

                # mount #
                elif SysMgr.checkMode("mount"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -I <DEV:DIR:FS:FLAGS:DATA> [OPTIONS] [--help]

Description:
    Mount filesystem
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Options:
    -I  <DEV:DIR:FS:FLAGS:DATA> set mount point
    -f                          force execution
    -m  <ROWS:COLS:SYSTEM>      set terminal size
    -v                          verbose

Flags:
    See the man page
                    """

                    helpStr += """
Examples:
    - Mount filesystem
        # {0:1} {1:1} "/dev/sda1:/data/fs:ext4"
        # {0:1} {1:1} -I "/dev/sda1:/data/fs:ext4"

    - Remount filesystem
        # {0:1} {1:1} "/dev/sda1:/data/fs:ext4:REMOUNT,RDONLY"
                    """.format(
                        cmd, mode
                    )

                # umount #
                elif SysMgr.checkMode("umount"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -I <TARGET:FLAGS> [OPTIONS] [--help]

Description:
    Unmount filesystem
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Options:
    -I  <TARGET:FLAGS>          set mount point
    -f                          force execution
    -m  <ROWS:COLS:SYSTEM>      set terminal size
    -v                          verbose

Flags:
    See the man page
                    """

                    helpStr += """
Examples:
    - Unmount filesystem
        # {0:1} {1:1} "/dev/sda1"
        # {0:1} {1:1} -I "/dev/sda1"
                    """.format(
                        cmd, mode
                    )

                # strings #
                elif SysMgr.checkMode("strings"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -g <TARGET> [OPTIONS] [--help]

Description:
    Print the sequences of printable characters in files
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Options:
    -I  <FILE>                  set file path
    -a                          show position info
    -g  <WORD>                  set filter
    -o  <DIR|FILE>              set output path
    -m  <ROWS:COLS:SYSTEM>      set terminal size
    -v                          verbose
                    """

                    helpStr += """
Examples:
    - Print printable characters in a specific file
        # {0:1} {1:1} a.out
        # {0:1} {1:1} -I a.out

    - Print the sequences of printable characters in a specific file
        # {0:1} {1:1} -I a.out -a

    - Print specific printable characters in a specific file
        # {0:1} {1:1} -I a.out -g PEACE
                    """.format(
                        cmd, mode
                    )

                # cgroup #
                elif SysMgr.checkMode("cgroup"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -g <CMD:SUB:NAME:TASK|VAL@FILE> [OPTIONS] [--help]

Description:
    Control cgroups
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Options:
    -e  <CHARACTER>             enable options
          [ t:thread | e:encode ]
    -P                          group threads in a same process
    -m  <ROWS:COLS:SYSTEM>      set terminal size
    -v                          verbose

Commands:
    CREATE   create a new group
    ADD      add specific tasks to a group
    MOVE     move specific tasks from a group to another group
    REMOVE   remove specific tasks from a group
    DELETE   delete a group
    WRITE    write value to the specific file
    LIST     print all tasks in a group
                    """

                    helpStr += """
Examples:
    - Make a new cpu group
        # {0:1} {1:1} CREATE:cpu:test1:
        # {0:1} {1:1} CREATE:cpu:test1:"*"

    - Add specific processes to a specific group
        # {0:1} {1:1} ADD:cpu:test1:"*a.out*"

    - Add specific threads to a specific group
        # {0:1} {1:1} ADD:cpu:test1:"*a.out*" -e t

    - Move specific processes between cpu groups
        # {0:1} {1:1} MOVE:cpu/test1:cpu/test2:"*a.out*"

    - Remove specific processes from a cpu group
        # {0:1} {1:1} REMOVE:cpu/test1:"*a.out*"

    - Delete a cpu group
        # {0:1} {1:1} DELETE:cpu:test1:*

    - Write value to the specific file
        # {0:1} {1:1} WRITE:memory:test2:100000@memory.limit_in_bytes

    - Print all processes in a cpu group
        # {0:1} {1:1} LIST:cpu:test1:*
                    """.format(
                        cmd, mode
                    )

                # print #
                elif SysMgr.checkMode("print"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -I <TARGET> [OPTIONS] [--help]

Description:
    Print files
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Options:
    -I  <FILE>                  set file path
    -a                          show position info
    -g  <WORD>                  set filter
    -o  <DIR|FILE>              set output path
    -m  <ROWS:COLS:SYSTEM>      set terminal size
    -Q                          print all rows in a stream
    -q  <NAME{:VALUE}>          set environment variables
    -v                          verbose
                    """

                    helpStr += """
Examples:
    - Print target files including gziped files
        # {0:1} {1:1} -I a.out
        # {0:1} {1:1} "a.out, test*.txt"

    - Print specific lines including specific words for target files
        # {0:1} {1:1} "a.out, test*.txt" -g "peace, best"

    - Print target files to the output file
        # {0:1} {1:1} "a.out, test*.txt" -o output.txt

    - Print the contents of target files as much as a specified size
        # {0:1} {1:1} "a.out, test*.txt" -q SIZE:1K

    - Print the last file of target files
        # {0:1} {1:1} "a.out, test*.txt" -q TAIL
        # {0:1} {1:1} "a.out, test*.txt" -q TAIL:100
                    """.format(
                        cmd, mode
                    )

                # dump #
                elif SysMgr.checkMode("dump"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -g <TARGET> [OPTIONS] [--help]

Description:
    Dump target memory
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Options:
    -u                          run in the background
    -a                          show all stats with registers
    -g  <COMM|TID>              set task filter
    -I  <RANGE>                 set memory address
    -R  <TIME>                  set timer
    -o  <DIR|FILE>              set output path
    -m  <ROWS:COLS:SYSTEM>      set terminal size
    -v                          verbose
                    """

                    helpStr += """
Examples:
    - {2:1} memory to the specific file
        # {0:1} {1:1} -g a.out -I 0x1234-0x4567 -o dump.out

    - {2:1} memory mapped to a specific file to the specific file
        # {0:1} {1:1} -g a.out -I a.out -o dump.out

    - {2:1} stack to the specific file
        # {0:1} {1:1} -g a.out -I stack -o dump.out

    - {2:1} heap to the specific file
        # {0:1} {1:1} -g a.out -I heap -o dump.out

    - {2:1} heap's bitmap to the specific file
        # {0:1} {1:1} -g a.out -I heap -o dump.out -q SAVEBITMAP
                    """.format(
                        cmd, mode, "Dump the target"
                    )

                # strace #
                elif SysMgr.checkMode("strace"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -g <TARGET> [OPTIONS] [--help]

Description:
    Trace syscalls
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Options:
    -e  <CHARACTER>             enable options
          [ p:pipe | e:encode ]
    -d  <CHARACTER>             disable options
          [ C:clone | e:encode | E:exec | g:general | O:color ]
    -u                          run in the background
    -a                          show all stats with registers
    -g  <COMM|TID{:FILE}>       set task filter
    -t  <SYSCALL>               set syscall
    -I  <COMMAND>               set command
    -R  <TIME>                  set timer
    -c  <EVENT>                 set breakpoint
    -l                          print syscall list
    -o  <DIR|FILE>              set output path
    -m  <ROWS:COLS:SYSTEM>      set terminal size
    -E  <DIR>                   set cache dir path
    -q  <NAME{:VALUE}>          set environment variables
    -J                          print in JSON format
    -v                          verbose
                    """

                    helpStr += """{2:1}
Examples:
    - {4:1} {5:1}
        # {0:1} {1:1} -g a.out -t read
        # {0:1} {1:1} -g a.out -t "read*", "*64"

    - {3:1} except for read {5:1}
        # {0:1} {1:1} -g a.out -t ^read

    - {3:1} {5:1} and print contexts in JSON format
        # {0:1} {1:1} -g a.out -J
        # {0:1} {1:1} -g a.out -J -Q
        # {0:1} {1:1} -g a.out -J -q COMPLETECALL

    - {4:1} for child tasks created by specific threads
        # {0:1} {1:1} -g 1234 -t read -q WAITCLONE

    - {4:1} from a specific binary
        # {0:1} {1:1} "ls -al" -t write
        # {0:1} {1:1} -I "ls -al" -t write

    - {4:1} from a specific binary excluding specific environment variable
        # {0:1} {1:1} "ls -al" -t write -q REMOVEENV:MAIL

    - {4:1} with backtrace {5:1}
        # {0:1} {1:1} -g a.out -t read -H

    - {4:1} with backtrace using merged symbol {5:1}
        # {0:1} {1:1} -g a.out -t read -H -q ALLSYM

    - Trace only successful syscalls {5:1}
        # {0:1} {1:1} -g a.out -q ONLYOK

    - Trace only failed syscalls {5:1}
        # {0:1} {1:1} -g a.out -q ONLYFAIL

    - {4:1} with python backtrace {5:1}
        # {0:1} {1:1} -g a.out -t read -H -q PYSTACK

    - {4:1} from a specific binary (print standard output)
        # {0:1} {1:1} -I "ls -al" -t write -q NOMUTE

    - {4:1} from a specific binary and redirect standard I/O of child tasks to specific files
        # {0:1} {1:1} "ls" -q STDIN:"./stdin"
        # {0:1} {1:1} "ls" -q STDOUT:"./stdout"
        # {0:1} {1:1} "ls" -q STDERR:"/dev/null"

    - {3:1} {5:1} (wait for new target if no task)
        # {0:1} {1:1} -g a.out -q WAITTASK
        # {0:1} {1:1} -g a.out -q WAITTASK:1
        # {0:1} {1:1} -g a.out -q WAITTASK, NOPIDCACHE

    - {4:1} from a specific binary with no strip for buffer contents
        # {0:1} {1:1} -I "ls -al" -t write -q NOSTRIP

    - {3:1} except for no symbol backtraces {5:1}
        # {0:1} {1:1} -g a.out -H -q ONLYSYM

    - {3:1} {5:1} with printing tracing overhead
        # {0:1} {1:1} -g a.out -q PRINTDELAY

    - {3:1} {5:1} including profiling overhead time
        # {0:1} {1:1} -g a.out -q INCOVERHEAD

    - {3:1} except for arguments {5:1}
        # {0:1} {1:1} -g a.out -q NOARG

    - {3:1} {5:1} even if the master tracer is terminated
        # {0:1} {1:1} -g a.out -q CONTALONE

    - {4:1} with colorful elapsed time exceeds 0.1 second
        # {0:1} {1:1} -g a.out -c write -q ELAPSED:0.1

    - {3:1} {5:1} without truncation
        # {0:1} {1:1} -g a.out -q NOCUT

    - {3:1} {5:1} with call interval info
        # {0:1} {1:1} -g a.out -q INTERCALL

    - {3:1} {5:1} and print strings in specific maximum size
        # {0:1} {1:1} -g a.out -q STRSIZE:10

    - {4:1} {5:1} and report the result to ./guider.out
        # {0:1} {1:1} -g a.out -t read -o .

    - {3:1} with breakpoint for read {5:1}
        # {0:1} {1:1} -g a.out -c read
        # {0:1} {1:1} -g a.out -c read -a

    - {3:1} {5:1} only for 1 minute
        # {0:1} {1:1} -g a.out -R 1m

    - {3:1} and pause when catching open syscall
        # {0:1} {1:1} -I "ls -al" -c open

    - {3:1} and sleep for 1.5 second when catching open syscall
        # {0:1} {1:1} -I "ls -al" -c "open|sleep:1.5"

    - {3:1} and sleep for 1.5 second whenever catching syscall
        # {0:1} {1:1} -I "ls -al" -c "*|sleep:1.5"

    - {3:1} and print memory that 2nd argument point to
        # {0:1} {1:1} -I "ls -al" -c "write|rdmem:1"

    - {3:1} {5:1} and draw timeline segments for all syscalls
        # {0:1} {1:1} -g a.out -q TIMELINE, TIMEUNIT:ms, INTERCALL, DURATION:10
        # {0:1} {1:1} -g a.out -q TIMELINE, TIMEUNIT:us, INTERCALL, DURATION:100 -H -a
        # {0:1} {1:1} -g a.out -q TIMELINE, TIMEUNIT:us, GROUPFONTSIZE:30
                    """.format(
                        cmd,
                        mode,
                        cmdListStr,
                        "Trace all syscalls",
                        "Trace specific syscalls",
                        "for specific threads",
                    )

                # utrace #
                elif SysMgr.checkMode("utrace"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -g <TARGET> [OPTIONS] [--help]

Description:
    Trace function calls
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Options:
    -e  <CHARACTER>             enable options
          [ p:pipe | D:DWARF | e:encode ]
    -d  <CHARACTER>             disable options
          [ C:clone | e:encode | D:DWARF | E:exec | g:general ]
    -u                          run in the background
    -a                          show all stats with registers
    -g  <COMM|TID{:FILE}>       set task filter
    -I  <COMMAND>               set command
    -R  <TIME>                  set timer
    -c  <EVENT>                 set breakpoint
    -H  <SKIP>                  set instrunction sampling rate
    -o  <DIR|FILE>              set output path
    -m  <ROWS:COLS:SYSTEM>      set terminal size
    -E  <DIR>                   set cache dir path
    -v                          verbose
                    """

                    helpStr += """
Examples:
    - {2:1} {3:1} in 100us cycles
        # {0:1} {1:1} -g a.out

    - {2:1} for child tasks created by a specific thread
        # {0:1} {1:1} -g a.out -W

    - {2:1} from a specific binary
        # {0:1} {1:1} "ls -al"
        # {0:1} {1:1} -I "ls -al"

    - {2:1} {3:1} from a specific binary
        # {0:1} {1:1} "ls -al" -g a.out
        # {0:1} {1:1} -I "ls -al" -g a.out

    - {2:1} {3:1} in 10ms cycles
        # {0:1} {1:1} -g a.out -i 10000

    - {2:1} {3:1} (print standard output)
        # {0:1} {1:1} -g a.out -i 10000 -q NOMUTE

    - {2:1} from a specific binary and redirect standard I/O of child tasks to specific files
        # {0:1} {1:1} "ls" -q STDIN:"./stdin"
        # {0:1} {1:1} "ls" -q STDOUT:"./stdout"
        # {0:1} {1:1} "ls" -q STDERR:"/dev/null"

    - {2:1} {3:1} (wait for new target if no task)
        # {0:1} {1:1} -g a.out -q WAITTASK
        # {0:1} {1:1} -g a.out -q WAITTASK:1
        # {0:1} {1:1} -g a.out -q WAITTASK, NOPIDCACHE

    - {2:1} {3:1} even if the master tracer is terminated
        # {0:1} {1:1} -g a.out -q CONTALONE

    - {2:1} with 1/10 instructions {3:1}
        # {0:1} {1:1} -g a.out -H 10

    - {2:1} {3:1} and report the result to ./guider.out
        # {0:1} {1:1} -g a.out -o . -a

    - {2:1} with breakpoint for peace {3:1}
        # {0:1} {1:1} -g a.out -c peace
        # {0:1} {1:1} -g a.out -c peace -a

    - {2:1} {3:1} only for 2 seconds
        # {0:1} {1:1} -g a.out -R 2s

    - {2:1} from a specific binary and pause when catching PLT function call
        # {0:1} {1:1} "ls -al" -c PLT
        # {0:1} {1:1} -I "ls -al" -c PLT
                    """.format(
                        cmd, mode, "Trace usercalls", "for specific threads"
                    )

                # pytrace #
                elif SysMgr.checkMode("pytrace"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -g <TARGET> [OPTIONS] [--help]

Description:
    Trace python calls
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Options:
    -e  <CHARACTER>             enable options
          [ p:pipe | D:DWARF | e:encode ]
    -d  <CHARACTER>             disable options
          [ C:clone | D:DWARF | e:encode | E:exec | g:general ]
    -u                          run in the background
    -a                          show all stats with registers
    -T  <FILE>                  set target file
    -g  <COMM|TID{:FILE}>       set task filter
    -I  <COMMAND>               set command
    -R  <TIME>                  set timer
    -c  <SYMBOL>                set function filter
    -H  <LEVEL>                 set function depth level
    -o  <DIR|FILE>              set output path
    -m  <ROWS:COLS:SYSTEM>      set terminal size
    -E  <DIR>                   set cache dir path
    -q  <NAME{:VALUE}>          set environment variables
    -J                          print in JSON format
    -v                          verbose
                    """

                    examStr = """{2:1}
Examples:
    - {3:1} {4:1}
        # {0:1} {1:1} -g iotop

    - {3:1} for child tasks created by a specific thread
        # {0:1} {1:1} -g iotop -W

    - {3:1} from a specific binary
        # {0:1} {1:1} "ls -al"
        # {0:1} {1:1} "python -c \"while 1: print('OK')\""
        # {0:1} {1:1} -I "ls -al"

    - {3:1} {4:1} from a specific binary
        # {0:1} {1:1} "ls -al" -g iotop
        # {0:1} {1:1} -I "ls -al" -g iotop

    - {3:1} {4:1} in 10ms cycles
        # {0:1} {1:1} -g iotop -i 10000

    - {3:1} {4:1} (print standard output)
        # {0:1} {1:1} -g iotop -q NOMUTE

    - {3:1} from a specific binary and redirect standard I/O of child tasks to specific files
        # {0:1} {1:1} "ls" -q STDIN:"./stdin"
        # {0:1} {1:1} "ls" -q STDOUT:"./stdout"
        # {0:1} {1:1} "ls" -q STDERR:"/dev/null"

    - {3:1} {4:1} (wait for new target if no task)
        # {0:1} {1:1} -g iotop -q WAITTASK
        # {0:1} {1:1} -g iotop -q WAITTASK:1
        # {0:1} {1:1} -g iotop -q WAITTASK, NOPIDCACHE

    - {3:1} for child tasks created by a specific thread
        # {0:1} {1:1} -g iotop -q WAITCLONE

    - {3:1} with colorful elapsed time exceeds 0 second
        # {0:1} {1:1} -g iotop -c write -q PYELAPSED:0

    - {3:1} {4:1} even if the master tracer is terminated
        # {0:1} {1:1} -g iotop -q CONTALONE

    - {3:1} {4:1} with printing tracing overhead
        # {0:1} {1:1} -g iotop -q PRINTDELAY

    - {3:1} {4:1} including profiling overhead time
        # {0:1} {1:1} -g iotop -q INCOVERHEAD

    - {3:1} {4:1} without truncation
        # {0:1} {1:1} -g iotop -q NOCUT

    - {3:1} with 1/10 instructions {4:1}
        # {0:1} {1:1} -g iotop -H 10

    - {3:1} {4:1} and report the result to ./guider.out
        # {0:1} {1:1} -g iotop -o . -a

    - {3:1} with breakpoint for peace {4:1}
        # {0:1} {1:1} -g iotop -c peace
        # {0:1} {1:1} -g iotop -c peace -a

    - {3:1} {4:1} only for 2 seconds
        # {0:1} {1:1} -g iotop -R 2s

    - {3:1} {4:1} and draw timeline segments for all python calls
        # {0:1} {1:1} -g iotop -q TIMELINE, TIMEUNIT:ms, INTERCALL, DURATION:10 -a
        # {0:1} {1:1} -g iotop -q TIMELINE, TIMEUNIT:us, INTERCALL, DURATION:100 -H -a
        # {0:1} {1:1} -g iotop -q TIMELINE, TIMEUNIT:us, PYELAPSED:0 -a
        # {0:1} {1:1} -g iotop -q TIMELINE, TIMEUNIT:us, PYELAPSED:0 -H -a
                    """.format(
                        cmd,
                        mode,
                        cmdListStr,
                        "Trace python calls",
                        "for specific threads",
                    )

                    helpStr += examStr

                # btrace #
                elif SysMgr.checkMode("btrace"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -g <TARGET> [OPTIONS] [--help]

Description:
    Trace native function calls
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Options:
    -e  <CHARACTER>             enable options
          [ p:pipe | D:DWARF | e:encode ]
    -d  <CHARACTER>             disable options
          [ C:clone | D:DWARF | e:encode | E:exec | g:general ]
    -u                          run in the background
    -a                          show all stats with registers
    -T  <FILE>                  set target file
    -g  <COMM|TID{:FILE}>       set task filter
    -I  <COMMAND>               set command
    -R  <TIME>                  set timer
    -c  <SYM|ADDR{:CMD}>        set breakpoint
    -H  <LEVEL>                 set function depth level
    -o  <DIR|FILE>              set output path
    -m  <ROWS:COLS:SYSTEM>      set terminal size
    -E  <DIR>                   set cache dir path
    -q  <NAME{:VALUE}>          set environment variables
    -J                          print in JSON format
    -v                          verbose
                    """

                    helpStr += brkExamStr

                # remote #
                elif SysMgr.checkMode("remote"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -g <TARGET> -c <COMMAND> [OPTIONS] [--help]

Description:
    Execute commands remotely
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Options:
    -u                          run in the background
    -a                          show all stats with registers
    -g  <COMM|TID{:FILE}>       set task filter
    -R  <TIME>                  set timer
    -i  <REPEAT>                set repeat count
    -c  <SYM|ADDR{:CMD}>        set command
    -H  <LEVEL>                 set function depth level
    -o  <DIR|FILE>              set output path
    -m  <ROWS:COLS:SYSTEM>      set terminal size
    -E  <DIR>                   set cache dir path
    -q  <NAME{:VALUE}>          set environment variables
    -v                          verbose
                    """

                    remoteExamStr = """
    - Print the context for the target repeatedly 5 times
        # {0:1} {1:1} -g a.out -c print -i 5
        # {0:1} {1:1} -g a.out -c print -i 5 -q onlyproc

    - {2:1} sleep for 0.1 second
        # {0:1} {1:1} -g a.out -c "sleep:0.1"
        # {0:1} {1:1} -g a.out -c "sleep:0.1" -q onlyproc

    - {2:1} be terminated
        # {0:1} {1:1} -g a.out -c "kill"

    - {2:1} modify its memory
        # {0:1} {1:1} -g a.out -c "wrmem:0x1234:aaaa:4"

    - {2:1} print 10-length string from the specific memory address
        # {0:1} {1:1} -g a.out -c "rdmem:0x1234:10"

    - {2:1} return from the current function with a specific value immediately
        # {0:1} {1:1} -g a.out -c "ret:3"

    - {2:1} dump stack to a file
        # {0:1} {1:1} -g a.out -c "dump:stack:stack.out"

    - {2:1} dump specific memory range to a file
        # {0:1} {1:1} -g a.out -c "dump:0x1234-0x4567:dump.out"

    - Check specific register value for the target
        # {0:1} {1:1} -g a.out -c "check:2:EQ:4096"
        # {0:1} {1:1} -g a.out -c "check:2:BT:0x1000"
        # {0:1} {1:1} -g a.out -c "check:*1:EQ:HELLO"
        # {0:1} {1:1} -g a.out -c "check:*1:INC:HE"

    - Print 1st and 2nd arguments (registers)
        # {0:1} {1:1} -g a.out -c "getarg:0:1"

    - {2:1} be terminated
        # {0:1} {1:1} -g a.out -c "exit"

    - {2:1} call the specific function
        # {0:1} {1:1} -g a.out -c "usercall:sleep#3"
        # {0:1} {1:1} -g a.out -c "usercall:printf#PEACE\\n"
        # {0:1} {1:1} -g a.out -c "usercall:printf#12345\\n"
        # {0:1} {1:1} -g a.out -c "usercall:getenv#PATH"
        # {0:1} {1:1} -g a.out -c "usercall:malloc_stats"
        # {0:1} {1:1} -g a.out -c "usercall:malloc_trim#0" -q PRINTDIFF
        # {0:1} {1:1} -g a.out -c "usercall:malloc#1024, usercall:memset#@malloc#0#1024" -q PRINTDIFF

    - {2:1} call the specific syscall
        # {0:1} {1:1} -g a.out -c "syscall:getpid"
        # {0:1} {1:1} -g a.out -c "syscall:open#test.out#1"

    - {2:1} load the specific library
        # {0:1} {1:1} -g a.out -c "load:/usr/lib/preload.so"

    - {2:1} create a thread
        # {0:1} {1:1} -g a.out -c "thread"

    - {2:1} execute python code
        # {0:1} {1:1} -g a.out -c "pystr:print('OK')" -q LIBPYTHON:/usr/lib/x86_64-linux-gnu/libpython3.8.so.1.0
        # {0:1} {1:1} -g a.out -c "pyfile:test.py:false" -q LIBPYTHON:/usr/lib/x86_64-linux-gnu/libpython3.8.so.1.0

    - {2:1} jump to the specific function with specific arguments
        # {0:1} {1:1} -g a.out -c "jump:sleep#5"

    - {2:1} execute specific commands
        # {0:1} {1:1} -g a.out -c "exec:ls -lha;sleep 1"
        # {0:1} {1:1} -g a.out -c "exec:ls -lha &"
                    """.format(
                        cmd, mode, "Control the target to"
                    )

                    helpStr += brkExamStr + remoteExamStr

                # hook #
                elif SysMgr.checkMode("hook"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -g <TARGET> -c <COMMAND> [OPTIONS] [--help]

Description:
    Replace target functions with specific functions for specific processes

    Caution) This command will update PLTs in mapped binaries.

Options:
    -u                          run in the background
    -g  <COMM|TID>              set task filter
    -c  <OSYM#NBIN#NSYM>        set command
    -H  <LEVEL>                 set function depth level
    -o  <DIR|FILE>              set output path
    -m  <ROWS:COLS:SYSTEM>      set terminal size
    -E  <DIR>                   set cache dir path
    -q  <NAME{{:VALUE}}>          set environment variables
    -v                          verbose

Examples:
    - Replace malloc() calls with mallocHook() calls in libhook.so for specific processes
        # {0:1} {1:1} -g a.out -c malloc#./libhook.so#mallocHook

    - Replace malloc() calls with mallocHook() calls in libhook.so for specific processes (wait for new target if no task)
        # {0:1} {1:1} -g a.out -c malloc#./libhook.so#malloc -q WAITTASK
        # {0:1} {1:1} -g a.out -c malloc#./libhook.so#malloc -q WAITTASK:1
        # {0:1} {1:1} -g a.out -c malloc#./libhook.so#malloc -q WAITTASK, NOPIDCACHE
                    """.format(
                        cmd, mode
                    )

                # printbind #
                elif SysMgr.checkMode("printbind"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -g <TARGET> -c <COMMAND> [OPTIONS] [--help]

Description:
    Print bind status of functions for specific processes

Options:
    -u                          run in the background
    -g  <COMM|TID>              set task filter
    -c  <FUNC|FILE>             set function filter
    -o  <DIR|FILE>              set output path
    -m  <ROWS:COLS:SYSTEM>      set terminal size
    -E  <DIR>                   set cache dir path
    -q  <NAME{{:VALUE}}>          set environment variables
    -v                          verbose

Environment Variables:
    LD_DEBUG: all, statistics, libs, bindings, detail, files, reloc, symbols
    LD_DEBUG_OUTPUT: PATH

Examples:
    - Print bind status of all functions for a specific process
        # {0:1} {1:1} -g a.out

    - Print bind status of specific functions for a specific process
        # {0:1} {1:1} -g a.out -c write
                    """.format(
                        cmd, mode
                    )

                # sigtrace #
                elif SysMgr.checkMode("sigtrace"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -g <TARGET> [OPTIONS] [--help]

Description:
    Trace signals
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Options:
    -e  <CHARACTER>             enable options
          [ p:pipe | e:encode ]
    -d  <CHARACTER>             disable options
          [ C:clone | e:encode | E:exec | g:general ]
    -u                          run in the background
    -a                          show all info
    -g  <COMM|TID{:FILE}>       set task filter
    -I  <COMMAND>               set command
    -R  <TIME>                  set timer
    -H  <LEVEL>                 set function depth level
    -o  <DIR|FILE>              set output path
    -m  <ROWS:COLS:SYSTEM>      set terminal size
    -E  <DIR>                   set cache dir path
    -v                          verbose
                    """

                    helpStr += """
Examples:
    - {2:1} for a specific thread
        # {0:1} {1:1} -g a.out

    - {2:1} for a specific command
        # {0:1} {1:1} -I "ls"

    - {2:1} with detailed info for a specific thread
        # {0:1} {1:1} -g a.out -a

    - Trace the SIGINT signal for a specific thread
        # {0:1} {1:1} -g 1234 -c SIGINT

    - Trace the SIGINT signal for a specific thread (print standard output)
        # {0:1} {1:1} -g 1234 -c SIGINT -q NOMUTE

    - {2:1} from a specific binary and redirect standard I/O of child tasks to specific files
        # {0:1} {1:1} "ls" -q STDIN:"./stdin"
        # {0:1} {1:1} "ls" -q STDOUT:"./stdout"
        # {0:1} {1:1} "ls" -q STDERR:"/dev/null"

    - {2:1} for specific threads (wait for new target if no task)
        # {0:1} {1:1} -g a.out -q WAITTASK
        # {0:1} {1:1} -g a.out -q WAITTASK:1
        # {0:1} {1:1} -g a.out -q WAITTASK, NOPIDCACHE

    - {2:1} for a specific thread even if the master tracer is terminated
        # {0:1} {1:1} -g a.out -q CONTALONE

    - {2:1} and draw timeline segments
        # {0:1} {1:1} -g a.out -q TIMELINE, TIMEUNIT:ms, INTERCALL, DURATION:10
        # {0:1} {1:1} -g a.out -q TIMELINE, TIMEUNIT:us, INTERCALL, DURATION:100 -H
                    """.format(
                        cmd, mode, "Trace all signals"
                    )

                # mem #
                elif SysMgr.checkMode("mem"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -g <TARGET> [OPTIONS] [--help]

Description:
    Print page attributes for tasks
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Options:
    -g  <COMM|TID{:FILE}>       set task filter
    -o  <DIR|FILE>              set output path
    -I  <ADDR>                  set address area
    -a                          show all memory info
    -m  <ROWS:COLS:SYSTEM>      set terminal size
    -v                          verbose
                    """

                    helpStr += """
Examples:
    - Print memory map summary {3:1}
        # {0:1} {1:1} a.out
        # {0:1} {1:1} "a.out, systemd"

    - Print memory map details {3:1}
        # {0:1} {1:1} a.out -a
        # {0:1} {1:1} "a.out, systemd" -a

    - Print the summary for page attributes in specific area {3:1}
        # {0:1} {1:1} a.out -I 0x0-0x4000
        # {0:1} {1:1} a.out -I libc-2.23.so
        # {0:1} {1:1} a.out -I /lib/x86_64-linux-gnu/libc-2.23.so
        # {0:1} {1:1} a.out -I "/lib/x86_64-linux-gnu/*"
        # {0:1} {1:1} a.out -I heap, stack
        # {0:1} {1:1} a.out -I anon
        # {0:1} {1:1} a.out -I file
        # {0:1} {1:1} a.out -I noperm
        # {0:1} {1:1} a.out -I all
        # {0:1} {1:1} a.out -I 0x8000-0x9000, 0x12345678

    - {2:1} in specific area {3:1}
        # {0:1} {1:1} a.out -I 0x0-0x4000 -a
        # {0:1} {1:1} a.out -I "/lib/x86_64-linux-gnu/*" -a
        # {0:1} {1:1} a.out -I heap, stack -a

    - {2:1} after marking idle flag in specific area {3:1}
        # {0:1} {1:1} a.out -I 0x0-0x4000 -q MARKIDLE

    - {2:1} including idle flag in specific area {3:1}
        # {0:1} {1:1} a.out -I 0x0-0x4000 -q CHECKIDLE

    - Save the bitmap including idle page info to the specific file {3:1}
        # {0:1} {1:1} a.out -I heap -o mem.out -q CHECKIDLE, SAVEBITMAP
                    """.format(
                        cmd,
                        mode,
                        "Print all page attributes",
                        "for specific processes",
                    )

                # CPU average draw #
                elif SysMgr.checkMode("drawcpuavg"):
                    helpStr = """
Usage:
    # {0:1} {1:1} <FILE> [OPTIONS] [--help]

Description:
    Draw CPU average graphs
                        """.format(
                        cmd, mode
                    )

                    helpStr += drawSubStr + drawExamStr

                # memory average draw #
                elif SysMgr.checkMode("drawmemavg"):
                    helpStr = """
Usage:
    # {0:1} {1:1} <FILE> [OPTIONS] [--help]

Description:
    Draw memory average graphs for system
                        """.format(
                        cmd, mode
                    )

                    helpStr += drawSubStr + drawExamStr

                # VSS average draw #
                elif SysMgr.checkMode("drawvssavg"):
                    helpStr = """
Usage:
    # {0:1} {1:1} <FILE> [OPTIONS] [--help]

Description:
    Draw VSS average graphs for processes
                        """.format(
                        cmd, mode
                    )

                    helpStr += drawSubStr + drawExamStr

                # RSS average draw #
                elif SysMgr.checkMode("drawrssavg"):
                    helpStr = """
Usage:
    # {0:1} {1:1} <FILE> [OPTIONS] [--help]

Description:
    Draw RSS average graphs for processes
                        """.format(
                        cmd, mode
                    )

                    helpStr += drawSubStr + drawExamStr

                # CPU draw #
                elif SysMgr.checkMode("drawcpu"):
                    helpStr = """
Usage:
    # {0:1} {1:1} <FILE> [OPTIONS] [--help]

Description:
    Draw CPU graphs
                        """.format(
                        cmd, mode
                    )

                    helpStr += drawSubStr + drawExamStr

                # CPU Delay draw #
                elif SysMgr.checkMode("drawdelay"):
                    helpStr = """
Usage:
    # {0:1} {1:1} <FILE> [OPTIONS] [--help]

Description:
    Draw CPU delay graphs
                        """.format(
                        cmd, mode
                    )

                    helpStr += drawSubStr + drawExamStr

                # bitmap draw #
                elif SysMgr.checkMode("drawbitmap"):
                    helpStr = """
Usage:
    # {0:1} {1:1} <FILE> [OPTIONS] [--help]

Description:
    Draw bitmap
                        """.format(
                        cmd, mode
                    )

                    helpStr += drawSubStr + drawExamStr

                # flamegraph draw #
                elif SysMgr.checkMode("drawflame"):
                    helpStr = """
Usage:
    # {0:1} {1:1} <FILE> [OPTIONS] [--help]

Description:
    Draw flame graph
                        """.format(
                        cmd, mode
                    )

                    helpStr += drawSubStr + drawExamStr

                # timeline draw #
                elif SysMgr.checkMode("drawtime"):
                    helpStr = """
Usage:
    # {0:1} {1:1} <FILE> [OPTIONS] [--help]

Description:
    Draw timeline segment from JSON format data
                        """.format(
                        cmd, mode
                    )

                    drawTimelineStr = """
Format:
    < DATA >
    {
      "title": "example",   // optional for title
      "font_size": 3,       // optional for font size
      "time_unit": "ms",    // [sec | ms | ns]
      "names": {            // optional for name
        '0': "task1",
        '1': "task2",
        '2': "task3"
        }
      "segments": [
        {
          "group": 0,
          "text": "task0",
          "time_start": 10,
          "time_end": 40,
          "id": 12,         // optional for class
          "color": "red",   // optional for color
          "state": "S"      // optional for event
        },
        {
          "group": 1,
          "text": "task2",
          "time_start": 0,
          "time_end": 20,
          "id": 13,
          "color": "black",
          "state": "S"
        },
        {
          "group": 1,
          "text": "task3",
          "time_start": 30,
          "time_end": 35,
          "id": 14,
          "color": "rgb(128,0,128)",
          "state": "S"
        }
      ]
    }

    < CONFIG >
    {
        "width": 400,
        "height": 100,
        "font_size": 4,
        "time_ticks": 20,
        "time_axis_height": 10,
        "label_size_min": 30,
        "palette": [
            "(244, 67, 54)",
            "(233,30,99)",
            "(156, 39, 176)"
        ]
    }
                        """

                    helpStr += drawSubStr + drawTimelineStr + drawExamStr

                # memory draw #
                elif SysMgr.checkMode("drawmem"):
                    helpStr = """
Usage:
    # {0:1} {1:1} <FILE> [OPTIONS] [--help]

Description:
    Draw system memory graphs and memory chart
                        """.format(
                        cmd, mode
                    )

                    helpStr += drawSubStr + drawExamStr

                # vss draw #
                elif SysMgr.checkMode("drawvss"):
                    helpStr = """
Usage:
    # {0:1} {1:1} <FILE> [OPTIONS] [--help]

Description:
    Draw process memory(VSS) graphs and memory chart
                        """.format(
                        cmd, mode
                    )

                    helpStr += drawSubStr + drawExamStr

                # rss draw #
                elif SysMgr.checkMode("drawrss"):
                    helpStr = """
Usage:
    # {0:1} {1:1} <FILE> [OPTIONS] [--help]

Description:
    Draw process memory(RSS) graphs and memory chart
                        """.format(
                        cmd, mode
                    )

                    helpStr += drawSubStr + drawExamStr

                # leak draw #
                elif SysMgr.checkMode("drawleak"):
                    helpStr = """
Usage:
    # {0:1} {1:1} <FILE> [OPTIONS] [--help]

Description:
    Draw memory(VSS) graphs of processes suspected memory leak and memory chart
                        """.format(
                        cmd, mode
                    )

                    helpStr += drawSubStr + drawExamStr

                # I/O draw #
                elif SysMgr.checkMode("drawio"):
                    helpStr = """
Usage:
    # {0:1} {1:1} <FILE> [OPTIONS] [--help]

Description:
    Draw system I/O graphs
                        """.format(
                        cmd, mode
                    )

                    helpStr += drawSubStr + drawExamStr

                # draw #
                elif SysMgr.isDrawMode():
                    helpStr = """
Usage:
    # {0:1} {1:1} <FILE> [OPTIONS] [--help]

Description:
    Draw system resource graph, event timeline, memory chart
                        """.format(
                        cmd, mode
                    )

                    helpStr += drawSubStr + drawExamStr

                # topdiff #
                elif SysMgr.checkMode("topdiff"):
                    helpStr = """
Usage:
    # {0:1} {1:1} <FILE> [OPTIONS] [--help]

Description:
    Diff top report files
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Options:
    -d  <CHARACTER>             disable options
          [ A:Average | e:encode ]
                    """

                    helpStr += """
Examples:
    - {2:1}
        # {0:1} {1:1} "tc1.out, tc2.out"

    - {2:1} in current directory
        # {0:1} {1:1} "tc*.out"

    - {2:1} from current directory to all sub-directories
        # {0:1} {1:1} "**/tc*.out"

    - {2:1} by total usage
        # {0:1} {1:1} "tc*.out" -dA

    - {2:1} within specific interval range in index unit
        # {0:1} {1:1} "tc*.out" -q TRIMIDX:1:5
                    """.format(
                        cmd, mode, "Diff top report files"
                    )

                # topsum #
                elif SysMgr.checkMode("topsum"):
                    helpStr = """
Usage:
    # {0:1} {1:1} <FILE> [OPTIONS] [--help]

Description:
    Summarize a raw data file for task top mode
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - {2:1}
        # {0:1} {1:1} output.out
        # {0:1} {1:1} "report1.out, report2.out.gz"
        # {0:1} {1:1} "output*.out"

    - {2:1} for each file
        # {0:1} {1:1} "report1.out, report2.out.gz" -q NOMERGE
        # {0:1} {1:1} "output*.out" -q NOMERGE

    - {2:1} after applying task filter
        # {0:1} {1:1} output.out -g "a.out*"
        # {0:1} {1:1} "output*.out" -g "*a.out*"

    - {2:1} in reversed file order
        # {0:1} {1:1} "report*.out" -q REVERSEFILE

    - {2:1} in reversed sample order
        # {0:1} {1:1} "report*.out" -q REVERSESAMPLE

    - {2:1} without process info
        # {0:1} {1:1} "report*.out" -q ONLYTOTAL

    - {2:1} without detailed info
        # {0:1} {1:1} "report*.out" -q ONLYSUMMARY

    - {2:1} after converting unique physical memory (RSS - Text - Shm)
        # {0:1} {1:1} "report*.out" -q EXCEPTSHM

    - {2:1} into guider.out
        # {0:1} {1:1} output.out.gz -o guider.out
                    """.format(
                        cmd, mode, "Summarize raw data files in the top report"
                    )

                # kill / send #
                elif SysMgr.isKillMode():
                    helpStr = """
Usage:
    # {0:1} {1:1} -<SIGNUM|SIGNAME> <PID|COMM> [OPTIONS] [--help]

Description:
    Send specific signal to specific tasks or all running Guiders

Options:
    -i  <SEC>                   set interval
    -l                          print signal list
    -W  <SEC>                   wait for input
    -v                          verbose
                    """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - Send the notification signal to all running Guiders
        # {0:1} {1:1}

    - Send SIGSTOP signal to specific tasks
        # {0:1} {1:1} -sigstop 1234
        # {0:1} {1:1} -sigstop a.out
        # {0:1} {1:1} -sigstop "a.out*"

    - Send SIGSTOP to specific tasks after 5 seconds
        # {0:1} {1:1} -sigstop 1234 -W 5s

    - Send SIGSTOP signal to specific tasks until one gets the signal
        # {0:1} {1:1} -sigstop a.out -q WAITTASK
        # {0:1} {1:1} -sigstop a.out -q WAITTASK:1
        # {0:1} {1:1} -sigstop a.out -q WAITTASK, NOPIDCACHE

    - Send 9th signal SIGKILL to specific tasks
        # {0:1} {1:1} -9 1234
        # {0:1} {1:1} -sigkill 1234

    - Send 9th signal SIGKILL to specific tasks every 2 seconds
        # {0:1} {1:1} -9 1234 -i 2
        # {0:1} {1:1} -sigkill 1234 -i 2
                    """.format(
                        cmd, mode
                    )

                # pause #
                elif SysMgr.checkMode("pause"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -g <TARGET> [OPTIONS] [--help]

Description:
    Pause specific running threads

Options:
    -g  <TID|COMM>              set task filter
    -R  <TIME>                  set timer
    -u                          run in the background
    -P                          group threads in a same process
    -v                          verbose
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - Pause specific running threads for 3 seconds
        # {0:1} {1:1} -g a.out -R 3
        # {0:1} {1:1} -g 1234 -R 3
        # {0:1} {1:1} -g "a*" -R 3

    - Pause specific running threads including a same process group
        # {0:1} {1:1} -g a.out -P
                    """.format(
                        cmd, mode
                    )

                # freeze #
                elif SysMgr.checkMode("freeze"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -g <TARGET> [OPTIONS] [--help]

Description:
    Freeze specific running tasks

Options:
    -g  <TID|COMM>              set task filter
    -R  <TIME>                  set timer
    -u                          run in the background
    -P                          group threads in a same process
    -v                          verbose
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - Freeze specific running processes for 3 seconds
        # {0:1} {1:1} -g a.out -R 3
        # {0:1} {1:1} -g 1234 -R 3
        # {0:1} {1:1} -g "a*" -R 3

    - Freeze specific running threads including a same process group
        # {0:1} {1:1} -g a.out -et -P
                    """.format(
                        cmd, mode
                    )

                # readelf #
                elif SysMgr.checkMode("readelf"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -I <FILE> [OPTIONS] [--help]

Description:
    Show information about ELF file

Options:
        -e  <CHARACTER>             enable options
              [ p:pipe | D:DWARF | e:encode ]
        -I  <FILE>                  set input path
        -g  <ADDR|SYMBOL>           set function filter
        -q  <NAME{{:VALUE}}>          set environment variables
        -v                          verbose
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - {2:1}
        # {0:1} {1:1} -I /usr/bin/yes

    - {2:1} with LLVM demangler
        # {0:1} {1:1} -I /usr/bin/yes -q LIBLLVM:libLLVM-10.so

    - Print vDSO information
        # {0:1} {1:1} -I vdso

    - {2:1} with debug information
        # {0:1} {1:1} -q DEBUGINFO

    - {2:1} without using debug files
        # {0:1} {1:1} -q NODEBUG
                    """.format(
                        cmd, mode, "Print ELF information of a specific file"
                    )

                # log #
                elif (
                    SysMgr.checkMode("logdlt")
                    or SysMgr.checkMode("logkmsg")
                    or SysMgr.checkMode("logsys")
                    or SysMgr.checkMode("logjrl")
                ):
                    helpStr = logCommonStr

                # printlog #
                elif (
                    SysMgr.checkMode("printdlt")
                    or SysMgr.checkMode("printdbus")
                    or SysMgr.checkMode("printkmsg")
                    or SysMgr.checkMode("printjrl")
                    or SysMgr.checkMode("printsys")
                ):
                    helpStr = printCommonStr

                    # printdbus #
                    if SysMgr.checkMode("printdbus"):
                        helpStr += """
    - {2:1} with detailed information in real-time
        # {0:1} {1:1} -a

    - {2:1} including specific word in real-time
        # {0:1} {1:1} -c test

    - {2:1} with backtrace for a.out process in real-time
        # {0:1} {1:1} -g a.out -H

    - {2:1} for a specific session bus
        # DBUS_SESSION_BUS_ADDRESS=$(cat addr) {0:1} {1:1}

    - {2:1} except for specific messages
        # {0:1} {1:1} -G sendData

    - {2:1} with detailed information in real-time until a log containing a specific word is detected
        # {0:1} {1:1} -q WATCHLOG:"*oops*"

    - {2:1} with detailed information in real-time until a log containing a specific word is detected and execute specific commands when terminated
        # {0:1} {1:1} -q WATCHLOG:"*oops*", WATCHLOGCMD:"ls -lha"
                    """.format(
                            cmd, mode, "Print D-Bus messages"
                        )

                    # printkmsg / printsys #
                    if SysMgr.checkMode("printkmsg") or SysMgr.checkMode(
                        "printsys"
                    ):
                        helpStr += """
    - Print logs including specific words
        # {0:1} {1:1} -g test
                    """.format(
                            cmd, mode
                        )

                    # printjrl #
                    if SysMgr.checkMode("printjrl"):
                        helpStr += """
    - {2:1} for all
        # {0:1} {1:1} -a

    - {2:1} including specific words in real-time
        # {0:1} {1:1} -g test

    - {2:1} with all fields in real-time
        # {0:1} {1:1} -I

    - {2:1} with specific fields in real-time
        # {0:1} {1:1} -I _TIME, _COMM, _PID
                    """.format(
                            cmd, mode, "Print the systemd journal"
                        )

                    # printdlt #
                    if SysMgr.checkMode("printdlt"):
                        helpStr += """
    - {2:1} from specific files
        # {0:1} {1:1} "./*.dlt"
        # {0:1} {1:1} -I "./*.dlt"

    - {2:1} from specific files from current directory to all sub-directories
        # {0:1} {1:1} "**/*.dlt"

    - {2:1} summary from specific files
        # {0:1} {1:1} "./*.dlt" -q PRINTSUMMARY

    - {2:1} with the file name
        # {0:1} {1:1} "./*.dlt" -q PRINTFILENAME

    - {2:1} including specific words
        # {0:1} {1:1} -g test

    - Change default log level to be printed
        # {0:1} {1:1} -c INFO

    - {2:1} using libdlt.so from specific path
        # {0:1} {1:1} -q LIBDLT:/home/iipeace/test/libdlt.so

    - {2:1} sorted by line from specific files
        # {0:1} {1:1} "./*.dlt" -S
        # {0:1} {1:1} -I "./*.dlt" -S

    - {2:1} from specific address for dlt-daemon
        # {0:1} {1:1} -X 127.0.0.1:12345

    - {2:1} with connection retry to dlt-daemon every 1,000 ms
        # {0:1} {1:1} -q RETRYCONN:1000
                    """.format(
                            cmd, mode, "Print DLT messages"
                        )

                # printsig #
                elif SysMgr.checkMode("printsig"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Show signal status

Options:
    -o  <DIR|FILE>              set output path
    -g  <TID|COMM>              set task filter
    -J                          print in JSON format
    -v                          verbose
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - Print signal status info for specific processes
        # {0:1} {1:1} a.out, java
        # {0:1} {1:1} -g a.out, java
                    """.format(
                        cmd, mode
                    )

                # printdbussub #
                elif SysMgr.checkMode("printdbussub"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Show D-Bus signal subscription info

Options:
    -o  <DIR|FILE>              set output path
    -a                          show all stats
    -v                          verbose
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - Print D-Bus signal subscription info
        # {0:1} {1:1}

    - Print D-Bus signal subscription info with specific values
        # {0:1} {1:1} -a

    - Print D-Bus signal subscription info to a specific file
        # {0:1} {1:1} -o sig.out
                    """.format(
                        cmd, mode
                    )

                # watch #
                elif SysMgr.checkMode("watch"):
                    helpStr = """
Usage:
    # {0:1} {1:1} <PATH> [OPTIONS] [--help]

Description:
    Watch specific files or directories

Options:
    -g  <PATH:EVENT:FILE:CMD>   set condition
    -v                          verbose
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - Watch the current directory
        # {0:1} {1:1}

    - Watch specific files to be created and terminate after all them created
        # {0:1} {1:1} "/home/iipeace/testFile1, /home/iipeace/testFile2"

    - Watch multiple directories
        # {0:1} {1:1} "/home/iipeace/test, /home/iipeace/test/sub"

    - Watch specific events for a.out in the current directory
        # {0:1} {1:1} ".:IN_CREATE|IN_CLOSE:a.out"

    - Watch specific events in the current directory and terminate if the events occur
        # {0:1} {1:1} ".:IN_CREATE|IN_CLOSE:a.out:exit"

    - Watch specific events in the current directory and execute specific commands if the events occur
        # {0:1} {1:1} ".:IN_CREATE|IN_CLOSE:a.out:ls -lha"
                    """.format(
                        cmd, mode
                    )

                # addr2sym #
                elif SysMgr.checkMode("addr2sym"):
                    helpStr = """
Usage:
    # {0:1} {1:1} <FILE|PID|COMM> -g <OFFSET> [OPTIONS] [--help]

Description:
    Show symbols of specific addresses in a file or a process memory map

Options:
    -I  <FILE|COMM|PID>         set input path or process
    -g  <OFFSET>                set offset
    -q  <NAME{{:VALUE}}>          set environment variables
    -v                          verbose
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - Print symbol information of specific addresses from specific files
        # {0:1} {1:1} -I /usr/bin/yes -g ab1cf
        # {0:1} {1:1} -I "/usr/lib/*" -g ab1cf

    - Print merged symbol information of specific addresses from a file
        # {0:1} {1:1} -I /usr/bin/yes -g ab1cf -q ALLSYM

    - Print symbol information of specific addresses from memory map of specific processes
        # {0:1} {1:1} -I "yes" -g ab1cf
        # {0:1} {1:1} -I "yes|systemd" -g ab1cf
                    """.format(
                        cmd, mode
                    )

                # mkcache #
                elif SysMgr.checkMode("mkcache"):
                    helpStr = """
Usage:
    # {0:1} {1:1} <FILE|COMM|PID> -g <OFFSET> [OPTIONS] [--help]

Description:
    Make ELF caches in parallel

Options:
    -I  <FILE|COMM|PID>         set input path or process
    -v                          verbose
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - Make ELF caches for a.out and yes processes in parallel
        # {0:1} {1:1} a.out, yes

    - Make a ELF cache for /usr/bin/yes
        # {0:1} {1:1} /usr/bin/yes

    - Make ELF caches for a.out process in parallel ignoring existing cache files
        # {0:1} {1:1} a.out, yes -q NOFILECACHE
                    """.format(
                        cmd, mode
                    )

                # readahead #
                elif SysMgr.checkMode("readahead"):
                    helpStr = """
Usage:
    # {0:1} {1:1} <FILE|COMM|PID> -g <OFFSET> [OPTIONS] [--help]

Description:
    Initiate file readahead into page cache

Options:
    -I  <FILE>                  set input path
    -W  <SEC>                   wait for input
    -Y  <POLICY:PRIO|TIME       set sched
         {{:TID|COMM:CONT}}>
        <CLASS:{{WHICH:}}PRIO
         :TID|COMM>
    -v                          verbose

Spec:
    - The format for readahead list
        1. The size for file name list: 4 Bytes
        2. The string for File name list: SIZE bytes
            - File names are split by '#'
        3. Data for readahead chunk: IDX|OFFSET|SIZE
            - IDX for file index in file name list: 2 Bytes
            - OFFSET for file offset: 8 Bytes
            - SIZE for readahead size: 4 Bytes

    - The format for filter list
        1. the entire file
            - /data/test
            - /data/test*
            - /data/*test*
        2. the specific area for the file
            - /data/test:4096:100M
            - /data/test:4096:4096

    - Caution
        - The valid size for a readahead syscall is maximum about 1MB
        - Readahead chunks larger than 1MB are split into multiple chunks in Guider automatically
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - Initiate file readahead into page cache
        # {0:1} {1:1} readahead.list

    - Initiate file readahead into page cache after setting the scheduling priority
        # {0:1} {1:1} -Y "c:10, idle:1:0"

    - Initiate file readahead into page cache using specific lists
        # {0:1} {1:1} readahead.list -q RAMIN:4096
        # {0:1} {1:1} readahead.list -q RAMAX:1048576
        # {0:1} {1:1} readahead.list -q RAALLOWLIST:allow.list
        # {0:1} {1:1} readahead.list -q RADENYLIST:deny.list
        # {0:1} {1:1} readahead.list -q RAADDLIST:add.list
                    """.format(
                        cmd, mode
                    )

                # sym2addr#
                elif SysMgr.checkMode("sym2addr"):
                    helpStr = """
Usage:
    # {0:1} {1:1} <FILE|COMM|PID> -g <SYMBOL> [OPTIONS] [--help]

Description:
    Show files and offset of specific symbols in a file or a process memory map

Options:
    -I  <FILE|COMM|PID>         set input path or process
    -g  <SYMBOL>                set offset
    -q  <NAME{{:VALUE}}>          set environment variables
    -v                          verbose
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - {2:1} specific symbols from a file
        # {0:1} {1:1} -I /usr/bin/yes -g testFunc

    - {2:1} specific merged symbols from a file
        # {0:1} {1:1} -I /usr/bin/yes -g testFunc -q ALLSYM

    - {2:1} specific symbols from specific files
        # {0:1} {1:1} -I "/usr/bin/*" -g testFunc

    - {2:1} all symbols from a file
        # {0:1} {1:1} -I /usr/bin/yes -g "*"

    - {2:1} specific symbols including specific word from a file
        # {0:1} {1:1} -I /usr/bin/yes -g "*testFunc"
        # {0:1} {1:1} -I /usr/bin/yes -g "testFunc*"
        # {0:1} {1:1} -I /usr/bin/yes -g "*testFunc*"

    - {2:1} specific symbols including specific word from a file
        # {0:1} {1:1} -I ~/test/mutex -g "std::_Vector_base<unsigned long\, std::allocator<unsigned long> >::~_Vector_base()"

    - {2:1} specific symbols from memory map of specific processes
        # {0:1} {1:1} -I "yes" -g testFunc
        # {0:1} {1:1} -I "yes|systemd" -g testFunc
                    """.format(
                        cmd, mode, "Print information of"
                    )

                # printdbusstat #
                elif SysMgr.checkMode("printdbusstat"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Print D-Bus stats

Options:
    -v                          verbose
    -g  <COMM>                  set task filter
    -o  <DIR|FILE>              set output path
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - Print D-Bus stats
        # {0:1} {1:1}

    - Print D-Bus stats into the specific file
        # {0:1} {1:1} -o stats.out
                    """.format(
                        cmd, mode
                    )

                # printdbusintro #
                elif SysMgr.checkMode("printdbusintro"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Print D-Bus introspection in XML

Options:
    -v                          verbose
    -g  <COMM>                  set task filter
    -o  <DIR|FILE>              set output path
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - Print D-Bus introspection
        # {0:1} {1:1}

    - Print D-Bus introspection into the specific file
        # {0:1} {1:1} -o intro.out
                    """.format(
                        cmd, mode
                    )

                # printcgroup #
                elif SysMgr.checkMode("printcg"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Show system cgroup tree

Options:
    -v                          verbose
    -a                          show all processes
    -g  <COMM>                  set task filter
    -H  <LEVEL>                 set depth level
    -o  <DIR|FILE>              set output path
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - {2:1}
        # {0:1} {1:1}

    - {2:1} for specific subsystem
        # {0:1} {1:1} "cpu*"
        # {0:1} {1:1} blkio

    - {2:1} with processes
        # {0:1} {1:1} -a

    - {2:1} with processes having specific name
        # {0:1} {1:1} -a -g kworker

    - {2:1} with depth 3
        # {0:1} {1:1} -H 3
                    """.format(
                        cmd, mode, "Print system cgroup tree"
                    )

                # exec #
                elif SysMgr.checkMode("exec"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Execute commands repeatedly with various conditions

Options:
    -v                          verbose
    -I  <COMMAND>               set commands
    -c  <VARIABLE>              set variables
    -C  <PATH>                  set config path
    -q  <NAME{{:VALUE}}>          set environment variables
    -u                          run in the background
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - {2:1}
        # {0:1} {1:1} -I "ls -lha"

    - {2:1} in background
        # {0:1} {1:1} -I "ls -lha" -u

    - Execute commands with range variables
        # {0:1} {1:1} -I "touch FILE" -c FILE:1:100:0.1

    - Execute commands with file variables
        # {0:1} {1:1} -I "ls -lha FILE" -c FILE:"/data/*"

    - Execute commands including specific environment variables
        # {0:1} {1:1} -I "ls -lha FILE" -q ENV:TEST=1, ENV:PATH=/data
        # {0:1} {1:1} -I "ls -lha FILE" -q ENVFILE:/data/env.sh

    - {2:1} and redirect standard I/O of child tasks to specific files
        # {0:1} {1:1} -I "ls" -q STDIN:"./stdin"
        # {0:1} {1:1} -I "ls" -q STDOUT:"./stdout"
        # {0:1} {1:1} -I "ls" -q STDERR:"/dev/null"

    - {2:1} after converting it using the config file
        # {0:1} {1:1} -I "CMD_TOP" -C guider.conf

    - {2:1} with the cpu limitation in % unit using cgroup
        # {0:1} {1:1} -q LIMITCPU:20
        # {0:1} {1:1} -q LIMITCPU:20@"*yes*|a.out"

    - {2:1} with the memory limitation using cgroup
        # {0:1} {1:1} -I "a.out" -q LIMITMEM:50M
        # {0:1} {1:1} -I "a.out" -q LIMITMEM:50M, LIMITMEM:swappiness:10
        # {0:1} {1:1} -I "a.out" -q LIMITMEM:50M@"*yes*|a.out"

    - {2:1} with the block I/O limitation using cgroup
        # {0:1} {1:1} -I "a.out" -q LIMITREAD:50M
        # {0:1} {1:1} -I "a.out" -q LIMITWRITE:50M
        # {0:1} {1:1} -I "a.out" -q LIMITREAD:50M@"*yes*|a.out"
        # {0:1} {1:1} -I "a.out" -q LIMITWRITE:50M@"*yes*|a.out"
        # {0:1} {1:1} -I "a.out" -q LIMITWRITE:50M@"*yes*|a.out", EACHTASK
                    """.format(
                        cmd, mode, "Execute a command"
                    )

                # printext #
                elif SysMgr.checkMode("printext"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Show inode attributes for ext4 filesystem

Options:
    -v                          verbose
    -I  <DIR>                   set input path
    -a                          show all attributes
    -g  <WORD>                  set filter
    -q  <NAME{{:VALUE}}>          set environment variables
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - Print all inode attributes for ext4 filesystem from the specific file
        # {0:1} {1:1} /dev/sda1

    - Print specific inode attributes for ext4 filesystem from the specific file
        # {0:1} {1:1} /dev/sda1 -g data
                    """.format(
                        cmd, mode
                    )

                # printdir #
                elif SysMgr.checkMode("printdir"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Show directory structure

Options:
    -v                          verbose
    -I  <DIR>                   set input path
    -a                          show all attributes
    -g  <WORD>                  set filter
    -c  <COMMAND>               set command
    -q  <NAME{{:VALUE}}>          set environment variables
    -J                          print in JSON format
    -H  <LEVEL>                 set function depth level
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - {2:1} from current working directory
        # {0:1} {1:1}

    - {2:1} from / directory
        # {0:1} {1:1} /
        # {0:1} {1:1} -I /

    - {2:1} from current working directory after sorting
        # {0:1} {1:1} -q SORT:SIZE
        # {0:1} {1:1} -q SORT:TYPE

    - {2:1} including linked directories from current working directory
        # {0:1} {1:1} -q INCLINK

    - {2:1} for specific directories
        # {0:1} {1:1} "/data, /tmp"

    - {2:1} in 2-depth from / directory
        # {0:1} {1:1} -I / -H 2

    - {2:1} with files from / directory
        # {0:1} {1:1} -I / -a

    - Print specific directories and files from / directory
        # {0:1} {1:1} -I / -a -g
        # {0:1} {1:1} -I / -a -g test
        # {0:1} {1:1} -I / -a -g "test*"
        # {0:1} {1:1} -I / -a -g "*test"

    - {2:1} with files bigger than 1MB from / dir
        # {0:1} {1:1} -I / -a -q SIZECOND:BT:1M

    - {2:1} with files lesser than 1MB from / dir
        # {0:1} {1:1} -I / -a -q SIZECOND:LT:1M

    - Print specific directories and files from / dir and apply command
        # {0:1} {1:1} -I / -a -g test -c "rm -rf TARGET"
                    """.format(
                        cmd, mode, "Print directory structure"
                    )

                # leaktracer #
                elif SysMgr.checkMode("leaktrace"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -g <TARGET> [OPTIONS] [--help]

Description:
    Show functions caused memory leakage

    1) Get libleaktracer.so for your CPU architecture from
       https://github.com/iipeace/portable/tree/master/leaktracer.
    2) Run the target process with below specific environment variables
       if you can't inject the hook binary to the running target process.
       - Auto start from loader
           $ LD_PRELOAD=./libleaktracer.so \\
             LEAKTRACER_AUTO_REPORTFILENAME=/tmp/leaks.out \\
             LEAKTRACER_ONSIG_REPORTFILENAME=/tmp/leaks.out \\
             LEAKTRACER_ONSIG_REPORT=36 EXEC_PATH
       - Manual start by signal(SIGRT1)
           $ LD_PRELOAD=./libleaktracer.so \\
             LEAKTRACER_ONSIG_REPORTFILENAME=/tmp/leaks.out \\
             LEAKTRACER_ONSIG_STARTALLTHREAD=35 \\
             LEAKTRACER_ONSIG_REPORT=36 EXEC_PATH
    3) Check below specification.
       - If the target process is on secure-execution mode,
         libleaktracer.so should be in standard search directories
         specified in  /etc/ld.so.conf,
         And all slashes in the preload path will be ignored.
         Otherwise add the library path to /etc/ld.so.preload.
       - Once leaktrace starts, the memory usage of the target process
         will increase rapidly due to logging data.
       - Specific allocators and deallocators called from inside
         standard libraries such as libstdc++ can't be traced
         if you injected libleaktracer.so to the target process dynamically.
         Because using dynamic injection just update PLTs in mapped binaries.

Options:
    -I  <DIR|FILE>              set input path
    -o  <DIR|FILE>              set output path
    -c  <{{STARTSIZE:}}ENDSIZE>   set condition for RSS
    -T  <FILE>                  set hook file
    -g  <PID|COMM>              set target process
    -k  <{{START,}}STOP>          set signal
    -R  <TIME>                  set timer
    -C  <PATH>                  set config path
    -q  <NAME{{:VALUE}}>          set environment variables
    -v                          verbose
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - {3:1} {2:1} after executing the target program with auto start
        # {0:1} {1:1} ./a.out -T ./libleaktracer.so
        # {0:1} {1:1} ./a.out -o ./guider.out -T ./libleaktracer.so
        # {0:1} {1:1} ./a.out -T ./libleaktracer.so -q MUTE

    - {3:1} {2:1} after executing the target program with manual start
        # {0:1} {1:1} ./a.out -o ./guider.out -T ./libleaktracer.so -q WAITSIGNAL

    - {3:1} {2:1} after setting environment variables
        # {0:1} {1:1} -g a.out
        # {0:1} {1:1} -g a.out -o ./guider.out

    - {3:1} {2:1} after setting environment variables for 5 seconds
        # {0:1} {1:1} -g a.out -R 5

    - {3:1} {2:1} {4:1}
        # {0:1} {1:1} -g a.out -T /home/root/libleaktracer.so

    - {3:1} including memory tracking {2:1} {4:1}
        # {0:1} {1:1} -g a.out -T /home/root/libleaktracer.so -q MEMPROF
        # {0:1} {1:1} -g a.out -T /home/root/libleaktracer.so -q MEMPROF:3

    - {3:1} {2:1} {4:1} and a temporary writable path
        # {0:1} {1:1} -g a.out -I /var/log/guider -T /home/root/libleaktracer.so

    - {3:1} after sending SIGRT2(36) to stop profiling
        # {0:1} {1:1} -g a.out -k 36
        # {0:1} {1:1} -g a.out -k SIGRT2

    - {3:1} {2:1} after starting profiling {5:1}
        # {0:1} {1:1} -g a.out -c 20m,0

    - Report idle memory hints of the target process {2:1} after executing the target program with auto start and receiving SIGQUIT for marking all anonymous pages as idle
        # {0:1} {1:1} ./a.out -T ./libleaktracer.so -q REPORTIDLE

    - Report active memory hints of the target process {2:1} after executing the target program with auto start and receiving SIGQUIT for marking all anonymous pages as idle
        # {0:1} {1:1} ./a.out -T ./libleaktracer.so -q REPORTACTIVE

    - {3:1} {5:1}
        # {0:1} {1:1} -g a.out -c 20m
        # {0:1} {1:1} -g a.out -c +20m
        # {0:1} {1:1} -g a.out -c 15m,20m
        # {0:1} {1:1} -g a.out -c +15m,+20m

    - {3:1} {2:1} {4:1} (wait for new process if no process)
        # {0:1} {1:1} -g a.out -T /home/root/libleaktracer.so -q WAITTASK
        # {0:1} {1:1} -g a.out -T /home/root/libleaktracer.so -q WAITTASK:1
        # {0:1} {1:1} -g a.out -T /home/root/libleaktracer.so -q WAITTASK, NOPIDCACHE

    - {3:1} using allocation size filter {2:1} after executing the target program with auto start
        # {0:1} {1:1} ./a.out -T ./libleaktracer.so -q SIZEFILTER:">100k"
        # {0:1} {1:1} ./a.out -T ./libleaktracer.so -q SIZEFILTER:">100m"
        # {0:1} {1:1} ./a.out -T ./libleaktracer.so -q SIZEFILTER:"=4096"

    - Print functions caused memory leakage of a specific process
        # {0:1} {1:1} -g a.out
        # {0:1} {1:1} -I ./leaks.out -g a.out
                    """.format(
                        cmd,
                        mode,
                        "when SIGINT is received",
                        "Report memory leakage hints of the target process",
                        "after hooking binary injection",
                        "when it's RSS reached the specific size",
                    )

                # printslab #
                elif SysMgr.checkMode("printslab"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Show system slab info

Options:
    -g  <WORD>                  set target object
    -S  <WORD>                  set sort value
    -v                          verbose

Sort:
    size:    the size of an object
    active:  the number of active objects
    actsize: the size of active objects
    total:   the size of all objects
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - Print system slab info
        # {0:1} {1:1} dentry

    - Print system slab info using type filter
        # {0:1} {1:1} -g dentry

    - Print system slab info sorted by specific values
        # {0:1} {1:1} -S size
        # {0:1} {1:1} -S active
        # {0:1} {1:1} -S actsize
        # {0:1} {1:1} -S total
                    """.format(
                        cmd, mode
                    )

                # printvma#
                elif SysMgr.checkMode("printvma"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Show system vmalloc info

Options:
    -g  <WORD>                  set target object
    -v                          verbose
                    """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - Print system vmalloc info
        # {0:1} {1:1}

    - Print system vmalloc info using filter
        # {0:1} {1:1} -g fork
                    """.format(
                        cmd, mode
                    )

                # printenv #
                elif SysMgr.checkMode("printenv"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -g <TARGET> [OPTIONS] [--help]

Description:
    Show environment variables for a specific process

Options:
    -g  <PID|COMM>              set target process
    -J                          print in JSON format
    -I  <WORD>                  set filter
    -v                          verbose
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - Print environment variables for a specific process
        # {0:1} {1:1} a.out
        # {0:1} {1:1} -g 1234

    - Print environment variables for all processes
        # {0:1} {1:1} "*"

    - Print environment variables including PWD for all processes
        # {0:1} {1:1} "*" -I PWD
                    """.format(
                        cmd, mode
                    )

                # printns #
                elif SysMgr.checkMode("printns"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Show namespace list

Options:
    -a                          show all attributes
    -v                          verbose
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - Print namespace list
        # {0:1} {1:1}

    - Print namespace list with tasks
        # {0:1} {1:1} -a
                    """.format(
                        cmd, mode
                    )

                # printsvc #
                elif SysMgr.checkMode("printsvc"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Show systemd services

Options:
    -a                          show all attributes
    -g  <NAME>                  set target file
    -c  <ATTR>                  set target attribute
    -I  <DIR>                   set input path
    -v                          verbose
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - {2:1}
        # {0:1} {1:1}

    - {2:1} about only specific files
        # {0:1} {1:1} -g test

    - {2:1} including specific attributes
        # {0:1} {1:1} -c Restart

    - {2:1} including specific value of attributes
        # {0:1} {1:1} -c :pid

    - {2:1} in specific directories
        # {0:1} {1:1} -I /home/iipeace/services
                    """.format(
                        cmd, mode, "Print systemd services"
                    )

                # printinfo #
                elif SysMgr.checkMode("printinfo"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Show system general info

Options:
    -v                          verbose
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - Print system info
        # {0:1} {1:1}
                    """.format(
                        cmd, mode
                    )

                # pstree #
                elif SysMgr.checkMode("pstree"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Show the tree of tasks

Options:
    -e  <CHARACTER>             enable options
          [ t:thread ]
    -g  <COMM>                  set filter
    -H  <LEVEL>                 set depth level
    -o  <DIR|FILE>              set output path
    -v                          verbose
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - Print the tree of processes
        # {0:1} {1:1}

    - Print the tree of specific processes
        # {0:1} {1:1} a.out
        # {0:1} {1:1} "a.out, yes"

    - Print the tree of threads
        # {0:1} {1:1} -e t

    - Print the highlighted processes having specific name
        # {0:1} {1:1} -g kworker

    - Print the tree of processes with depth 3
        # {0:1} {1:1} -H 3
                    """.format(
                        cmd, mode
                    )

                # comp #
                elif SysMgr.checkMode("comp"):
                    helpStr = """
Usage:
    # {0:1} {1:1} <FILE> [OPTIONS] [--help]

Description:
    Compress a file

Options:
    -o  <FILE>                  set output path
    -v                          verbose
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - Compress a file
        # {0:1} {1:1} guider.out
        # {0:1} {1:1} guider.out -o guider.out.gz

    - Compress multiple files
        # {0:1} {1:1} "guider.out, guider2.out"
        # {0:1} {1:1} "guider*.out"
                    """.format(
                        cmd, mode
                    )

                # decomp #
                elif SysMgr.checkMode("decomp"):
                    helpStr = """
Usage:
    # {0:1} {1:1} <FILE> [OPTIONS] [--help]

Description:
    Decompress a file

Options:
    -o  <DIR>                   set output path
    -v                          verbose
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - Decompress a file
        # {0:1} {1:1} guider.gz
        # {0:1} {1:1} guider.gz -o guider.out

    - Decompress multiple files
        # {0:1} {1:1} "guider.out.gz, guider2.out.gz"
        # {0:1} {1:1} "guider*.gz"
                    """.format(
                        cmd, mode
                    )

                # systat #
                elif SysMgr.checkMode("systat"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Print system status

Options:
    -e  <CHARACTER>             enable options
          [ t:thread ]
    -J                          print in JSON format
    -v                          verbose
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - Print system status
        # {0:1} {1:1}
                    """.format(
                        cmd, mode
                    )

                # request #
                elif SysMgr.checkMode("req"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Request URLs

Options:
    -I  <METHOD#OPT#ADDR>       input requests
    -o  <DIR|FILE>              set output path
    -R  <DELAY:COUNT>           set repeat count
    -T  <PROC>                  set process number
    -q  <NAME{{:VALUE}}>          set environment variables
    -v                          verbose
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - Run client with interaction menu
        # {0:1} {1:1}

    - {2:1}
        # {0:1} {1:1} http://127.0.0.1:5000
        # {0:1} {1:1} GET#http://127.0.0.1:5000
        # {0:1} {1:1} "GET#http://127.0.0.1:5000|GET#http://10.25.123.123:5000"

    - {2:1} with Keep-Alive attribute
        # {0:1} {1:1} http://127.0.0.1:5000 -q KEEPALIVE

    - Request GET/URL with alias to specific server
        # {0:1} {1:1} ALIAS:TEST1#http://127.0.0.1:5000

    - {2:1} and print contents for the request
        # {0:1} {1:1} http://127.0.0.1:5000 -q PRINTREQ

    - {2:1} and print only summary for requests
        # {0:1} {1:1} http://127.0.0.1:5000 -q MUTE

    - {3:1}
        # {0:1} {1:1} POST#DATA:"data"#http://127.0.0.1:5000
        # {0:1} {1:1} POST#JSONDATA:"{{'key':'value'}}"#http://127.0.0.1:5000

    - {3:1} after base64 encoding specific file data from specific string "@@@FILE:PATH@@@"
        # {0:1} {1:1} POST#DATA:"@@@FILE:a.out@@@"#http://127.0.0.1:5000
        # {0:1} {1:1} POST#JSONDATA:"{{'date':'123', 'image': {{'name': 'good', 'data':'@@@FILE:a.out@@@'}}}}"#http://127.0.0.1:5000
        # {0:1} {1:1} POST#JSONFILE:input.json#http://127.0.0.1:5000

    - {3:1} with base64 encoded data from specific string "@@@BIN:SIZE@@@"
        # {0:1} {1:1} POST#DATA:"@@@BIN:4MB@@@"#http://127.0.0.1:5000

    - {3:1} with files
        # {0:1} {1:1} POST#FILE:image:test.png:img/png#http://127.0.0.1:5000
        # {0:1} {1:1} POST#FILE:doc:test.txt:doc/txt#http://127.0.0.1:5000
        # {0:1} {1:1} POST#FILE:test.png:img/png#http://127.0.0.1:5000

    - {3:1} with data from data.json file
        # {0:1} {1:1} POST#JSONFILE:data.json#http://127.0.0.1:5000

    - {3:1} with data from data file
        # {0:1} {1:1} POST#DATAFILE:data#http://127.0.0.1:5000

    - {2:1} infinitely
        # {0:1} {1:1} GET#http://127.0.0.1:5000 -R

    - {2:1} 10 times with 500ms delay
        # {0:1} {1:1} GET#http://127.0.0.1:5000 -R 500:10

    - {2:1} 10 times by 10 processes
        # {0:1} {1:1} GET#http://127.0.0.1:5000 -R 10 -T 10

    - {2:1} with 5 second timeout
        # {0:1} {1:1} GET#TIMEOUT:5#http://127.0.0.1:5000

    - {2:1} with no verification for SSL
        # {0:1} {1:1} GET#VERIFY:false#https://127.0.0.1:5000

    - {2:1} with auth
        # {0:1} {1:1} GET#AUTH:id,passwd#https://127.0.0.1:5000

    - {2:1} with cookies
        # {0:1} {1:1} GET#COOKIES:sessionKey:sessionValue#https://127.0.0.1:5000

    - {2:1} with headers
        # {0:1} {1:1} GET#HEADERS:Content-Type:application/json;charset=utf-8#https://127.0.0.1:5000
                    """.format(
                        cmd,
                        mode,
                        "Request GET/URL to specific server",
                        "Request POST/URL to specific server",
                    )

                # limitcpu #
                elif SysMgr.checkMode("limitcpu"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -g <TID|PID:PER> [OPTIONS] [--help]

Description:
    Limit CPU usage of threads / processes

Options:
    -g  <TID|COMM>              set task filter
    -R  <TIME>                  set timer
    -P                          group threads in a same process
    -q  <NAME{{:VALUE}}>          set environment variables
    -v                          verbose
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - {2:1} for specific threads
        # {0:1} {1:1} yes:20

    - {2:1} for specific threads (wait for new target if no task)
        # {0:1} {1:1} yes:20 -q WAITTASK
        # {0:1} {1:1} yes:20 -q WAITTASK:1
        # {0:1} {1:1} yes:20 -q WAITTASK, NOPIDCACHE

    - {2:1} of specific threads for 3 seconds
        # {0:1} {1:1} -g 1234:10, yes:20 -R 3
                    """.format(
                        cmd, mode, "Limit CPU usage"
                    )

                # setcpu #
                elif SysMgr.checkMode("setcpu"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -g <CORE:CLOCK:GOVERNOR> [OPTIONS] [--help]

Description:
    Set CPU clock and governor

Options:
    -g  <CORE:CLOCK:GOVERNOR>   set filter
    -v                          verbose
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - {2:1} 2,000,000HZ and the governor to userspace for CPU1
        # {0:1} {1:1} 1:10000000:userspace

    - {2:1} 2,000,000HZ and the governor to userspace for All CPUs
        # {0:1} {1:1} :10000000:userspace

    - {2:1} 2,000,000HZ for CPU0
        # {0:1} {1:1} 0:10000000

    - Set the governor to performance for CPU2
        # {0:1} {1:1} 2::performance

    - Set the governor to performance for all CPUs
        # {0:1} {1:1} ::performance
                    """.format(
                        cmd, mode, "Set the clock speed to"
                    )

                # convert #
                elif SysMgr.checkMode("convert"):
                    helpStr = """
Usage:
    # {0:1} {1:1} <FILE> [OPTIONS] [--help]

Description:
    Convert a text file to a image file

Options:
    -v                          verbose
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - Convert a text file to a image file
        # {0:1} {1:1} guider.out
                    """.format(
                        cmd, mode
                    )

                # drawreq #
                elif SysMgr.checkMode("drawreq"):
                    helpStr = """
Usage:
    # {0:1} {1:1} <FILE> [OPTIONS] [--help]

Description:
    Draw graphs for response time

Options:
    -v                          verbose
    -I  <DIR|FILE>              set input path
    -o  <DIR|FILE>              set output path
    -g  <WORD>                  set filter
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - Draw graphs for response time
        # {0:1} {1:1} guider.out
        # {0:1} {1:1} "guider*.out"

    - Draw graphs for response time for specific requests
        # {0:1} {1:1} guider.out -g www.google.com
                    """.format(
                        cmd, mode
                    )

                # rlimit #
                elif SysMgr.checkMode("rlimit"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -g <TID|COMM:RTYPE:SLIM:HLIM> [OPTIONS] [--help]

Description:
    Change resource limit for specific tasks

Resource:
    {2:1}

Options:
    -g <TID|COMM:RTYPE:SLIM:HLIM> set value
    -v                            verbose
                        """.format(
                        cmd, mode, "\n    ".join(ConfigMgr.RLIMIT_TYPE)
                    )

                    helpStr += """
Examples:
    - Change resource limit for specific tasks
        # {0:1} {1:1} "a.out:RLIMIT_NOFILE:1000:2000"
        # {0:1} {1:1} -g "a.out:RLIMIT_NOFILE:1000:2000"

    - Show resource limits for specific tasks
        # {0:1} {1:1} a.out
        # {0:1} {1:1} -g a.out
                    """.format(
                        cmd, mode
                    )

                # setsched #
                elif SysMgr.checkMode("setsched"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -g <POLICY:PRIO|TIME:TID|COMM> [OPTIONS] [--help]
    # {0:1} {1:1} -g <CLASS:WHICH:PRIO:TID|COMM> [OPTIONS] [--help]

Description:
    Set the scheduler policy and priority for tasks

Policy(CPU):
    c: CFS [default]
    f: FIFO(RT)
    r: RR(RT)
    b: BATCH
    i: IDLE
    d: DEADLINE

Class(I/O):
    rt:   IOPRIO_CLASS_RT
    be:   IOPRIO_CLASS_BE
    idle: IOPRIO_CLASS_IDLE

Who(I/O):
    process: IOPRIO_WHO_PROCESS
    pgrp:    IOPRIO_WHO_PGRP
    user:    IOPRIO_WHO_USER

Options:
    -g <POLICY:PRIO|TIME:TID|COMM>  set value for CPU scheduling
    -g <CLASS:WHO:PRIO:TID|COMM>    set value for I/O scheduling
    -P                              group threads in a same process
    -i  <SEC>                       set interval
    -W  <SEC>                       wait for input
    -q  <NAME{{:VALUE}}>              set environment variables
    -v                              verbose
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - {3:1} policy(CFS), priority(-20) {2:1}
        # {0:1} {1:1} "-20:a.out"
        # {0:1} {1:1} "c:-20:1234"
        # {0:1} {1:1} "-20:a*"
        # {0:1} {1:1} "-20:1234, 10:a.out, 15:test"
        # {0:1} {1:1} "-20:a.out|test"

    - Set the I/O scheduler {2:1}
        # {0:1} {1:1} "rt:process:1:a.out"
        # {0:1} {1:1} "idle:process:1:a.out"
        # {0:1} {1:1} "be:5:a.out"
        # {0:1} {1:1} "rt:process:1:0"

    - {3:1} policy(CFS), priority(-20) for specific TID
        # {0:1} {1:1} "-20:1234" -q ONLYPID

    - {3:1} policy(CFS), priority(-20) for specific task name
        # {0:1} {1:1} "-20:1234" -q ONLYCOMM

    - {3:1} policy(CFS), priority(-20) for specific processes
        # {0:1} {1:1} "-20:a.out" -q PROCSEARCH

    - {3:1} policy(CFS), priority(-20) for all sibling threads of specific processes
        # {0:1} {1:1} "-20:a.out" -q PROCSEARCH -P (save CPU resource for searching tasks)

    - {3:1} policy(CFS), priority(-20) {2:1} (wait for new target if no task)
        # {0:1} {1:1} "-20:a.out" -q WAITTASK
        # {0:1} {1:1} "-20:a.out" -q WAITTASK:1
        # {0:1} {1:1} "-20:a.out" -q WAITTASK, NOPIDCACHE

    - {3:1} policy(CFS), priority(-20) {2:1} after 5 seconds
        # {0:1} {1:1} "-20:a.out" -W 5s

    - {3:1} policy(CFS), priority(-20) {2:1} every 2 seconds
        # {0:1} {1:1} "-20:a.out" -i 2

    - {3:1} policy(CFS), priority(-20) {2:1} and their siblings
        # {0:1} {1:1} "-20:a.out" -P

    - {3:1} policy(FIFO), priority(90) {2:1}
        # {0:1} {1:1} "f:90:a.out"

    - {3:1} policy(DEADLINE), runtime(1ms), deadline(10ms), period(10ms) {2:1}
        # {0:1} {1:1} "d:1000000/10000000/10000000:a.out"
                    """.format(
                        cmd,
                        mode,
                        "for specific threads",
                        "Set the CPU scheduler",
                    )

                # printkconf #
                elif SysMgr.checkMode("printkconf"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -g <OPTION> -I <PATH> [OPTIONS] [--help]

Description:
    Print kernel config

Options:
    -g  <OPTION>                set value
    -I                          set input path
    -v                          verbose
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - Print all kernel configs
        # {0:1} {1:1}

    - Print specific kernel configs
        # {0:1} {1:1} "CONFIG_RT_GROUP_SCHED*"
        # {0:1} {1:1} -g "CONFIG_RT_GROUP_SCHED*"

    - Print kernel config from the specific file
        # {0:1} {1:1} -I /boot/config-4.4.0-210-generic
                    """.format(
                        cmd, mode
                    )

                # getaffinity #
                elif SysMgr.checkMode("getafnt"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -g <TID|COMM> [OPTIONS] [--help]

Description:
    Get CPU affinity of threads

Options:
    -g  <TID|COMM>              set values
    -P                          group threads in a same process
    -v                          verbose
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - Get CPU affinity of specific threads
        # {0:1} {1:1} -g a.out, 1234
        # {0:1} {1:1} "a.out, 1234"
                    """.format(
                        cmd, mode
                    )

                # setaffinity #
                elif SysMgr.checkMode("setafnt"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -g <TARGET:MASK> [OPTIONS] [--help]

Description:
    Set CPU affinity of threads

Options:
    -g  <TID|COMM:MASK>         set values
    -P                          group threads in a same process
    -i  <SEC>                   set interval
    -q  <NAME{{:VALUE}}>          set environment variables
    -v                          verbose
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - {2:1} to use only CPU 1 and CPU 2
        # {0:1} {1:1} a.out:3
        # {0:1} {1:1} -g a.out:3

    - {2:1} to use only CPU 1 (wait for new target if no task)
        # {0:1} {1:1} a.out:2 -q WAITTASK
        # {0:1} {1:1} a.out:2 -q WAITTASK:1
        # {0:1} {1:1} a.out:2 -q WAITTASK, NOPIDCACHE

    - {2:1} to use only CPU 1 every 2 seconds
        # {0:1} {1:1} a.out:1 -i 2
                    """.format(
                        cmd, mode, "Set CPU affinity of a specific thread"
                    )

                # ping #
                elif SysMgr.checkMode("ping"):
                    helpStr = """
Usage:
    # {0:1} {1:1} <IP|URL> [OPTIONS] [--help]

Description:
    Send ICMP ECHO_REQUEST to network hosts

Options:
    -R  <COUNT>                 set repeat count
    -T  <TIMEOUT>               set timeout
    -I  <FILE>                  set input path
    -i  <SEC>                   set interval
    -J                          print in JSON format
    -v                          verbose
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - {2:1}
        # {0:1} {1:1} www.google.com
        # {0:1} {1:1} "www.google.com, www.naver.com"
        # {0:1} {1:1} "192.168.100.*"
        # {0:1} {1:1} "192.168.100.10-250"

    - {2:1} in a specific file
        # {0:1} {1:1} -I ip.txt

    - {2:1} with 3 second interval infinitely
        # {0:1} {1:1} www.google.com -i 3

    - {2:1} 3 times
        # {0:1} {1:1} www.google.com -R 3

    - {2:1} with 2.5 second timeout
        # {0:1} {1:1} www.google.com -T 2.5
                    """.format(
                        cmd, mode, "Send ICMP ECHO_REQUEST to network hosts"
                    )

                # cputest #
                elif SysMgr.checkMode("cputest"):
                    helpStr = """
Usage:
    # {0:1} {1:1} <LOAD:NRTASK> [OPTIONS] [--help]

Description:
    Create tasks using cpu

Options:
    -R  <TIME>                  set timer
    -Y  <POLICY:PRIO|TIME       set sched
         {{:TID|COMM:CONT}}>
    -v                          verbose
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - Create 10 processes using 5% of a core each other
        # {0:1} {1:1} 50:10

    - {2:1} 250% CPU totally
        # {0:1} {1:1} 250

    - {2:1} 250% CPU totally with custom process name
        # {0:1} {1:1} 250 -q COMM:newbee

    - Create threads in a process using 250% CPU totally
        # {0:1} {1:1} 250 -et

    - {2:1} 250% CPU totally with RR 1 priority
        # {0:1} {1:1} 250 -Y r:1

    - {2:1} 250% CPU totally and run them only on CPU 1
        # {0:1} {1:1} 250 -z :1

    - {2:1} 250% CPU totally and terminate them after 3 seconds
        # {0:1} {1:1} 250 -R 3
                    """.format(
                        cmd, mode, "Create processes using"
                    )

                # memtest #
                elif SysMgr.checkMode("memtest"):
                    helpStr = """
Usage:
    # {0:1} {1:1} <SIZE:INTERVAL:COUNT> [OPTIONS] [--help]

Description:
    Allocate physical memory

Options:
    -i  <SEC>                   set interval
    -R  <TIME>                  set timer
    -v                          verbose
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - {2:1} 1G and {3:1} every second
        # {0:1} {1:1} 1G

    - {2:1} 1G and {3:1} every 3 seconds
        # {0:1} {1:1} 1G -i 3

    - {2:1} 1G and {3:1} every second with custom process name
        # {0:1} {1:1} 1G -q COMM:newbee

    - {2:1} 200MB using a new process every 3 seconds
        # {0:1} {1:1} 200M:3

    - {2:1} 100MB twice using 2 processes and {3:1} every second
        # {0:1} {1:1} 100M:0:2

    - {2:1} 100MB twice using 2 processes and terminate them after 3 seconds
        # {0:1} {1:1} 100M:0:2 -R 3
                    """.format(
                        cmd,
                        mode,
                        "Allocate physical memory",
                        "print memory stats",
                    )

                # iotest #
                elif SysMgr.checkMode("iotest"):
                    helpStr = """
Usage:
    # {0:1} {1:1} -g <OP:PATH> [OPTIONS] [--help]

Description:
    Run storage I/O operations

Options:
    -g  <OP:PATH>               set path
    -i  <TIME>                  set timer
    -R  <COUNT>                 set repeat count
    -q  <NAME{{:VALUE}}>          set environment variables
    -v                          verbose
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - Read all files from current mount point
        # {0:1} {1:1}

    - Read all files from current directory recursively
        # {0:1} {1:1} .
        # {0:1} {1:1} -g .

    - Read all files from current directory recursively for 3 seconds
        # {0:1} {1:1} . -i 3
        # {0:1} {1:1} -g . -i 3

    - Read all files from current mount point with custom process name
        # {0:1} {1:1} -q COMM:newbee

    - Read specific files 5 times
        # {0:1} {1:1} "read:TEST1,TEST2" -R 5
        # {0:1} {1:1} "read:TEST*" -R 5

    - Read the specific file with specific chunk size
        # {0:1} {1:1} read:TEST -q CHUNK:1M

    - Read all device nodes mounted
        # {0:1} {1:1} -a

    - Read all device nodes mounted after flushing the system cache
        # {0:1} {1:1} -a -q DROPCACHE

    - Write dummy data to the specific file infinitely
        # {0:1} {1:1} write:TEST
        # {0:1} {1:1} -g write:TEST

    - Write 100MB of dummy data to the specific file
        # {0:1} {1:1} write:TEST:100m
        # {0:1} {1:1} "write:TEST:100m, write:TEST2:50m"
        # {0:1} {1:1} -g write:TEST:100m
        # {0:1} {1:1} write:TEST:100m -q SYNC
                    """.format(
                        cmd, mode
                    )

                # nettest #
                elif SysMgr.checkMode("nettest"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Run network I/O operations

Options:
    -x  <IP:PORT>               set local address
    -I  <PROTOCOL{{:IP:PORT}}>    set job
    -R  <TIME>                  set timer
    -v                          verbose
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - Send UDP packets
        # {0:1} {1:1}

    - Send UDP packets with 3 processes
        # {0:1} {1:1} udp, udp, udp
        # {0:1} {1:1} -I udp, udp, udp
                    """.format(
                        cmd, mode
                    )

                # flush #
                elif SysMgr.checkMode("flush"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Flush specific file pages on memory

Options:
    -i  <SEC>                   set interval
    -v                          verbose
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - Flush all caches on memory
        # {0:1} {1:1}
        # {0:1} {1:1} 1 (page caches)
        # {0:1} {1:1} 2 (slab caches)
        # {0:1} {1:1} 3 (both caches)

    - Flush specific file pages for the file
        # {0:1} {1:1} ./TEST

    - Flush specific file pages for the file every 3 seconds
        # {0:1} {1:1} ./TEST -i 3
                    """.format(
                        cmd,
                        mode,
                    )

                # list #
                elif SysMgr.checkMode("list"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Show running {2:1} processes

Options:
    -Q                          print all rows in a stream
    -v                          verbose
                        """.format(
                        cmd, mode, __module__
                    )

                # start #
                elif SysMgr.checkMode("start"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Send signal to all running Guider processes to run

Options:
    -v                          verbose
                        """.format(
                        cmd, mode
                    )

                # event #
                elif SysMgr.checkMode("event"):
                    helpStr = """
Usage:
    # {0:1} {1:1} <EVENT> [OPTIONS] [--help]

Description:
    Notify the event to running Guider processes

Options:
    -I  <EVENT>                 set event name
    -g  <PID>                   set target
    -X  <IP:PORT>               set request address
    -v                          verbose

Commands:
    CMD_BUFFER:TIME           resize the monitoring buffer
    CMD_CLEAR                 clear the monitoring buffer
    CMD_DISABLE:ATTR          disable monitoring of the specific resource
    CMD_ENABLE:ATTR           enable monitoring of the specific resource
    CMD_FILTER:ITEM           set the task filter
    CMD_INTERVAL:TIME         change the monitoring interval
    CMD_PAUSE                 pause all monitoring activities
    CMD_RELOAD:PATH           reload the threshold config
    CMD_RESTART               restart the Guider process
    CMD_SAVE{{:TIME@NAME}}      save the monitoring results
    CMD_SAVERAW{{:TIME@NAME}}   save the monitoring results
    CMD_STOP                  stop the threshold monitoring
    CMD_UPDATE:FILE           update the threshold data
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - Notify specific events {2:1}
        # {0:1} {1:1} EVENT1
        # {0:1} {1:1} EVENT1, EVENT2
        # {0:1} {1:1} -I EVENT1, EVENT2

    - Notify specific events to the specific address for minimum latency
        # {0:1} {1:1} EVENT1, EVENT2 -X
        # {0:1} {1:1} EVENT1, EVENT2 -X 4545
        # {0:1} {1:1} EVENT1, EVENT2 -X 192.168.155.200:4545

    - Notify specific events to specific Guider processes
        # {0:1} {1:1} EVENT1, EVENT2 -g 1234, 1237

    - Notify CMD_SAVE event {2:1} to save the monitoring results to the specific file
        # {0:1} {1:1} CMD_SAVE
        # {0:1} {1:1} CMD_SAVE:3s
        # {0:1} {1:1} CMD_SAVE:1m
        # {0:1} {1:1} CMD_SAVE:2s@FrameDropCase

    - Notify CMD_SAVERAW event {2:1} to save the monitoring results composed only of raw data to the specific file
        # {0:1} {1:1} CMD_SAVERAW
        # {0:1} {1:1} CMD_SAVERAW:3s
        # {0:1} {1:1} CMD_SAVERAW:1m
        # {0:1} {1:1} CMD_SAVERAW:2s@FrameDropCase

    - Notify CMD_BUFFER event {2:1} to resize the monitoring buffer
        # {0:1} {1:1} CMD_BUFFER:500k
        # {0:1} {1:1} CMD_BUFFER:2m

    - Notify CMD_INTERVAL event {2:1} to change the monitoring interval
        # {0:1} {1:1} CMD_INTERVAL:3s
        # {0:1} {1:1} CMD_INTERVAL:1m

    - Notify CMD_FILTER event {2:1} to set the task filter
        # {0:1} {1:1} CMD_FILTER:"*kworker*"
        # {0:1} {1:1} CMD_FILTER:"a.out|systemd"

    - Notify CMD_UPDATE event {2:1} to update the threshold data from the specific file
        # {0:1} {1:1} CMD_UPDATE:test.conf

    - Notify CMD_ENABLE or CMD_DISABLE events {2:1} to enable monitoring of specific resources
        # {0:1} {1:1} CMD_ENABLE:ALL
        # {0:1} {1:1} CMD_DISABLE:ALL
        # {0:1} {1:1} CMD_DISABLE:CPU
        # {0:1} {1:1} CMD_DISABLE:GPU
        # {0:1} {1:1} CMD_ENABLE:MEM
        # {0:1} {1:1} CMD_ENABLE:IRQ
        # {0:1} {1:1} CMD_ENABLE:DISK
        # {0:1} {1:1} CMD_ENABLE:BLOCK
        # {0:1} {1:1} CMD_ENABLE:NETWORK
        # {0:1} {1:1} CMD_ENABLE:PMU
        # {0:1} {1:1} CMD_ENABLE:LOG
                    """.format(
                        cmd, mode, "to all Guider processes"
                    )

                # server #
                elif SysMgr.checkMode("server"):
                    helpStr = """
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Run server

Options:
    -x  <IP:PORT>               set local address
    -X  <IP:PORT>               set agent address
    -u                          run in the background
    -C  <PATH>                  set config path
    -E  <DIR>                   set cache dir path
    -q  <NAME{{:VALUE}}>          set environment variables
    -v                          verbose
                        """.format(
                        cmd, mode
                    )

                    helpStr += """
Examples:
    - Run server in background
        # {0:1} {1:1} -u

    - {2:1} specific local address
        # {0:1} {1:1} -x 127.0.0.1:5556

    - Run server and register to the agent as a service node
        # {0:1} {1:1} -X 127.0.0.1:3456
        # {0:1} {1:1} -X 127.0.0.1:3456 -q CLIIP:127.0.0.1, CLIPORT:12345
        # {0:1} {1:1} -X 127.0.0.1:3456 -q CLIPORT:12345-12399
        # {0:1} {1:1} -X 127.0.0.1:3456 -q CLIPORT:12345-

    - {2:1} configuration
        # {0:1} {1:1} -C
        # {0:1} {1:1} -C guider.conf

    - {2:1} no timeout
        # {0:1} {1:1} -q NOTIMEOUT

    - {2:1} specific timeout
        # {0:1} {1:1} -q TIMEOUT:1.5

    - {2:1} specific read chunk size for command process
        # {0:1} {1:1} -q READCHUNK:4096

    - {2:1} no output for remote request
        # {0:1} {1:1} -q QUIET
                    """.format(
                        cmd, mode, "{2:1}"
                    )

                # client #
                elif SysMgr.checkMode("cli"):
                    helpStr = """
Usage:
    # {0:1} {1:1} <COMMAND> [OPTIONS] [--help]

Description:
    Request remote commands
{2:2}
Options:
    -x  <IP:PORT>               set local address
    -X  <IP:PORT>               set request address
    -E  <DIR>                   set cache dir path
    -c  <COMMAND>               set command
    -q  <NAME{{:VALUE}}>          set environment variables
    -v                          verbose
                        """.format(
                        cmd, mode, SysMgr.cliCmdStr
                    )

                    helpStr += """
Examples:
    - Run client with interaction menu
        # {0:1} {1:1}

    - Download a.out from the server to ./a.out
        # {0:1} {1:1} "d:a.out@./a.out"
        # {0:1} {1:1} "download:a.out@./a.out"
        # {0:1} {1:1} "download:a.out"

    - Download all files in test directory from the server to backup directory
        # {0:1} {1:1} "download:test/*@backup/"

    - Download TEST* from the server to ./
        # {0:1} {1:1} "d:TEST*"

    - Upload ./a.out to a.out in the server
        # {0:1} {1:1} "u:./a.out@a.out"
        # {0:1} {1:1} "upload:./a.out@a.out"
        # {0:1} {1:1} "upload:./a.out"

    - Ping to the server
        # {0:1} {1:1} p
        # {0:1} {1:1} "ping"

    - Print node list registered in the server
        # {0:1} {1:1} l
        # {0:1} {1:1} "list"

    - Print all worker processes executed by the server
        # {0:1} {1:1} j
        # {0:1} {1:1} "jobs"

    - Terminate all worker processes executed by the server
        # {0:1} {1:1} c
        # {0:1} {1:1} "clear"

    - Request remote commands in parallel by the server
        # {0:1} {1:1} "ls -lha", "date"
        # {0:1} {1:1} "192.168.0.100:5050|vmstat 1, 192.168.0.101:1234|find /"

    - Request remote commands by all nodes connected to the agent
        # {0:1} {1:1} "b:ls -lha"
        # {0:1} {1:1} "broadcast:ls -lha"
        # {0:1} {1:1} "b:restart"
        # {0:1} {1:1} "b:download:test/*@backup/""

    - Notify an event occurred to the server
        # {0:1} {1:1} "n:TEST"
        # {0:1} {1:1} "notify:TEST"

    - Request remote commands on the central server through the agent
        # {0:1} {1:1} "s:ls -lha"
        # {0:1} {1:1} "upstream:ls -lha"
        # {0:1} {1:1} "upstream:notify:TEST

    - Request remote commands by specific nodes connected to the agent
        # {0:1} {1:1} "b:@192.168.105.86/5589@192.168.105.100/5566:ls -lha"

    - Execute a remote commands with no timeout
        # {0:1} {1:1} "ls -lha" -q NOTIMEOUT

    - Execute a remote commands with specific timeout
        # {0:1} {1:1} "ls -lha" -q TIMEOUT:1.5

    - Execute a remote commands with no output
        # {0:1} {1:1} -q QUIET

    - Execute a remote commands using specific client addresses
        # {0:1} {1:1} -q CLIIP:127.0.0.1, CLIPORT:12345
        # {0:1} {1:1} -q CLIPORT:12345-12399
        # {0:1} {1:1} -q CLIPORT:12345-

    - Execute remote Guider commands in fixed-line-output
        # {0:1} {1:1} "192.168.0.100:5050|GUIDER top -m 15:, 192.168.0.101:1234|GUIDER ttop -m 15:"
                    """.format(
                        cmd, mode
                    )

                # default #
                elif mode.startswith("-") or mode == "help":
                    helpStr = (
                        defStr
                        + """
COMMAND:
{0:1}
FILE:
    Profile file (e.g. guider.dat)
    Report  file (e.g. guider.out)

Options:
    Check COMMAND with --help (e.g. {1:1} top --help)
                    """.format(
                            SysMgr.getCmdString(), cmd
                        )
                    )

                # wrong command #
                else:
                    SysMgr.printErr("wrong command %s" % mode)
                    sys.exit(-1)

                # no pager #
                if SysMgr.findOption("Q"):
                    SysMgr.setStream()

                # print small logo #
                SysMgr.printLogo()

                # print help #
                printPipe(helpStr)

            else:
                helpStr = (
                    defStr
                    + """
Author:
    {0:1} ({1:1})

Bugs:
    {1:1} | {2:1}/issues

Copyright:
    {3:1}
    License {4:1}.
    This is free software
                    """.format(
                        __author__,
                        __email__,
                        __repository__,
                        __copyright__,
                        __license__,
                    )
                )

                # no pager #
                SysMgr.setStream()

                # print help #
                printPipe(helpStr)

            sys.exit(0)

    @staticmethod
    def getKernelVersion(name=False):
        if SysMgr.kernelVersion:
            return SysMgr.kernelVersion

        try:
            kernel = os.uname()[2]
            if kernel:
                return kernel

            kernelList = kernel.split(".")

            # get kernel major version #
            kernelVersion = ".".join(kernelList[0:2])

            # get kernel minor version #
            if len(kernel) > 2:
                kernelVersion = "%s.%s" % (
                    kernelVersion,
                    kernelList[2].split("-")[0],
                )

            # update system info #
            SysMgr.kernelVersion = kernelVersion

            return kernelVersion
        except SystemExit:
            sys.exit(0)
        except:
            return None

    @staticmethod
    def getArch():
        if SysMgr.arch:
            return SysMgr.arch

        try:
            if SysMgr.isWindows:
                if "PROCESSOR_ARCHITECTURE" in os.environ:
                    arch = os.environ["PROCESSOR_ARCHITECTURE"]
                else:
                    arch = "N/A"
            else:
                arch = os.uname()[4]

            if arch.startswith("arm"):
                SysMgr.arch = "arm"
            elif arch.startswith("aarch64"):
                SysMgr.arch = "aarch64"
            elif (
                arch.startswith("x86_64")
                or arch.startswith("ia64")
                or arch == "AMD64"
            ):
                SysMgr.arch = "x64"
            elif (
                arch.startswith("i386")
                or arch.startswith("i686")
                or arch == "x86"
            ):
                SysMgr.arch = "x86"
            else:
                SysMgr.arch = arch
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.arch = "arm"

        return SysMgr.arch

    @staticmethod
    def setArch(arch):
        if not arch or not arch:
            return

        arch = UtilMgr.cleanItem(arch)

        # set syscall table #
        if arch == "arm":
            ConfigMgr.sysList = ConfigMgr.SYSCALL_ARM
            ConfigMgr.regList = ConfigMgr.REGS_ARM
            ConfigMgr.wordSize = 4
        elif arch == "aarch64":
            ConfigMgr.sysList = ConfigMgr.SYSCALL_AARCH64
            ConfigMgr.regList = ConfigMgr.REGS_AARCH64
            ConfigMgr.wordSize = 8
        elif arch == "x86":
            ConfigMgr.sysList = ConfigMgr.SYSCALL_X86
            ConfigMgr.regList = ConfigMgr.REGS_X86
            ConfigMgr.wordSize = 4
        elif arch == "x64":
            ConfigMgr.sysList = ConfigMgr.SYSCALL_X64
            ConfigMgr.regList = ConfigMgr.REGS_X64
            ConfigMgr.wordSize = 8
        else:
            support = " / ".join(ConfigMgr.supportArch)
            SysMgr.printErr(
                "failed to set architecture to %s, only %s supported"
                % (arch, support)
            )
            sys.exit(-1)

        SysMgr.arch = arch

    @staticmethod
    def waitForFile(dirname, filename):
        while 1:
            try:
                events = SysMgr.inotify(dirname)
                if not events:
                    break

                finished = False
                for item in events:
                    if item[2] == filename:
                        finished = True
                        break
                if finished:
                    break
            except SystemExit:
                sys.exit(0)
            except:
                break

    @staticmethod
    def inotify(path, flags=[], wait=False, verb=False):
        if not path:
            return False

        # load libc #
        SysMgr.loadLibcObj(exit=True)

        # convert path type to list #
        if type(path) is str:
            path = [path]

        # check and wait for files to be created #
        if wait:
            exitFlag = False

            for item in path:
                if os.path.exists(item):
                    continue

                # get file info #
                dirname, filename = UtilMgr.getPath(item)

                # set exit flag #
                exitFlag = True

                SysMgr.printWarn(
                    "failed to access to '%s', wait for it..." % item, verb
                )

                # wait for file creation #
                SysMgr.waitForFile(dirname, filename)

                # check result #
                if os.path.exists(item):
                    current = SysMgr.updateUptime()
                    fpath = os.path.realpath(os.path.expanduser(item))
                    SysMgr.printPipe("[%.6f] IN_CREATE@%s" % (current, fpath))
                else:
                    SysMgr.printWarn(
                        "skipped to wait '%s' to be created" % item, True
                    )

            # check exit condition #
            if exitFlag:
                sys.exit(0)

        # check flags type #
        if type(flags) is not list:
            SysMgr.printErr("failed to get flags as a list")
            return False

        if not SysMgr.inotifyEnable:
            inotifyFuncs = [
                "inotify_init",
                "inotify_add_watch",
                "read",
                "inotify_rm_watch",
                "close",
            ]

            # check functions #
            for func in inotifyFuncs:
                if not hasattr(SysMgr.libcObj, func):
                    SysMgr.printWarn(
                        "no %s in %s" % (func, SysMgr.libcPath), verb
                    )
                    return False

            SysMgr.inotifyEnable = True

        class inotify_event(Structure):
            _fields_ = (
                ("wd", c_int),
                ("mask", c_uint32),
                ("cookie", c_uint32),
                ("len", c_uint32),
                ("name", c_char_p),
            )

        # create an object #
        ie = inotify_event()
        EVENT_SIZE = sizeof(ie)
        BUF_LEN = 1024 * (EVENT_SIZE + 16)
        buf = (c_char * BUF_LEN)()

        # create a file descriptor #
        fd = SysMgr.libcObj.inotify_init()
        if fd < 0:
            SysMgr.printWarn("failed to inotify_init", verb)
            return False

        # get flag bits #
        fbits = UtilMgr.getFlagBit(ConfigMgr.INOTIFY_TYPE, flags)
        if fbits == 0:
            # IN_ALL #
            fbits = 0xFFF

        # create reverse list #
        flist = {}
        for flag in flags:
            flist[ConfigMgr.INOTIFY_TYPE[flag]] = flag

        # add watch #
        wlist = {}
        for item in path:
            wd = SysMgr.libcObj.inotify_add_watch(fd, item.encode(), fbits)
            if wd < 0:
                SysMgr.printWarn(
                    "failed to inotify_add_watch for '%s'" % item, verb
                )
                continue
            wlist[wd] = item

        # read events #
        length = SysMgr.libcObj.read(fd, byref(buf), BUF_LEN)
        if length < 0:
            SysMgr.printWarn("failed to read inotify event", verb)
            return False

        # check events #
        i = 0
        fmt = "iIII"
        revents = []
        size = struct.calcsize(fmt)
        while i < length:
            wd, mask, cookie, flen = struct.unpack(fmt, buf[i : i + size])

            # get file name #
            if flen > 0:
                (fname,) = struct.unpack(
                    "%ds" % flen, buf[i + size : i + size + flen]
                )
                fname = fname.decode().rstrip("\0")
            else:
                fname = None

            # get events #
            try:
                rtypes = UtilMgr.getFlagList(mask, ConfigMgr.INOTIFY_TYPE)
                revents.append([wlist[wd], rtypes, fname])
            except SystemExit:
                sys.exit(0)
            except:
                pass

            i += size + flen

        # clean up #
        for wd in list(wlist):
            SysMgr.libcObj.inotify_rm_watch(fd, wd)
        SysMgr.libcObj.close(fd)

        return revents

    @staticmethod
    def getNrSyscall(name):
        try:
            return SysMgr.syscallCache[name]
        except SystemExit:
            sys.exit(0)
        except:
            num = ConfigMgr.sysList.index(name)
            SysMgr.syscallCache[name] = num
            return num

    @staticmethod
    def syscall(syscall, *args):
        if not SysMgr.isLinux:
            return None

        try:
            # load libc #
            if not SysMgr.loadLibcObj():
                raise Exception("no libc")

            # check syscall #
            if UtilMgr.isNumber(syscall):
                nrSyscall = long(syscall)
                nmSyscall = ConfigMgr.sysList[nrSyscall]
            elif UtilMgr.isString(syscall):
                val = syscall.lower()
                if val[0:4] == "sys_":
                    nmSyscall = val
                else:
                    nmSyscall = "sys_%s" % val

                nrSyscall = SysMgr.getNrSyscall(nmSyscall)
            else:
                raise Exception("wrong syscall")

            try:
                nrParams = len(ConfigMgr.SYSCALL_PROTOTYPES[nmSyscall[4:]][1])
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "failed to get the number of arguments for %s" % nmSyscall
                )
                raise Exception("wrong syscall")

            # check arguments #
            if len(args) != nrParams:
                SysMgr.printErr(
                    (
                        "failed to get arguments for %s "
                        "because of wrong parameters"
                    )
                    % nmSyscall
                )
                raise Exception("wrong params")

            if nrParams == 0:
                ret = SysMgr.libcObj.syscall(nrSyscall)
            elif nrParams == 1:
                ret = SysMgr.libcObj.syscall(nrSyscall, args[0])
            elif nrParams == 2:
                ret = SysMgr.libcObj.syscall(nrSyscall, args[0], args[1])
            elif nrParams == 3:
                ret = SysMgr.libcObj.syscall(
                    nrSyscall, args[0], args[1], args[2]
                )
            elif nrParams == 4:
                ret = SysMgr.libcObj.syscall(
                    nrSyscall, args[0], args[1], args[2], args[3]
                )
            elif nrParams == 5:
                ret = SysMgr.libcObj.syscall(
                    nrSyscall, args[0], args[1], args[2], args[3], args[4]
                )
            elif nrParams == 6:
                ret = SysMgr.libcObj.syscall(
                    nrSyscall,
                    args[0],
                    args[1],
                    args[2],
                    args[3],
                    args[4],
                    args[5],
                )

            # print error code #
            if SysMgr.warnEnable and ret < 0:
                SysMgr.printWarn(
                    "%s for %s() syscall" % (SysMgr.getErrReason(), syscall)
                )

            return ret
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn(
                "failed to call %s syscall" % syscall, True, reason=True
            )

    @staticmethod
    def checkRootPerm(exit=True, verb=True, attr="error", msg=""):
        if SysMgr.isRoot():
            return True

        # print log #
        if verb:
            if msg:
                msg = " to %s" % msg

            if attr == "error":
                logger = SysMgr.printErr
            else:
                logger = SysMgr.printWarn

            logger("failed to get root permission%s" % msg)

        # exit #
        if exit:
            sys.exit(-1)
        else:
            return False

    @staticmethod
    def isRoot():
        if (SysMgr.isLinux or SysMgr.isDarwin) and os.geteuid() == 0:
            return True
        else:
            return False

    @staticmethod
    def openPerfEvent(econfig, cpu=-1, pid=-1):
        try:
            perfEventList = ConfigMgr.PERF_EVENT_TYPE
            if econfig in ConfigMgr.PERF_HW_EVENT_TYPE:
                nrType = perfEventList.index("PERF_TYPE_HARDWARE")
                nrConfig = ConfigMgr.PERF_HW_EVENT_TYPE.index(econfig)
            elif econfig in ConfigMgr.PERF_SW_EVENT_TYPE:
                nrType = perfEventList.index("PERF_TYPE_SOFTWARE")
                nrConfig = ConfigMgr.PERF_SW_EVENT_TYPE.index(econfig)
            else:
                raise Exception("wrong perf event")
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to recognize '%s' as the perf event type" % econfig
            )
            return False

        if SysMgr.guiderObj:
            # reference to http://man7.org/linux/man-pages/man2/perf_event_open.2.html #
            func = (
                SysMgr.guiderObj.perf_event_open
            )  # pylint: disable=no-member
            fd = func(nrType, nrConfig, pid, cpu, -1, 0)
            if fd < 0:
                # check root permission #
                if not SysMgr.checkRootPerm(
                    exit=False, msg="open perf events"
                ):
                    return False
                else:
                    return -1
            else:
                return fd

        # load libc #
        if not SysMgr.loadLibcObj():
            SysMgr.perfEnable = False
            SysMgr.perfGroupEnable = False
            return False

        # define struct perf_event_attr #
        class union_anon_5(Union):
            pass

        union_anon_5.__slots__ = ["sample_period", "sample_freq"]
        union_anon_5._fields_ = [
            ("sample_period", c_uint64),
            ("sample_freq", c_uint64),
        ]

        class union_anon_6(Union):
            pass

        union_anon_6.__slots__ = ["wakeup_events", "wakeup_watermark"]
        union_anon_6._fields_ = [
            ("wakeup_events", c_uint32),
            ("wakeup_watermark", c_uint32),
        ]

        class union_anon_7(Union):
            pass

        union_anon_7.__slots__ = ["bp_addr", "config1"]
        union_anon_7._fields_ = [("bp_addr", c_uint64), ("config1", c_uint64)]

        class union_anon_8(Union):
            pass

        union_anon_8.__slots__ = ["bp_len", "config2"]
        union_anon_8._fields_ = [("bp_len", c_uint64), ("config2", c_uint64)]

        class struct_perf_event_attr(Structure):
            pass

        """
        struct perf_event_attr
        {

            uint32_t type;

            uint32_t size;

            uint64_t config;

            union
            {
                uint64_t sample_period;
                uint64_t sample_freq;
            };

            uint64_t sample_type;

            uint64_t read_format;

            uint64_t disabled:1,                /* off by default        */
                     inherit:1,                 /* children inherit it   */
                     pinned:1,                  /* must always be on PMU */
                     exclusive:1,               /* only group on PMU     */
                     exclude_user:1,            /* don't count user      */
                     exclude_kernel:1,          /* ditto kernel          */
                     exclude_hv:1,              /* ditto hypervisor      */
                     exclude_idle:1,            /* don't count when idle */
                     mmap:1,                    /* include mmap data     */
                     comm:1,                    /* include comm data     */
                     freq:1,                    /* use freq, not period  */
                     inherit_stat:1,            /* per task counts       */
                     enable_on_exec:1,          /* next exec enables     */
                     task:1,                    /* trace fork/exit       */
                     watermark:1,               /* wakeup_watermark      */
                     /*
                      * precise_ip:
                      *
                      *  0 - SAMPLE_IP can have arbitrary skid
                      *  1 - SAMPLE_IP must have constant skid
                      *  2 - SAMPLE_IP requested to have 0 skid
                      *  3 - SAMPLE_IP must have 0 skid
                      *
                      *  See also PERF_RECORD_MISC_EXACT_IP
                      */
                     precise_ip:2,              /* skid constraint       */
                     mmap_data:1,               /* non-exec mmap data    */
                     sample_id_all:1,           /* sample_type all events */
                     exclude_host:1,            /* don't count in host   */
                     exclude_guest:1,           /* don't count in guest  */
                     exclude_callchain_kernel:1,        /* exclude kernel callchains */
                     exclude_callchain_user:1,  /* exclude user callchains */
                     mmap2:1,                   /* include mmap with inode data     */
                     comm_exec:1,               /* flag comm events that are due to an exec */
                     use_clockid:1,             /* use @clockid for time fields */
                     context_switch:1,          /* context switch data */
                     write_backward:1,          /* Write ring buffer from end to beginning */
                     namespaces:1,              /* include namespaces data */
                     __reserved_1:35;

            union
            {
                uint32_t wakeup_events; /* wakeup every n events */
                uint32_t wakeup_watermark;      /* bytes before wakeup   */
            };

            uint32_t bp_type;

            union
            {
                uint64_t bp_addr;
                uint64_t config1;               /* extension of config */
            };

            union
            {
                uint64_t bp_len;
                uint64_t config2;               /* extension of config1 */
            };

            uint64_t branch_sample_type;        /* enum perf_branch_sample_type */

            uint64_t sample_regs_user;

            uint32_t sample_stack_user;

            int32_t clockid;

            uint64_t sample_regs_intr;

            uint32_t aux_watermark;

            uint16_t sample_max_stack;

            uint16_t __reserved_2;              /* align to uint64_t */
        };
        """
        struct_perf_event_attr.__slots__ = [
            "type",
            "size",
            "config",
            "unnamed_1",
            "sample_type",
            "read_format",
            "disabled",
            "inherit",
            "pinned",
            "exclusive",
            "exclude_user",
            "exclude_kernel",
            "exclude_hv",
            "exclude_idle",
            "mmap",
            "comm",
            "freq",
            "inherit_stat",
            "enable_on_exec",
            "task",
            "watermark",
            "precise_ip",
            "mmap_data",
            "sample_id_all",
            "exclude_host",
            "exclude_guest",
            "exclude_callchain_kernel",
            "exclude_callchain_user",
            "mmap2",
            "comm_exec",
            "use_clockid",
            "context_switch",
            "write_backward",
            "namespaces",
            "__reserved_1",
            "unnamed_2",
            "bp_type",
            "unnamed_3",
            "unnamed_4",
            "branch_sample_type",
            "sample_regs_user",
            "sample_stack_user",
            "clockid",
            "sample_regs_intr",
            "aux_watermark",
            "sample_max_stack",
            "__reserved_2",
        ]
        struct_perf_event_attr._anonymous_ = [
            "unnamed_1",
            "unnamed_2",
            "unnamed_3",
            "unnamed_4",
        ]
        struct_perf_event_attr._fields_ = [
            ("type", c_uint32),
            ("size", c_uint32),
            ("config", c_uint64),
            ("unnamed_1", union_anon_5),
            ("sample_type", c_uint64),
            ("read_format", c_uint64),
            ("disabled", c_uint64, 1),
            ("inherit", c_uint64, 1),
            ("pinned", c_uint64, 1),
            ("exclusive", c_uint64, 1),
            ("exclude_user", c_uint64, 1),
            ("exclude_kernel", c_uint64, 1),
            ("exclude_hv", c_uint64, 1),
            ("exclude_idle", c_uint64, 1),
            ("mmap", c_uint64, 1),
            ("comm", c_uint64, 1),
            ("freq", c_uint64, 1),
            ("inherit_stat", c_uint64, 1),
            ("enable_on_exec", c_uint64, 1),
            ("task", c_uint64, 1),
            ("watermark", c_uint64, 1),
            ("precise_ip", c_uint64, 2),
            ("mmap_data", c_uint64, 1),
            ("sample_id_all", c_uint64, 1),
            ("exclude_host", c_uint64, 1),
            ("exclude_guest", c_uint64, 1),
            ("exclude_callchain_kernel", c_uint64, 1),
            ("exclude_callchain_user", c_uint64, 1),
            ("mmap2", c_uint64, 1),
            ("comm_exec", c_uint64, 1),
            ("use_clockid", c_uint64, 1),
            ("context_switch", c_uint64, 1),
            ("write_backward", c_uint64, 1),
            ("namespaces", c_uint64, 1),
            ("__reserved_1", c_uint64, 35),
            ("unnamed_2", union_anon_6),
            ("bp_type", c_uint32),
            ("unnamed_3", union_anon_7),
            ("unnamed_4", union_anon_8),
            ("branch_sample_type", c_uint64),
            ("sample_regs_user", c_uint64),
            ("sample_stack_user", c_uint32),
            ("clockid", c_int32),
            ("sample_regs_intr", c_uint64),
            ("aux_watermark", c_uint32),
            ("sample_max_stack", c_uint16),
            ("__reserved_2", c_uint16),
        ]

        # define constants for ioctl #
        _IOC_NRBITS = 8
        _IOC_TYPEBITS = 8
        _IOC_SIZEBITS = 14  # architecture specific
        _IOC_DIRBITS = 2
        _IOC_NRMASK = (1 << _IOC_NRBITS) - 1
        _IOC_TYPEMASK = (1 << _IOC_TYPEBITS) - 1
        _IOC_SIZEMASK = (1 << _IOC_SIZEBITS) - 1
        _IOC_DIRMASK = (1 << _IOC_DIRBITS) - 1
        _IOC_NRSHIFT = 0
        _IOC_TYPESHIFT = _IOC_NRSHIFT + _IOC_NRBITS
        _IOC_SIZESHIFT = _IOC_TYPESHIFT + _IOC_TYPEBITS
        _IOC_DIRSHIFT = _IOC_SIZESHIFT + _IOC_SIZEBITS
        _IOC_NONE = 0
        _IOC_WRITE = 1
        _IOC_READ = 2

        def _IOC(dir, type, nr, size):
            return (
                dir << _IOC_DIRSHIFT
                | ord(type) << _IOC_TYPESHIFT
                | nr << _IOC_NRSHIFT
                | size << _IOC_SIZESHIFT
            )

        def _IO(type, nr):
            return _IOC(_IOC_NONE, type, nr, 0)

        def _IOR(type, nr, size):
            return _IOC(_IOC_READ, type, nr, size)

        def _IOW(type, nr, size):
            return _IOC(_IOC_WRITE, type, nr, size)

        def _IOWR(type, nr, size):
            return _IOC(_IOC_READ | _IOC_WRITE, type, nr, size)

        # define CMD #
        PERF_EVENT_IOC_ENABLE = _IO("$", 0)
        PERF_EVENT_IOC_DISABLE = _IO("$", 1)
        PERF_EVENT_IOC_REFRESH = _IO("$", 2)
        PERF_EVENT_IOC_RESET = _IO("$", 3)
        PERF_EVENT_IOC_PERIOD = _IOW("$", 4, sizeof(c_uint64))
        PERF_EVENT_IOC_SET_OUTPUT = _IO("$", 5)
        PERF_EVENT_IOC_SET_FILTER = _IOW("$", 6, sizeof(c_uint))
        PERF_EVENT_IOC_ID = _IOR("$", 7, sizeof(c_uint64))
        PERF_EVENT_IOC_SET_BPF = _IOW("$", 8, sizeof(c_uint32))
        PERF_EVENT_IOC_PAUSE_OUTPUT = _IOW("$", 9, sizeof(c_uint32))

        # set struct perf_event_attr #
        perf_attr = struct_perf_event_attr()
        perf_attr.type = nrType
        perf_attr.config = nrConfig
        perf_attr.size = sizeof(perf_attr)
        perf_attr.disabled = 1
        # perf_attr.exclude_user = 1
        # perf_attr.exclude_kernel = 1
        # perf_attr.exclude_hv = 1
        # perf_attr.exclude_idle = 1

        # call a perf_event_open syscall #
        """
        int perf_event_open(struct perf_event_attr *attr,
            pid_t pid, int cpu, int group_fd, unsigned long flags);
        """
        # reference to http://man7.org/linux/man-pages/man2/perf_event_open.2.html #
        fd = SysMgr.syscall(
            "sys_perf_event_open", pointer(perf_attr), pid, cpu, -1, 0
        )
        if fd < 0:
            # check root permission #
            if not SysMgr.checkRootPerm(exit=False, msg="open perf events"):
                return False
            else:
                return -1

        # control perf event #
        SysMgr.syscall("ioctl", fd, PERF_EVENT_IOC_RESET, 0)
        SysMgr.syscall("ioctl", fd, PERF_EVENT_IOC_ENABLE, 0)

        # free perf_attr object, but memory leak exists now #
        del perf_attr

        return fd

    @staticmethod
    def readPerfEvents(fdList):
        if SysMgr.guiderObj:
            retList = []

            for fd in fdList:
                try:
                    # read PMU data #
                    value = SysMgr.guiderObj.perf_event_read(
                        fd
                    )  # pylint: disable=no-member

                    # add value to list #
                    retList.append(value)
                except SystemExit:
                    sys.exit(0)
                except:
                    retList.append(None)

            return retList

        # load libc #
        if not SysMgr.loadLibcObj():
            return

        # define struct read_group_format #
        class struct_anon_5(Structure):
            __slots__ = ["value", "id"]

            _fields_ = [("value", c_uint64), ("id", c_uint64)]

        """
        struct read_group_format {
            uint64_t nr;            /* The number of events */
            uint64_t time_enabled;  /* if PERF_FORMAT_TOTAL_TIME_ENABLED */
            uint64_t time_running;  /* if PERF_FORMAT_TOTAL_TIME_RUNNING */
            struct {
                uint64_t value;     /* The value of the event */
                uint64_t id;        /* if PERF_FORMAT_ID */
            } values[];
        };
        """
        """
        class struct_read_group_format(Structure):
            __slots__ = [
                'nr',
                #'time_enabled',
                #'time_running',
                'values',
            ]

            _fields_ = [
                ('nr', c_uint64),
                #('time_enabled', c_uint64),
                #('time_running', c_uint64),
                ('values', POINTER(struct_anon_5)),
            ]
        """

        # define struct read_format #
        """
        struct read_format {
            uint64_t value;         /* The value of the event */
            uint64_t time_enabled;  /* if PERF_FORMAT_TOTAL_TIME_ENABLED */
            uint64_t time_running;  /* if PERF_FORMAT_TOTAL_TIME_RUNNING */
            uint64_t id;            /* if PERF_FORMAT_ID */
        };
        """

        class struct_read_format(Structure):
            __slots__ = [
                "value",
                #'time_enabled',
                #'time_running',
                "id",
            ]

            _fields_ = [
                ("value", c_uint64),
                # ('time_enabled', c_uint64),
                # ('time_running', c_uint64),
                ("id", c_uint64),
            ]

        # define IOC for ioctl call #
        _IOC_NRBITS = 8
        _IOC_TYPEBITS = 8
        _IOC_SIZEBITS = 14  # architecture specific
        _IOC_DIRBITS = 2
        _IOC_NRMASK = (1 << _IOC_NRBITS) - 1
        _IOC_TYPEMASK = (1 << _IOC_TYPEBITS) - 1
        _IOC_SIZEMASK = (1 << _IOC_SIZEBITS) - 1
        _IOC_DIRMASK = (1 << _IOC_DIRBITS) - 1
        _IOC_NRSHIFT = 0
        _IOC_TYPESHIFT = _IOC_NRSHIFT + _IOC_NRBITS
        _IOC_SIZESHIFT = _IOC_TYPESHIFT + _IOC_TYPEBITS
        _IOC_DIRSHIFT = _IOC_SIZESHIFT + _IOC_SIZEBITS
        _IOC_NONE = 0
        _IOC_WRITE = 1
        _IOC_READ = 2

        def _IOC(dir, type, nr, size):
            return (
                dir << _IOC_DIRSHIFT
                | ord(type) << _IOC_TYPESHIFT
                | nr << _IOC_NRSHIFT
                | size << _IOC_SIZESHIFT
            )

        def _IO(type, nr):
            return _IOC(_IOC_NONE, type, nr, 0)

        def _IOR(type, nr, size):
            return _IOC(_IOC_READ, type, nr, size)

        def _IOW(type, nr, size):
            return _IOC(_IOC_WRITE, type, nr, size)

        def _IOWR(type, nr, size):
            return _IOC(_IOC_READ | _IOC_WRITE, type, nr, size)

        # define CMD #
        PERF_EVENT_IOC_ENABLE = _IO("$", 0)
        PERF_EVENT_IOC_DISABLE = _IO("$", 1)
        PERF_EVENT_IOC_REFRESH = _IO("$", 2)
        PERF_EVENT_IOC_RESET = _IO("$", 3)
        PERF_EVENT_IOC_PERIOD = _IOW("$", 4, sizeof(c_uint64))
        PERF_EVENT_IOC_SET_OUTPUT = _IO("$", 5)
        PERF_EVENT_IOC_SET_FILTER = _IOW("$", 6, sizeof(c_uint))
        PERF_EVENT_IOC_ID = _IOR("$", 7, sizeof(c_uint64))
        PERF_EVENT_IOC_SET_BPF = _IOW("$", 8, sizeof(c_uint32))
        PERF_EVENT_IOC_PAUSE_OUTPUT = _IOW("$", 9, sizeof(c_uint32))

        # declare syscalls #
        SysMgr.libcObj.ioctl.restype = c_int
        SysMgr.libcObj.ioctl.argtypes = [c_int, c_ulong]
        SysMgr.libcObj.read.argtypes = [c_int, POINTER(None), c_uint]
        SysMgr.libcObj.read.restype = c_int

        # declare buffer and retList #
        pbuf = (8 * c_ubyte)()
        retList = []

        for fd in fdList:
            try:
                # read PMU data #
                SysMgr.libcObj.read(fd, pointer(pbuf), sizeof(pbuf))

                # control perf event #
                SysMgr.libcObj.ioctl(fd, PERF_EVENT_IOC_RESET, 0)

                # cast buffer to data #
                retList.append(cast(pbuf, POINTER(c_ulong)).contents.value)
            except SystemExit:
                sys.exit(0)
            except:
                retList.append(None)

        return retList

    @staticmethod
    def initSystemPerfEvents():
        # check perf option #
        if not SysMgr.perfEnable:
            return

        # check root permission #
        if not SysMgr.isRoot():
            SysMgr.perfEnable = False
            return

        # check config #
        try:
            PMUs = "/sys/bus/event_source/devices"
            attrPath = "%s/sys/kernel/perf_event_paranoid" % SysMgr.procPath
            with open(attrPath, "w+") as fd:
                """
                -1 - not paranoid at all
                 0 - disallow raw tracepoint access for unpriv
                 1 - disallow CPU events for unpriv
                 2 - disallow kernel profiling for unpriv
                 3 - disallow user profiling for unpriv
                """
                paranoid = long(fd.readline()[:-1])
                if paranoid > -1:
                    fd.seek(0)
                    # write all privilege to read perf events #
                    fd.write("-1")
                    SysMgr.printWarn(
                        (
                            "change value of %s from %s to -1 "
                            "to read all perf events"
                        )
                        % (attrPath, paranoid)
                    )
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("enable CONFIG_PERF_EVENTS kernel option")
            return

        hwTargetList = [
            "PERF_COUNT_HW_CPU_CYCLES",
            "PERF_COUNT_HW_INSTRUCTIONS",
            "PERF_COUNT_HW_CACHE_REFERENCES",
            "PERF_COUNT_HW_CACHE_MISSES",
            "PERF_COUNT_HW_BRANCH_INSTRUCTIONS",
            "PERF_COUNT_HW_BRANCH_MISSES",
        ]

        swTargetList = [
            "PERF_COUNT_SW_CPU_CLOCK",
            "PERF_COUNT_SW_PAGE_FAULTS_MIN",
            "PERF_COUNT_SW_PAGE_FAULTS_MAJ",
        ]

        successCnt = 0
        cpuPath = "/sys/devices/system/cpu"
        cpuList = [
            UtilMgr.lstrip(coreId, "cpu")
            for coreId in os.listdir(cpuPath)
            if coreId.startswith("cpu")
        ]

        for item in cpuList:
            try:
                coreId = long(item)
            except:
                continue

            SysMgr.perfEventChannel[coreId] = {}

            # HW Events #
            for evt in hwTargetList:
                # initialize hw event channels #
                SysMgr.perfEventChannel[coreId][evt] = SysMgr.openPerfEvent(
                    evt, coreId
                )

                # handle unavailable hw events #
                if SysMgr.perfEventChannel[coreId][evt] == -1:
                    del SysMgr.perfEventChannel[coreId][evt]
                elif not SysMgr.perfEventChannel[coreId][evt]:
                    return
                else:
                    successCnt += 1

            # SW Events #
            for evt in swTargetList:
                # initialize sw event channels #
                SysMgr.perfEventChannel[coreId][evt] = SysMgr.openPerfEvent(
                    evt, coreId
                )

                # handle unavailable sw events #
                if SysMgr.perfEventChannel[coreId][evt] == -1:
                    del SysMgr.perfEventChannel[coreId][evt]
                elif not SysMgr.perfEventChannel[coreId][evt]:
                    return
                else:
                    successCnt += 1

            if (
                not SysMgr.perfTargetEvent
                and len(SysMgr.perfEventChannel[coreId]) > 0
            ):
                SysMgr.perfTargetEvent = list(SysMgr.perfEventChannel[coreId])

        if successCnt == 0:
            SysMgr.printWarn("failed to find available perf event")
            SysMgr.perfEnable = False
            SysMgr.perfGroupEnable = False

    @staticmethod
    def initProcPerfEvents(pid):
        eventChannel = {}

        for evt in SysMgr.perfTargetEvent:
            eventChannel[evt] = SysMgr.openPerfEvent(evt, -1, pid)

        return eventChannel

    @staticmethod
    def collectSystemPerfData():
        SysMgr.perfEventData = {}

        # check perf event option #
        if SysMgr.perfGroupEnable and not SysMgr.perfEventChannel:
            return

        # check perf event channel #
        for coreId in list(SysMgr.perfEventChannel):
            # make event list #
            events = list(SysMgr.perfEventChannel[coreId])

            # remove all core events if specific target process exist #
            if SysMgr.perfGroupEnable:
                for fd in SysMgr.perfEventChannel[coreId].values():
                    os.close(fd)
                del SysMgr.perfEventChannel[coreId]
                continue

            # get event data #
            values = SysMgr.readPerfEvents(
                SysMgr.perfEventChannel[coreId].values()
            )

            if not values:
                continue

            # summarize perf data of each cores #
            for idx, evt in enumerate(events):
                try:
                    SysMgr.perfEventData[evt] += values[idx]
                except:
                    SysMgr.perfEventData[evt] = values[idx]

    @staticmethod
    def collectProcPerfData(fdList):
        perfData = {}

        # make event list #
        events = list(fdList)

        # get event data #
        values = SysMgr.readPerfEvents(fdList.values())

        # summarize perf data of each cores #
        for idx, evt in enumerate(events):
            perfData[evt] = values[idx]

        return perfData

    @staticmethod
    def getPerfString(value):
        perfbuf = ""

        if not value:
            return perfbuf

        convColor = UtilMgr.convColor
        convSize = UtilMgr.convSize2Unit

        inst = cpucycle = -1
        cacheref = cachemiss = cachemissrate = -1
        branch = branchmiss = branchmissrate = -1

        # IPC stats #
        try:
            cpucycle = value["PERF_COUNT_HW_CPU_CYCLES"]
            perfbuf = "%sCycle: %s / " % (
                perfbuf,
                convColor(convSize(cpucycle), "YELLOW"),
            )
            inst = value["PERF_COUNT_HW_INSTRUCTIONS"]
            perfbuf = "%sInst: %s / " % (
                perfbuf,
                convColor(convSize(inst), "YELLOW"),
            )
            ipc = inst / float(cpucycle)
            perfbuf = "%sIPC: %s / " % (
                perfbuf,
                convColor("%.2f" % ipc, "YELLOW"),
            )
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # CACHE stats #
        try:
            cacheref = value["PERF_COUNT_HW_CACHE_REFERENCES"]
            cachemiss = value["PERF_COUNT_HW_CACHE_MISSES"]
            cachemissrate = long(cachemiss / float(cacheref) * 100)
            perfbuf = "%sCacheMiss : %s(%s) / " % (
                perfbuf,
                convSize(cachemiss),
                convColor("%s%%" % cachemissrate, "YELLOW"),
            )
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # BRANCH stats #
        try:
            branch = value["PERF_COUNT_HW_BRANCH_INSTRUCTIONS"]
            branchmiss = value["PERF_COUNT_HW_BRANCH_MISSES"]
            branchmissrate = long(branchmiss / float(branch) * 100)
            perfbuf = "%sBrcMiss: %s(%s) / " % (
                perfbuf,
                convSize(branchmiss),
                convColor("%s%%" % branchmissrate, "YELLOW"),
            )
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # CPU stats #
        try:
            perfbuf = "%sClk: %s / " % (
                perfbuf,
                convSize(value["PERF_COUNT_SW_CPU_CLOCK"]),
            )
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # FAULT stats #
        try:
            faultmin = value["PERF_COUNT_SW_PAGE_FAULTS_MIN"]
            faultmaj = value["PERF_COUNT_SW_PAGE_FAULTS_MAJ"]
            perfbuf = "%sMinFlt: %s / MajFlt: %s / " % (
                perfbuf,
                format(faultmin, ","),
                format(faultmaj, ","),
            )
        except SystemExit:
            sys.exit(0)
        except:
            pass

        try:
            if perfbuf:
                perfbuf = "[%s]" % perfbuf[: perfbuf.rfind(" /")]
        except SystemExit:
            sys.exit(0)
        except:
            pass

        return perfbuf

    @staticmethod
    def writeKernelCmd():
        effectiveCmd = []

        if not SysMgr.keventEnable:
            return
        elif not SysMgr.kernelCmd:
            SysMgr.printErr(
                "wrong format for kernel command [NAME:FUNC|ADDR{:ARGS:RET}]"
            )
            sys.exit(-1)
        elif not os.path.isfile(SysMgr.mountPath + "../kprobe_events"):
            SysMgr.printErr(
                "enable CONFIG_KPROBES & CONFIG_KPROBE_EVENTS kernel option"
            )
            sys.exit(-1)

        for cmd in SysMgr.kernelCmd:
            cmdFormat = cmd.split(":")

            # check command format #
            cmdCnt = len(cmdFormat)
            if not (2 <= cmdCnt <= 4):
                SysMgr.printErr(
                    "wrong format for kernel command "
                    "[NAME:FUNC|ADDR{:ARGS:RET}]"
                )
                sys.exit(-1)

            for item in effectiveCmd:
                if cmdFormat[0] == item[0]:
                    SysMgr.printErr(
                        "redundant kernel event name '%s'" % item[0]
                    )
                    sys.exit(-1)

            effectiveCmd.append(cmdFormat)

        # print kprobe event list #
        SysMgr.printInfo(
            "enabled kernel events [ %s ]"
            % ", ".join([":".join(cmd) for cmd in effectiveCmd])
        )

        # apply kprobe events #
        for cmd in effectiveCmd:
            # check redundant event name #
            if SysMgr.userCmd and cmd[0] in [
                ucmd.split(":")[0] for ucmd in SysMgr.userCmd
            ]:
                SysMgr.printErr(
                    "redundant name '%s' for user event and kernel event"
                    % cmd[0]
                )
                sys.exit(-1)

            # make entry commands #
            pCmd = "p:%s_enter %s" % (cmd[0], cmd[1])
            sCmd = ""
            try:
                # parse argument option #
                for rCmd in cmd[2].split("."):
                    # convert ; to : for type definition #
                    rCmd = rCmd.replace(";", ":")

                    # check absolute argument #
                    if not rCmd:
                        pass
                    elif rCmd[0] == "#":
                        sCmd = "%s %s" % (sCmd, rCmd[1:])
                        continue
                    elif len(rCmd.split("/")) == 1:
                        sCmd = "%s %s" % (sCmd, rCmd)
                        continue

                    rVal = rCmd.split("/")
                    if len(rVal) < 2:
                        continue
                    elif len(rVal) > 2:
                        SysMgr.printErr("wrong command '%s'" % rCmd)
                        sys.exit(-1)
                    tVal = rVal[1]

                    # count the number of prefix * #
                    wCnt = 0
                    for idx, ch in enumerate(tVal):
                        if ch != "*":
                            wCnt = idx
                            break

                    # make entry command #
                    tVal = "%s%s%s:%s" % (
                        "+0(" * wCnt,
                        rVal[0],
                        ")" * wCnt,
                        tVal[wCnt:],
                    )

                    # add argument command to entry command #
                    sCmd = "%s %s" % (sCmd, tVal)
            except SystemExit:
                sys.exit(0)
            except:
                pass

            # apply entry command #
            if sCmd != " NONE":
                pCmd = "%s %s" % (pCmd, sCmd)
                if (
                    SysMgr.writeTraceCmd("../kprobe_events", pCmd, append=True)
                    < 0
                ):
                    SysMgr.printErr("wrong command '%s'" % pCmd)
                    sys.exit(-1)

            # make return commands #
            rCmd = "r:%s_exit %s" % (cmd[0], cmd[1])
            sCmd = ""

            try:
                tCmd = cmd[3]

                # check absolute argument #
                if tCmd[0] == "#":
                    sCmd = "%s" % (tCmd[1:])
                else:
                    rVal = tCmd.split("/")
                    if len(rVal) > 2:
                        SysMgr.printErr("wrong command '%s'" % tCmd)
                        sys.exit(-1)
                    tVal = rVal[0]

                    # count the number of prefix * #
                    wCnt = 0
                    for idx, ch in enumerate(tVal):
                        if ch != "*":
                            wCnt = idx
                            break

                    if tCmd != "NONE":
                        # make return command #
                        sCmd = "%s%s%s:%s" % (
                            "+0(" * wCnt,
                            "$retval",
                            ")" * wCnt,
                            tVal[wCnt:],
                        )
                    else:
                        sCmd = "NONE"
            except SystemExit:
                sys.exit(0)
            except:
                pass

            # apply return command #
            if sCmd != "NONE":
                rCmd = "%s %s" % (rCmd, sCmd)
                if (
                    SysMgr.writeTraceCmd("../kprobe_events", rCmd, append=True)
                    < 0
                ):
                    SysMgr.printErr("wrong command '%s'" % rCmd)
                    sys.exit(-1)

        # apply filter #
        if SysMgr.filterGroup:
            cmd = SysMgr.getPidFilter()
            if cmd != "":
                SysMgr.writeTraceCmd("kprobes/filter", cmd)
            else:
                SysMgr.printErr("failed to apply '%s' to kprobe filter" % cmd)
                sys.exit(-1)

        # enable kprobe events #
        if SysMgr.writeTraceCmd("kprobes/enable", "1") < 0:
            SysMgr.printErr("failed to apply '%s' to kprobe events" % cmd)
            sys.exit(-1)

    @staticmethod
    def writeUserCmd():
        effectiveCmd = []

        if not SysMgr.ueventEnable:
            return
        elif not SysMgr.userCmd:
            SysMgr.printErr(
                "wrong format for user command [NAME:FUNC|ADDR:FILE]"
            )
            sys.exit(-1)
        elif not os.path.isfile(SysMgr.mountPath + "../uprobe_events"):
            SysMgr.printErr(
                "enable CONFIG_UPROBES & CONFIG_UPROBE_EVENT kernel option"
            )
            sys.exit(-1)

        kernelCmd = SysMgr.kernelCmd

        for cmd in SysMgr.userCmd:
            addr = None
            cvtCmd = cmd.replace("::", "#")
            cmdFormat = cvtCmd.split(":")
            cmdFormat = [cmd.replace("#", "::") for cmd in cmdFormat]

            if len(cmdFormat) != 3:
                SysMgr.printErr(
                    "wrong format for user command [NAME:FUNC|ADDR:FILE]"
                )
                sys.exit(-1)

            # check redundant event name #
            if kernelCmd and cmd[0] in [
                kcmd.split(":")[0] for kcmd in kernelCmd
            ]:
                SysMgr.printErr(
                    (
                        "redundant event name '%s' "
                        "as user event and kernel event"
                    )
                    % cmd[0]
                )
                sys.exit(-1)

            # check binary file #
            if not os.path.isfile(cmdFormat[2]):
                SysMgr.printErr("failed to find '%s' binary" % cmdFormat[2])
                sys.exit(-1)

            # symbol input #
            objdumpPath = None
            if not cmdFormat[1].startswith("0x"):
                # symbol input with no objdump path #
                if not "OBJDUMP" in SysMgr.environList:
                    # get address of symbol in binary #
                    addr = ElfAnalyzer.getSymOffset(
                        cmdFormat[1], cmdFormat[2], loadAddr=False
                    )
                # symbol input with objdump #
                else:
                    objdumpPath = SysMgr.environList["OBJDUMP"][0]

                    SysMgr.printInfo(
                        "apply '%s' to objdump path" % objdumpPath
                    )

                    if not os.path.isfile(objdumpPath):
                        SysMgr.printErr(
                            "failed to find %s to use objdump" % objdumpPath
                        )
                        sys.exit(-1)

                    # get address of symbol in binary #
                    addr = ElfAnalyzer.getSymOffset(
                        cmdFormat[1], cmdFormat[2], objdumpPath, loadAddr=True
                    )

                if not addr:
                    SysMgr.printErr(
                        "failed to find '%s' in %s"
                        % (cmdFormat[1], cmdFormat[2])
                    )
                    sys.exit(-1)
            # address input #
            else:
                addr = cmdFormat[1]
                try:
                    hex(long(addr, base=16))
                except:
                    SysMgr.printErr("failed to recognize address %s" % addr)
                    sys.exit(-1)

            for item in effectiveCmd:
                if cmdFormat[0] == item[0]:
                    SysMgr.printErr("redundant user event name '%s'" % item[0])
                    sys.exit(-1)

            # convert address #
            if type(addr) is list:
                try:
                    addr = str(hex(addr[0][0])).rstrip("L")
                except:
                    addr = str(addr[0][1])

            effectiveCmd.append([cmdFormat[0], addr, cmdFormat[2]])

        # print uprobe event list #
        SysMgr.printInfo(
            "enabled user events [ %s ]"
            % ", ".join([":".join(cmd) for cmd in effectiveCmd])
        )

        # apply uprobe events #
        for cmd in effectiveCmd:
            # apply entry events #
            pCmd = "p:%s_enter %s:%s" % (cmd[0], cmd[2], cmd[1])
            if SysMgr.writeTraceCmd("../uprobe_events", pCmd, append=True) < 0:
                SysMgr.printErr("wrong command '%s'" % pCmd)
                sys.exit(-1)

            # apply return events #
            rCmd = "r:%s_exit %s:%s" % (cmd[0], cmd[2], cmd[1])
            if SysMgr.writeTraceCmd("../uprobe_events", rCmd, append=True) < 0:
                SysMgr.printErr("wrong command '%s'" % rCmd)
                sys.exit(-1)

        # apply filter #
        if SysMgr.filterGroup:
            cmd = SysMgr.getPidFilter()
            if cmd != "":
                SysMgr.writeTraceCmd("uprobes/filter", cmd)
            else:
                SysMgr.printErr("failed to apply '%s' to uprobe filter" % cmd)
                sys.exit(-1)

        # enable uprobe events #
        if SysMgr.writeTraceCmd("uprobes/enable", "1") < 0:
            SysMgr.printErr("failed to apply '%s' to uprobe events" % cmd)
            sys.exit(-1)

    @staticmethod
    def writeSyscallCmd(enable):
        scmd = ""
        defaultList = [
            "sys_execve",
            "sys_execveat",
            "sys_nice",
            "sys_setpriority",
            "sys_sched_setparam",
            "sys_sched_setscheduler",
            "sys_sched_setattr",
            "sys_bpf",
            "sys_ioprio_set",
        ]

        if SysMgr.isFuncMode() and not SysMgr.heapEnable:
            cmd = "raw_syscalls/sys_enter/enable"
        else:
            cmd = "raw_syscalls/enable"

        # specific syscalls #
        if enable:
            sfilter = ""
            pfilter = SysMgr.getPidFilter()
            if SysMgr.syscallList:
                sfilter = "("
                for val in SysMgr.syscallList:
                    sfilter += " id == %s ||" % val
                sfilter = "%s )" % sfilter[: sfilter.rfind(" ||")]

            if sfilter and pfilter:
                scmd = "(%s && %s)" % (sfilter, pfilter)
            elif sfilter:
                scmd = sfilter
                for item in defaultList:
                    try:
                        scmd = "%s || ( id == %s )" % (
                            scmd,
                            SysMgr.getNrSyscall(item),
                        )
                    except:
                        continue
            elif pfilter:
                scmd = "(%s)" % pfilter
            else:
                pass
        # default syscalls #
        else:
            for item in defaultList:
                try:
                    scmd = "%s || ( id == %s )" % (
                        scmd,
                        SysMgr.getNrSyscall(item),
                    )
                except:
                    continue
            scmd = scmd[scmd.find("(") :]

        SysMgr.writeTraceCmd("raw_syscalls/filter", scmd)
        ret = SysMgr.writeTraceCmd(cmd, "1")
        if ret < 0:
            SysMgr.printWarn("failed to enable syscall events", True)

    @staticmethod
    def printSigError(tid, signal, warn=True):
        if warn:
            printFunc = SysMgr.printWarn
        else:
            printFunc = SysMgr.printErr

        # get comm #
        comm = SysMgr.getComm(tid)

        # get signal name #
        try:
            signal = ConfigMgr.SIG_LIST[signal]
        except:
            pass
        if "." in signal:
            signal = signal.split(".", 2)[1]

        printFunc(
            "failed to send %s to %s(%s)" % (signal, comm, tid), reason=True
        )

    @staticmethod
    def getLine():
        try:
            inspect = SysMgr.getPkg("inspect")
            lines = ""
            debug = "DEBUG" in SysMgr.environList
            if sys.version_info >= (3, 5, 0):
                # filename, lineno, function, code_context #
                for fb in reversed(inspect.trace()):
                    if debug:
                        print(
                            "[DEBUG] %s() at %s in %s"
                            % (fb.function, fb.lineno, fb.filename)
                        )
                    lines += "%s<" % fb.lineno
            else:
                # obj, filename, lineno, function, code_context #
                for fb in reversed(inspect.trace()):
                    if debug:
                        print(
                            "[DEBUG] %s() at %s in %s" % (fb[3], fb[2], fb[1])
                        )
                    lines += "%s<" % fb[2]
            return lines.rstrip("<")
        except:
            return None

    @staticmethod
    def getErrMsg():
        et, err, to = sys.exc_info()
        lineno = SysMgr.getLine()
        if lineno:
            linestr = " at %s" % lineno
        else:
            linestr = ""

        # error #
        try:
            if not err.args or err.args[0] == 0:
                return sys.exc_info()[0].__name__ + linestr
        except SystemExit:
            sys.exit(0)
        except:
            if to:
                return "N/A%s" % linestr
            else:
                return "N/A"

        # error code #
        try:
            code = "%s-" % errno.errorcode[err.args[0]]
        except SystemExit:
            sys.exit(0)
        except:
            code = ""

        errstr = " ".join(list(map(str, err.args)))
        return "%s%s%s" % (code, errstr, linestr)

    def disableAllEvents(self):
        for event in list(self.cmdList):
            self.cmdList[event] = False

    @staticmethod
    def writeCustomCmd():
        effectiveCmd = []

        if not SysMgr.customCmd:
            return

        if not SysMgr.filterGroup:
            pidFilter = "common_pid != 0"
        else:
            pidFilter = SysMgr.getPidFilter()

        for cmd in SysMgr.customCmd:
            cmdFormat = cmd.split(":")

            if cmdFormat[0] == "":
                SysMgr.printErr("wrong event '%s'" % cmdFormat[0])
                sys.exit(-1)

            # check filter #
            if len(cmdFormat) == 1:
                origFilter = ""
                cmdFormat.append(pidFilter)
            else:
                origFilter = cmdFormat[1]
                cmdFormat[1] = pidFilter + " && " + cmdFormat[1]

            # check effective event #
            if SysMgr.writeTraceCmd(cmdFormat[0] + "/enable", "0") < 0:
                SysMgr.printErr("wrong event '%s'" % cmdFormat[0])
                sys.exit(-1)

            # check and enable effective filter #
            if (
                len(cmdFormat) > 1
                and SysMgr.writeTraceCmd(
                    cmdFormat[0] + "/filter", cmdFormat[1]
                )
                < 0
            ):
                SysMgr.printErr(
                    "wrong filter '%s' for '%s' event"
                    % (origFilter, cmdFormat[0])
                )
                sys.exit(-1)

            # check and enable effective event #
            if SysMgr.writeTraceCmd(cmdFormat[0] + "/enable", "1") < 0:
                SysMgr.printErr("wrong event '%s'" % cmdFormat[0])
                sys.exit(-1)
            else:
                effectiveCmd.append(cmdFormat[0])

        if effectiveCmd:
            SysMgr.printInfo(
                "enabled custom events [ %s ]" % ", ".join(effectiveCmd)
            )

    @staticmethod
    def printAnalOption():
        def _setOpt(items, val, name):
            if val:
                items["enable"] += name
            else:
                items["disable"] += name

        if SysMgr.outputFile:
            return

        items = {"enable": "", "disable": ""}

        if not SysMgr.isRecordMode() and not SysMgr.isTopMode():
            # common options #
            items["enable"] += SysMgr.arch.upper() + " "
            _setOpt(items, SysMgr.warnEnable, "WARN ")

        # function mode #
        if SysMgr.isFuncMode():
            _setOpt(items, SysMgr.heapEnable, "HEAP ")
            _setOpt(items, SysMgr.userEnable, "USER ")
        # thread mode #
        else:
            _setOpt(items, SysMgr.depEnable, "DEP ")
            _setOpt(items, SysMgr.fsEnable, "FS ")
            _setOpt(items, SysMgr.intervalEnable, "INTERVAL ")
            _setOpt(items, SysMgr.irqEnable, "IRQ ")
            _setOpt(items, SysMgr.keventEnable, "KEVT ")
            _setOpt(items, SysMgr.latEnable, "LATENCY ")
            _setOpt(items, SysMgr.networkEnable, "NET ")
            _setOpt(items, SysMgr.perCoreList, "PERCORE ")
            _setOpt(items, SysMgr.powerEnable, "POWER ")
            _setOpt(items, SysMgr.preemptGroup, "PREEMPT ")
            _setOpt(items, SysMgr.ueventEnable, "UEVT ")
            _setOpt(items, SysMgr.wqEnable, "WQ ")
            _setOpt(items, not SysMgr.latEnable, "SCHEDBLK ")

        if SysMgr.customCmd:
            SysMgr.printInfo(
                "selected custom events [ %s ]" % ", ".join(SysMgr.customCmd)
            )

        # common options #
        _setOpt(items, SysMgr.blockEnable, "BLOCK ")
        _setOpt(items, SysMgr.compressEnable, "COMP ")
        _setOpt(items, SysMgr.countEnable, "CUT ")
        _setOpt(items, SysMgr.cpuEnable, "CPU ")
        _setOpt(items, SysMgr.disableAll, "DISABLE ")
        _setOpt(items, SysMgr.groupProcEnable, "PGRP ")
        _setOpt(items, SysMgr.lockEnable, "LOCK ")
        _setOpt(items, SysMgr.memEnable, "MEM ")
        _setOpt(items, SysMgr.printEnable, "PRINT ")
        _setOpt(items, SysMgr.showAll, "ALL ")
        _setOpt(items, SysMgr.sysEnable, "SYSCALL ")

        enableStat = items["enable"]
        disableStat = items["disable"]

        # print options #
        if enableStat:
            SysMgr.printInfo("enabled analysis options [ %s]" % enableStat)

        if disableStat:
            SysMgr.printWarn("disabled analysis options [ %s]" % disableStat)

    @staticmethod
    def getUdsList(addrList):
        def _getStats(addrList):
            retList = []
            for item in addrList:
                if item in SysMgr.udsListCache:
                    retList.append(SysMgr.udsListCache[item])
            return retList

        if SysMgr.udsListCache:
            return _getStats(addrList)

        inodeIdx = ConfigMgr.UDS_ATTR.index("Inode")
        pathIdx = ConfigMgr.UDS_ATTR.index("Path")

        udsBuf = []
        udsPath = "%s/net/unix" % SysMgr.procPath

        # init UDS stats #
        SysMgr.nrUDSSock = 0

        # make dictionary #
        try:
            with open(udsPath, "r") as fd:
                udsBuf = fd.read().split("\n")
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenWarn(udsPath)
            return udsBuf

        # remove title #
        udsBuf.pop(0)

        for line in udsBuf:
            try:
                if not line:
                    continue

                # increase UDS socket number #
                SysMgr.nrUDSSock += 1

                uds = line.split()

                item = "UDS>%s" % uds[pathIdx]

                SysMgr.udsListCache[uds[inodeIdx]] = item
            except SystemExit:
                sys.exit(0)
            except:
                pass

        return _getStats(addrList)

    @staticmethod
    def getUdpList(addrList):
        def _getStats(addrList):
            retList = []
            for item in addrList:
                if item in SysMgr.udpListCache:
                    retList.append(SysMgr.udpListCache[item])
            return retList

        if SysMgr.udpListCache:
            return _getStats(addrList)

        inodeIdx = ConfigMgr.PROTOCOL_ATTR.index("inode")
        laddrIdx = ConfigMgr.PROTOCOL_ATTR.index("local_address")

        udpBuf = []
        udpFileList = [
            "%s/net/udp" % SysMgr.procPath,
            "%s/net/udp6" % SysMgr.procPath,
        ]

        # init UDP stats #
        SysMgr.nrUDPSock = 0

        for udpPath in udpFileList:
            try:
                with open(udpPath, "r") as fd:
                    udpBuf = fd.read().split("\n")
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenWarn(udpPath)
                continue

            # remove title #
            udpBuf.pop(0)

            for line in udpBuf:
                try:
                    if not line:
                        continue

                    # increase UCP socket number #
                    SysMgr.nrUDPSock += 1

                    udp = line.split()

                    # convert local address #
                    lip, lport = udp[laddrIdx].split(":")
                    lip = SysMgr.convCIDR(lip)
                    item = "UDP>%s:%s" % (lip, long(lport, base=16))

                    # convert remote address #
                    rip, rport = udp[laddrIdx + 1].split(":")

                    # append remote address #
                    try:
                        rport = long(rport, 16)
                        if long(rip, 16) > 0 and rport > 0:
                            rip = SysMgr.convCIDR(rip)
                            item = "%s->%s:%s" % (item, rip, rport)
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass

                    # cache string #
                    SysMgr.udpListCache[udp[inodeIdx]] = item
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printWarn(
                        "failed to parse UDP data '%s'" % line, reason=True
                    )

        return _getStats(addrList)

    @staticmethod
    def getTcpList(addrList):
        def _getStats(addrList):
            retList = []
            for item in addrList:
                if item in SysMgr.tcpListCache:
                    retList.append(SysMgr.tcpListCache[item])
            return retList

        if SysMgr.tcpListCache:
            return _getStats(addrList)

        stIdx = ConfigMgr.PROTOCOL_ATTR.index("st")
        inodeIdx = ConfigMgr.PROTOCOL_ATTR.index("inode")
        laddrIdx = ConfigMgr.PROTOCOL_ATTR.index("local_address")
        estIdx = ConfigMgr.TCP_STAT.index("ESTABLISHED")

        tcpBuf = []
        tcpFileList = [
            "%s/net/tcp" % SysMgr.procPath,
            "%s/net/tcp6" % SysMgr.procPath,
        ]

        # init TCP stats #
        SysMgr.nrTCPSock = 0
        SysMgr.nrTCPConn = 0

        # make dictionary #
        for tcpPath in tcpFileList:
            try:
                with open(tcpPath, "r") as fd:
                    tcpBuf = fd.read().split("\n")
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenWarn(tcpPath)
                continue

            # remove title #
            tcpBuf.pop(0)

            for line in tcpBuf:
                try:
                    if not line:
                        continue

                    # increase TCP socket number #
                    SysMgr.nrTCPSock += 1

                    tcp = line.split()

                    # convert local address #
                    lip, lport = tcp[laddrIdx].split(":")
                    lip = SysMgr.convCIDR(lip)
                    item = "TCP>%s:%s" % (lip, long(lport, base=16))

                    # convert remote address #
                    rip, rport = tcp[laddrIdx + 1].split(":")

                    # append remote address #
                    try:
                        rport = long(rport, 16)
                        if rport > 0 and long(rip, 16) > 0:
                            rip = SysMgr.convCIDR(rip)
                            item = "%s->%s:%s" % (item, rip, rport)
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass

                    # define status #
                    try:
                        tcpStat = long(tcp[stIdx], 16)

                        # increase established TCP socket number #
                        if tcpStat == estIdx:
                            SysMgr.nrTCPConn += 1

                        stat = "/%s" % ConfigMgr.TCP_STAT[tcpStat]
                    except SystemExit:
                        sys.exit(0)
                    except:
                        stat = ""

                    # append status #
                    item += stat

                    # cache string #
                    SysMgr.tcpListCache[tcp[inodeIdx]] = item
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printWarn(
                        "failed to parse TCP data '%s'" % line, reason=True
                    )

        return _getStats(addrList)

    @staticmethod
    def printProfileCmd():
        for idx, val in SysMgr.rcmdList.items():
            if not val:
                continue

            cmds = []
            for item in val:
                cmds.append(":".join(item))
            SysMgr.printInfo(
                "user custom commands on %s [ %s ]" % (idx, ", ".join(cmds))
            )

    @staticmethod
    def getVDSO(elf=True, debug=False):
        # get address of vdso object #
        addr = SysMgr.getauxval("AT_SYSINFO_EHDR")
        if not addr:
            return None

        # create a memory file #
        fd = MemoryFile(addr, name="vdso")
        if not fd:
            SysMgr.printErr("failed to create memory file for vdso object")
            return None
        elif not elf:
            return fd

        # return vDSO #
        obj = ElfAnalyzer(path="vdso", fd=fd, debug=debug)
        if obj:
            ElfAnalyzer.cachedFiles["vdso"] = obj

        return obj

    @staticmethod
    def getauxval(attype):
        if not SysMgr.isLinux:
            return None

        try:
            nrType = ConfigMgr.AT_TYPE[attype]
        except:
            SysMgr.printErr("failed to get entry type %s" % attype, True)
            return

        # load libc #
        if not SysMgr.loadLibcObj():
            return

        # declare syscalls #
        try:
            SysMgr.libcObj.getauxval.restype = c_ulong
            SysMgr.libcObj.getauxval.argtypes = [c_ulong]
        except:
            SysMgr.printErr("failed to find getauxval in libc")
            return None

        return SysMgr.libcObj.getauxval(c_ulong(nrType))

    @staticmethod
    def printProfileOption():
        def _setOpt(items, val, name):
            if val:
                items["enable"] += name
            else:
                items["disable"] += name

        items = {"enable": "", "disable": ""}

        # common options #
        items["enable"] += SysMgr.arch.upper() + " "

        _setOpt(items, SysMgr.cgroupEnable, "CGROUP ")
        _setOpt(items, SysMgr.cpuEnable, "CPU ")
        _setOpt(items, SysMgr.encodeEnable, "ENCODE ")
        _setOpt(items, SysMgr.pipeEnable, "PIPE ")
        _setOpt(items, SysMgr.printEnable, "PRINT ")
        _setOpt(items, SysMgr.warnEnable, "WARN ")

        # check current mode #
        if SysMgr.isTopMode():
            SysMgr.printInfo("<TOP MODE>")

            if SysMgr.fileTopEnable:
                items["enable"] += "FILE "
            else:
                if SysMgr.processEnable:
                    items["enable"] += "PROCESS "
                else:
                    items["enable"] += "THREAD "

                _setOpt(items, SysMgr.compressEnable, "COMP ")
                _setOpt(items, SysMgr.affinityEnable, "AFNT ")
                _setOpt(items, SysMgr.barGraphEnable, "BAR ")
                _setOpt(items, SysMgr.blockEnable, "BLOCK ")
                _setOpt(items, SysMgr.cmdlineEnable, "CMD ")
                _setOpt(items, SysMgr.delayEnable, "DELAY ")
                _setOpt(items, SysMgr.diskEnable, "DISK ")
                _setOpt(items, SysMgr.dltEnable, "DLT ")
                _setOpt(items, SysMgr.dwarfEnable, "DWARF ")
                _setOpt(items, SysMgr.eventHandleEnable, "EVENT ")
                _setOpt(items, SysMgr.floatEnable, "FLOAT ")
                _setOpt(items, SysMgr.gpuEnable, "GPU ")
                _setOpt(items, SysMgr.groupProcEnable, "PGRP ")
                _setOpt(items, SysMgr.irqEnable, "IRQ ")
                _setOpt(items, SysMgr.journalEnable, "JRL ")
                _setOpt(items, SysMgr.kmsgEnable, "KMSG ")
                _setOpt(items, SysMgr.memEnable, "MEM ")
                _setOpt(items, SysMgr.minStatEnable, "MIN ")
                _setOpt(items, SysMgr.networkEnable, "NET")
                _setOpt(items, SysMgr.nsEnable, "NS ")
                _setOpt(items, SysMgr.oomEnable, "OOM ")
                _setOpt(items, SysMgr.perfEnable, "PERF ")
                _setOpt(items, SysMgr.perfGroupEnable, "PERFPROC ")
                _setOpt(items, SysMgr.pssEnable, "PSS ")
                _setOpt(items, SysMgr.reportEnable, "REPORT ")
                _setOpt(items, SysMgr.reportFileEnable, "RFILE ")
                _setOpt(items, SysMgr.schedEnable, "SCHED ")
                _setOpt(items, SysMgr.sigHandlerEnable, "SIG ")
                _setOpt(items, SysMgr.stackEnable, "STACK ")
                _setOpt(items, SysMgr.syslogEnable, "SYSLOG ")
                _setOpt(items, SysMgr.thresholdEnable, "THRESHOLD ")
                _setOpt(items, SysMgr.totalEnable, "TOTAL ")
                _setOpt(items, SysMgr.ussEnable, "USS ")
                _setOpt(items, SysMgr.wchanEnable, "WCHAN ")
                _setOpt(items, SysMgr.wfcEnable, "WFC ")
                _setOpt(items, SysMgr.wssEnable, "WSS ")

        elif SysMgr.isFuncMode():
            SysMgr.printInfo("<FUNCTION MODE>")

            _setOpt(items, SysMgr.getCompressFlag(), "COMP ")

            if SysMgr.graphEnable:
                items["enable"] += "GRAPH "
            else:
                items["disable"] += "GRAPH "

                _setOpt(items, SysMgr.blockEnable, "BLOCK ")
                _setOpt(items, SysMgr.disableAll, "DISABLE ")
                _setOpt(items, SysMgr.heapEnable, "HEAP ")
                _setOpt(items, SysMgr.lockEnable, "LOCK ")
                _setOpt(items, SysMgr.memEnable, "MEM ")
                _setOpt(items, SysMgr.sysEnable, "SYSCALL ")
                _setOpt(items, SysMgr.userEnable, "USER ")

        elif SysMgr.isFileMode():
            SysMgr.printInfo("<FILE MODE>")

        elif SysMgr.isSystemMode():
            SysMgr.printInfo("<SYSTEM MODE>")

        else:
            SysMgr.printInfo("<THREAD MODE>")
            SysMgr.threadEnable = True

            _setOpt(items, SysMgr.binderEnable, "BINDER ")
            _setOpt(items, SysMgr.blockEnable, "BLOCK ")
            _setOpt(items, SysMgr.bufferLossEnable, "BUFLOSS ")
            _setOpt(items, SysMgr.depEnable, "DEP ")
            _setOpt(items, SysMgr.disableAll, "DISABLE ")
            _setOpt(items, SysMgr.diskEnable, "DISK ")
            _setOpt(items, SysMgr.fsEnable, "FS ")
            _setOpt(items, SysMgr.i2cEnable, "I2C ")
            _setOpt(items, SysMgr.iouringEnable, "IOURING ")
            _setOpt(items, SysMgr.kvmEnable, "KVM ")
            _setOpt(items, SysMgr.irqEnable, "IRQ ")
            _setOpt(items, SysMgr.keventEnable, "KEVT ")
            _setOpt(items, SysMgr.latEnable, "LATENCY ")
            _setOpt(items, SysMgr.lockEnable, "LOCK ")
            _setOpt(items, SysMgr.memEnable, "MEM ")
            _setOpt(items, SysMgr.networkEnable, "NET ")
            _setOpt(items, SysMgr.powerEnable, "POWER ")
            _setOpt(items, SysMgr.resetEnable, "RESET ")
            _setOpt(items, SysMgr.sysEnable, "SYSCALL ")
            _setOpt(items, SysMgr.ueventEnable, "UEVT ")
            _setOpt(items, SysMgr.wqEnable, "WQ ")
            _setOpt(items, SysMgr.getCompressFlag(), "COMP ")

        enableStat = items["enable"]
        disableStat = items["disable"]

        # print options #
        if enableStat:
            SysMgr.printInfo("enabled runtime options [ %s]" % enableStat)

        if disableStat:
            SysMgr.printWarn("disabled runtime options [ %s]" % disableStat)

    @staticmethod
    def isThreadMode():
        return SysMgr.threadEnable

    @staticmethod
    def isFuncMode():
        return SysMgr.functionEnable

    @staticmethod
    def isFileMode():
        return SysMgr.fileEnable

    @staticmethod
    def isSystemMode():
        return SysMgr.systemEnable

    @staticmethod
    def defaultHandler(signum, frame):
        return

    @staticmethod
    def chldHandler(signum, frame):
        try:
            os.waitpid(-1, os.WNOHANG)
        except:
            pass

    @staticmethod
    def fgHandler(signum, frame):
        SysMgr.bgStatus = False

    @staticmethod
    def bgHandler(signum, frame):
        SysMgr.bgStatus = True

        if signum == signal.SIGTSTP:
            os.kill(SysMgr.pid, signal.SIGSTOP)
        elif signum == signal.SIGTTIN:
            sys.stdin.close()
            sys.stdin = None

    @staticmethod
    def winchHandler(signum, frame):
        SysMgr.getTty(update=True)

    @staticmethod
    def stopHandler(signum=None, frame=None):
        if SysMgr.exitFlag:
            os._exit(0)

        # mask signal #
        if signum:
            signal.signal(signum, signal.SIG_IGN)

        # write user command #
        SysMgr.runProfCmd("STOP")

        # handle signal #
        if SysMgr.jsonEnable:
            sys.exit(0)

        elif SysMgr.checkMode("filerec") and not SysMgr.intervalEnable:
            sys.exit(0)

        elif SysMgr.isFileMode() or SysMgr.isSystemMode():
            SysMgr.condExit = True

        elif SysMgr.isTopMode() or SysMgr.isTraceMode():
            # skip summary for Debugger #
            if Debugger.dbgInstance:
                pass
            elif SysMgr.outPath and not "NOSUMMARY" in SysMgr.environList:
                # update exit status #
                SysMgr.inExit = True

                SysMgr.printStat("start reporting... [ STOP(Ctrl+\) ]")

                # reload data written to file #
                if SysMgr.pipeEnable:
                    SysMgr.reloadFileBuffer()

                SysMgr.printLogo(absolute=True, big=True)

                # save system info #
                SysMgr.saveSysStats()
                SysMgr.printInfoBuffer()

                # submit summary report and details #
                if "NOINTSUMMARY" in SysMgr.environList:
                    SysMgr.printProcBuffer()
                else:
                    TaskAnalyzer.printIntervalUsage()

                if os.path.exists(SysMgr.inputFile):
                    # get output size #
                    fsize = UtilMgr.getFileSizeStr(SysMgr.inputFile)

                    SysMgr.printInfo(
                        "saved the results based monitoring into "
                        "'%s'%s successfully" % (SysMgr.inputFile, fsize)
                    )

            # broadcast signal to childs and close all FDs #
            SysMgr.releaseResource(signal.SIGINT)

            # update exit status #
            SysMgr.inExit = False

            # unmask signal #
            if signum:
                signal.signal(signum, SysMgr.stopHandler)

            # quit to avoid termination #
            if not SysMgr.termFlag:
                SysMgr.progressCnt = 0
                return

            """
            # enable for cProfile #
            sys.settrace
            sys.exit(0)
            """

            # remove stopHandler in exit list to prevent recursive calls #
            newExitList = []
            for idx, item in enumerate(SysMgr.exitFuncList):
                if item[0] != SysMgr.stopHandler:
                    newExitList.append(item)
            SysMgr.exitFuncList = newExitList

            # call exit handlers #
            SysMgr.doExit()

            # do terminate #
            os._exit(0)

        else:
            # write trace message #
            SysMgr.writeEvent("EVENT_STOP", False)

            if signum:
                signal.signal(signal.SIGINT, signal.SIG_DFL)

            SysMgr.stopRecording()

        # update record stats #
        SysMgr.recordStatus = False
        SysMgr.repeatCount = 0

        SysMgr.printStat("ready to save and analyze... [ STOP(Ctrl+c) ]")

        # unmask signal #
        if signum:
            signal.signal(signum, SysMgr.stopHandler)

        if not "ISMAIN" in os.environ:
            sys.exit(0)

        raise Exception("stop signal")

    @staticmethod
    def closePrintFd():
        try:
            SysMgr.printFd.close()
        except SystemExit:
            sys.exit(0)
        except:
            pass
        finally:
            SysMgr.printFd = None

    @staticmethod
    def newHandler(signum=None, frame=None):
        # check force exit condition #
        if SysMgr.inExit:
            SysMgr.releaseResource()
            os._exit(0)

        SysMgr.condExit = False

        if SysMgr.isFileMode():
            SysMgr.printStat("saved file usage successfully")
        elif SysMgr.isSystemMode():
            pass
        elif SysMgr.isTopMode():
            # reset WSS #
            if SysMgr.wssEnable:
                SysMgr.initWssEnable = True
                SysMgr.printInfo("initialize WSS")

            # check silent mode #
            if not SysMgr.outPath:
                return

            # masking signal #
            if signum:
                signal.signal(signum, signal.SIG_IGN)

            # reload data written to file #
            if SysMgr.pipeEnable:
                SysMgr.reloadFileBuffer()

            # create a new process #
            pid = SysMgr.createProcess()
            if pid > 0:
                # clear buffer as parent #
                SysMgr.procBufferSize = 0
                SysMgr.procBuffer = []

                # close an output file to sync #
                SysMgr.closePrintFd()

                # enable signal again #
                if signum:
                    signal.signal(signum, SysMgr.newHandler)

                return True

            # change priority #
            SysMgr.setLowPriority(True)

            SysMgr.printLogo(absolute=True, big=True)

            # save system info #
            SysMgr.saveSysStats()
            SysMgr.printInfoBuffer()

            # submit summarized report and details #
            TaskAnalyzer.printIntervalUsage()

            # print output info #
            fsize = UtilMgr.getFileSizeStr(SysMgr.inputFile)

            SysMgr.printInfo(
                "saved the results based monitoring into "
                "'%s'%s successfully" % (SysMgr.inputFile, fsize)
            )

            sys.exit(0)
        elif SysMgr.resetEnable:
            SysMgr.writeEvent("EVENT_START")
        else:
            SysMgr.writeEvent("EVENT_MARK")

    @staticmethod
    def alarmExitHandler(signum, frame):
        SysMgr.printWarn("terminated by timer\n", True)
        SysMgr.exitHandler(signum, frame)

    @staticmethod
    def exitHandler(signum, frame):
        if SysMgr.exitFlag or SysMgr.checkMode("report"):
            os._exit(0)

        # block signals and disable alarm for stable termination #
        SysMgr.setIgnoreSignal()
        signal.alarm(0)
        SysMgr.condExit = True

        SysMgr.printWarn("terminated by user\n")

        sys.exit(0)

    @staticmethod
    def faultHandler(signum, frame):
        """
        SysMgr.releaseResource()
        sys.stdout.write('terminated by SEGFAULT signal\n')
        """
        os._exit(0)

    @staticmethod
    def timerHandler(signum, frame):
        raise Exception("timer expired")

    @staticmethod
    def alarmHandler(signum, frame):
        # check exit condition #
        if SysMgr.repeatCount <= SysMgr.progressCnt and SysMgr.termFlag:
            UtilMgr.deleteProgress()
            SysMgr.printWarn("terminated by timer\n", True)
            sys.exit(0)

        # print progress #
        if not SysMgr.isRecordMode() and SysMgr.repeatCount > 0:
            UtilMgr.printProgress(SysMgr.progressCnt, SysMgr.repeatCount)

        # update count #
        SysMgr.progressCnt += 1
        progressCnt = SysMgr.progressCnt
        repeatInterval = SysMgr.repeatInterval
        repeatCount = SysMgr.repeatCount

        # disable alarm handler #
        signal.signal(signal.SIGALRM, SysMgr.defaultHandler)

        if SysMgr.pipeEnable:
            if repeatCount == progressCnt:
                # stop recording #
                SysMgr.stopRecording()
            signal.alarm(repeatInterval)
        elif SysMgr.outputFile:
            if repeatCount == 1 and SysMgr.termFlag:
                output = SysMgr.outputFile
            else:
                output = "%s_%s" % (SysMgr.outputFile, SysMgr.getRuntime())

            # stop recording #
            SysMgr.stopRecording()

            # save system info #
            SysMgr.saveSysStats()

            # read trace data #
            try:
                rpath = os.path.join(SysMgr.mountPath, "../trace")
                if sys.version_info >= (3, 0, 0):
                    with open(rpath, "r", encoding="latin-1") as fr:
                        lines = fr.readlines()
                else:
                    with open(rpath, "r") as fr:
                        lines = fr.readlines()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenErr(rpath)
                sys.exit(-1)

            # write trace data #
            try:
                SysMgr.saveTraceData(lines, output)
                SysMgr.clearInfoBuffer()
            except:
                sys.exit(-1)
        else:
            SysMgr.printWarn(
                "failed to save data because the path is not set", True
            )

        # set alarm again #
        signal.signal(signal.SIGALRM, SysMgr.alarmHandler)

    @staticmethod
    def isTermSignal(sig):
        if sig in (signal.SIGKILL, signal.SIGSEGV, signal.SIGABRT):
            return True
        else:
            return False

    @staticmethod
    def getCompressFlag():
        # compress data by default #
        disabledOptions = SysMgr.getOption("d")
        if disabledOptions and "C" in disabledOptions:
            ret = False
        else:
            ret = True
        return ret

    @staticmethod
    def saveTraceData(lines, outputFile=None):
        if not outputFile:
            outputFile = SysMgr.outputFile
        outputFile = os.path.realpath(outputFile)

        # backup file already exists #
        SysMgr.backupFile(outputFile)

        # compress by gzip #
        if SysMgr.isRecordMode() and SysMgr.getCompressFlag():
            compressor = SysMgr.getPkg("gzip", False)
        else:
            compressor = None

        size = 0
        for line in lines:
            size += len(line)

        try:
            # strip trace data #
            traceData = "\n".join(lines)
            magicPos = traceData.rfind(SysMgr.magicStr)
            if magicPos > 0:
                traceData = traceData[magicPos:]

            # encoding data #
            encodedInfoData = SysMgr.systemInfoBuffer.encode("latin-1")
            encodedTraceData = traceData.encode("latin-1")
            del traceData
            totalSize = len(encodedInfoData) + len(encodedTraceData)

            SysMgr.printInfo(
                "wait for writing data to '%s' [%s]"
                % (outputFile, UtilMgr.convSize2Unit(totalSize))
            )

            f = open(outputFile, "wb")
            os.chmod(outputFile, 0o777)
            if compressor:
                f = compressor.GzipFile(fileobj=f)

            # write system info #
            if SysMgr.systemInfoBuffer:
                magicStr = "%s\n" % SysMgr.magicStr
                magicStr = magicStr.encode("latin-1")

                # write start mark #
                f.write(magicStr)

                # write info data #
                f.write(encodedInfoData)

                # write end mark #
                f.write(magicStr)

            # write trace info and close file #
            f.write(encodedTraceData)
            f.close()

            # get output size #
            fsize = UtilMgr.getFileSizeStr(outputFile)

            SysMgr.printInfo(
                "finish saving trace data into '%s'%s successfully"
                % (outputFile, fsize)
            )
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to write trace data to '%s'" % outputFile, True
            )

    @staticmethod
    def runProfCmd(time):
        if not SysMgr.isLinux:
            return
        elif SysMgr.rcmdList == {}:
            return

        for cmd in SysMgr.rcmdList[time.upper()]:
            if len(cmd) == 1:
                if cmd[0].endswith("&"):
                    command = cmd[0].rstrip("& ")
                    wait = False
                else:
                    command = cmd[0]
                    wait = True

                # execute a command using a new process #
                SysMgr.execBgCmd(command, mute=False, wait=wait)
                continue
            elif len(cmd) != 2:
                continue

            try:
                path, val = cmd

                with open(path, "w") as fd:
                    fd.write(val)
                    SysMgr.printInfo(
                        "applied command '%s' to %s successfully" % (val, path)
                    )
            except:
                SysMgr.printWarn(
                    "failed to apply command '%s' to %s" % (val, path)
                )

    @staticmethod
    def readFile(path):
        try:
            with open(path, "r") as fd:
                return fd.read().strip()
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to read '%s'" % path, True)
            return None

    @staticmethod
    def writeFile(path, val):
        try:
            fd = open(path, "w")

            if type(val) is list:
                for item in val:
                    if not item:
                        continue
                    fd.seek(0)
                    fd.write(item)
            else:
                fd.write(val)

            return True
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to write '%s' to '%s'" % (path, val), True)
            return False

    @staticmethod
    def readTraceFile(path):
        # open for applying command #
        try:
            target = "%s%s" % (SysMgr.mountPath, path)
            with open(target, "r") as fd:
                return fd.read()[:-1]
        except:
            SysMgr.printErr("failed to read data from %s\n" % target)
            return None

    @staticmethod
    def procReadline(path):
        target = "%s/%s" % (SysMgr.procPath, path)
        with open(target, "r") as fd:
            return fd.readline()

    @staticmethod
    def procReadlines(path):
        target = "%s/%s" % (SysMgr.procPath, path)
        with open(target, "r") as fd:
            return fd.readlines()

    @staticmethod
    def getDirSize(path):
        # get target dir info #
        dirInfo = SysMgr.printDirs(path=path, retVal=True)
        if not dirInfo:
            return 0

        # get current size #
        try:
            item = next(iter(dirInfo))
            if not "size" in dirInfo[item]:
                return 0

            curSize = dirInfo[item]["size"]
            curSize = UtilMgr.convUnit2Size(curSize)
            return curSize
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to get current dir info", True)
            return None

    @staticmethod
    def freeReportDir():
        # check limit size #
        if not SysMgr.limitRepDirSize:
            return 0

        # get output dir #
        if SysMgr.outPath == SysMgr.nullPath:
            targetDir = SysMgr.tmpPath
        elif os.path.isdir(SysMgr.outPath):
            targetDir = SysMgr.outPath
        else:
            targetDir = os.path.dirname(SysMgr.outPath)

        # get total size of the directory #
        curSize = SysMgr.getDirSize(targetDir)
        if not curSize:
            return 0

        # get free-up size #
        try:
            diff = SysMgr.limitRepDirSize - curSize
            if diff >= 0:
                return 0

            needSize = abs(diff)
            rmSize = 0
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to get free-up size of target dir", True)
            return 0

        # get the file list sorted by name in the output dir #
        flist = sorted(
            filter(
                lambda x: os.path.isfile(os.path.join(targetDir, x)),
                os.listdir(targetDir),
            )
        )

        # check remove variable #
        if "REMOVEOTHERS" in SysMgr.environList:
            removeOthers = True
        else:
            removeOthers = False

        # remove report files #
        for fname in flist:
            m = re.match(r"^guider_(?P<run>[0-9]+)_*", fname)
            if not m:
                if not removeOthers:
                    continue

            fpath = os.path.join(targetDir, fname)

            # get file size #
            size = UtilMgr.getFileSize(fpath, False)

            msg = "'%s' [%s] to free up space of the report directory [%s]" % (
                fpath,
                UtilMgr.convSize2Unit(size),
                UtilMgr.convSize2Unit(curSize),
            )

            # remove the file #
            try:
                os.remove(fpath)

                SysMgr.printWarn("removed %s" % msg, True)

                rmSize += size
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("failed to %s" % msg, True)

            if rmSize >= needSize:
                break

        # print freed up space #
        if rmSize:
            curSize = SysMgr.getDirSize(targetDir)

            SysMgr.printInfo(
                (
                    "removed files with a total size of [%s] "
                    "to free up space of the report directory [%s]"
                )
                % (
                    UtilMgr.convSize2Unit(rmSize),
                    UtilMgr.convSize2Unit(curSize),
                )
            )

        return rmSize

    @staticmethod
    def freeDirs():
        for path, limitSize in SysMgr.limitDirList.items():
            # get total size of the directory #
            curSize = SysMgr.getDirSize(path)
            if not curSize:
                continue

            # get free-up size #
            try:
                diff = limitSize - curSize
                if diff >= 0:
                    continue

                needSize = abs(diff)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "failed to get free-up size of target dir", True
                )
                continue

            # TODO: free up directory size by removing files #

    @staticmethod
    def writeTraceCmd(path, val, append=False):
        # set open permission #
        if append:
            perm = "a+"
        else:
            perm = "w"

        # record command to file #
        if SysMgr.cmdEnable:
            if not SysMgr.cmdFd:
                try:
                    SysMgr.cmdFd = open(SysMgr.cmdEnable, perm)
                    SysMgr.cmdFd.write(
                        "mount -t debugfs nodev %s 2>%s\n"
                        % (SysMgr.debugfsPath, SysMgr.nullPath)
                    )
                    SysMgr.cmdFd.write(
                        'echo "\n[Info] start recording... '
                        '[ STOP(Ctrl+c) ]\n"\n'
                    )
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printOpenErr(SysMgr.cmdEnable)
                    return -1

            if SysMgr.cmdFd:
                try:
                    cmd = 'echo "%s" > %s%s 2>%s\n' % (
                        str(val),
                        SysMgr.mountPath,
                        path,
                        SysMgr.nullPath,
                    )
                    SysMgr.cmdFd.write(cmd)
                    SysMgr.cmdFd.flush()
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr("failed to write command", True)
                    return -1

        # open node #
        try:
            target = "%s%s" % (SysMgr.mountPath, path)
            if append:
                fd = os.open(target, os.O_RDWR | os.O_CREAT | os.O_APPEND)
            else:
                fd = open(target, perm)
        except SystemExit:
            sys.exit(0)
        except:
            fpos = path.rfind("/")
            try:
                if path[fpos + 1 :] == "enable":
                    epath = path[:fpos]
                else:
                    epath = path[fpos + 1 :]
            except:
                epath = path

            try:
                SysMgr.sysInstance.cmdList[epath] = False
            except:
                pass

            SysMgr.printWarn("failed to use %s event" % epath, reason=True)
            return -1

        # write value #
        try:
            if append:
                os.write(fd, bytes(UtilMgr.encodeStr(val)))
                try:
                    os.close(fd)
                except:
                    pass
            else:
                fd.write(val)
                try:
                    fd.close()
                except:
                    pass

            # update command list #
            if path.endswith("/enable"):
                if val == "1":
                    SysMgr.sysInstance.cmdList[
                        path[: path.rfind("/enable")]
                    ] = True
                elif val == "0":
                    SysMgr.sysInstance.cmdList[
                        path[: path.rfind("/enable")]
                    ] = False
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn(
                "failed to apply command '%s' to %s" % (val, path), True
            )
            return -2

        return 0

    @staticmethod
    def doPrint(
        newline=True, clear=False, flush=True, addLine=False, isList=False
    ):
        if not SysMgr.bufferString and not SysMgr.bufferList:
            return

        if isList:
            output = SysMgr.getPrintList(retStr=True, char="")
        else:
            output = SysMgr.bufferString

        if addLine:
            output += "\n"

        SysMgr.printPipe(output, newline=newline, flush=flush)

        if clear:
            SysMgr.clearPrint()

    @staticmethod
    def printConsole(string):
        # split and cut lines by cols #
        string = "\n".join(
            [nline[: SysMgr.ttyCols - 1] for nline in string.split("\n")]
        )

        # print on console #
        try:
            print(string.rstrip())
        except SystemExit:
            sys.exit(0)
        except:
            return

    @staticmethod
    def addPrint(string, newline=1, force=False, isList=False):
        # check print flag #
        if not SysMgr.printEnable:
            return

        # check skip condition #
        if not force and SysMgr.checkCutCond(newline):
            return False

        # add string to buffer #
        if isList:
            SysMgr.bufferList.append(string)
        else:
            try:
                SysMgr.bufferString += string
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.bufferString = "%s%s" % (SysMgr.bufferString, string)

        SysMgr.bufferRows += newline

        if (
            SysMgr.terminalOver
            or not SysMgr.outPath
            or not SysMgr.streamEnable
        ):
            return True

        SysMgr.printConsole(string)

        return True

    @staticmethod
    def getPrintList(retStr=False, sort=False, char="\n"):
        if sort:
            SysMgr.bufferList.sort()

        if retStr:
            return char.join(SysMgr.bufferList)
        else:
            return SysMgr.bufferList

    @staticmethod
    def delPrint(newline=1):
        try:
            target = SysMgr.bufferString
            start = target.rfind("\n")
            pos = newline

            while start >= 0 and pos > 1:
                start = target.rfind("\n", start - 1)
                pos -= 1

            SysMgr.bufferString = target[: start + 1]
            SysMgr.bufferRows -= newline
        except:
            pass

    @staticmethod
    def clearPrint():
        del SysMgr.bufferString
        SysMgr.bufferList = []
        SysMgr.bufferString = ""
        SysMgr.bufferRows = 0
        SysMgr.terminalOver = False

    @staticmethod
    def clearScreen():
        # check stdout status #
        if not SysMgr.printEnable or SysMgr.pipeForPager:
            return

        if (
            SysMgr.isLinux or SysMgr.isDarwin
        ) and not "REMOTERUN" in os.environ:
            sys.stdout.write("\x1b[2J\x1b[H")
        elif sys.platform.startswith("win"):
            os.system("cls")

    @staticmethod
    def printLogo(absolute=False, big=False, onlyFile=False, pager=True):
        if not SysMgr.logoEnable:
            return

        # check package #
        if not "ISMAIN" in os.environ:
            print("\nPowered by %s" % ConfigMgr.logo)
            return

        # check print option and remote runner #
        if not SysMgr.printEnable or SysMgr.remoteRun:
            return

        # check extended ascii support #
        SysMgr.convExtAscii(ConfigMgr.logo)

        if not SysMgr.outPath:
            if SysMgr.streamEnable:
                if not absolute:
                    return
            elif onlyFile:
                return

        # print logo #
        if big:
            logo = UtilMgr.convColor(ConfigMgr.logo, "GREEN")
            if pager:
                SysMgr.printPipe(logo)
            else:
                print(logo)
        else:
            title = "/ G.u.i.d.e.r \tver.%s /" % __version__
            underline = "_" * (len(title))
            overline = "-" * (len(title))
            SysMgr.printPipe(" %s\n%s\n%s" % (underline, title, overline))

        # append new line #
        if onlyFile:
            SysMgr.printPipe("\n\n")

    @staticmethod
    def printInfoBuffer():
        SysMgr.printPipe(SysMgr.systemInfoBuffer + "\n")
        SysMgr.clearInfoBuffer()

    @staticmethod
    def parseCustomRecordCmd(cmdList):
        tempList = {"BEFORE": [], "AFTER": [], "STOP": []}

        if not cmdList:
            return {}

        cmdList = cmdList.split(",")

        for item in cmdList:
            sitem = item.split(":")
            ltime = sitem[0].upper()

            if (
                len(sitem) < 2
                or len(sitem) > 3
                or (ltime != "BEFORE" and ltime != "AFTER" and ltime != "STOP")
            ):
                SysMgr.printErr(
                    "wrong format used, BEFORE|AFTER|STOP:file:value"
                )
                sys.exit(-1)
            elif len(sitem) == 2:
                tempList[ltime].append([sitem[1]])
            elif len(sitem) == 3:
                tempList[ltime].append([sitem[1], sitem[2]])

        return tempList

    @staticmethod
    def getOverlayfsInfo(pid):
        data = SysMgr.getMountData(pid)
        mountList = SysMgr.convMountList(data)
        if not mountList:
            return {}

        overlayList = {}
        for point, info in mountList.items():
            try:
                if info["fs"] != "overlay":
                    continue

                overlayList[point] = {}
                items = info["subopt"].split(",")
                for line in items:
                    if line.startswith("lowerdir"):
                        attr = "lowerdir"
                    elif line.startswith("upperdir"):
                        attr = "upperdir"
                    elif line.startswith("mergedir"):
                        continue
                    else:
                        continue

                    dirs = line.lstrip(attr)[1:].split(":")
                    overlayList[point][attr] = dirs
            except SystemExit:
                sys.exit(0)
            except:
                continue

        return overlayList

    @staticmethod
    def convMountList(mountInfo):
        if not mountInfo:
            return {}

        mountList = {}
        for l in mountInfo:
            # split mount info #
            values = l.split(" - ")
            if len(values) != 2:
                continue
            left = values[0]
            right = values[1]

            # split left-side part #
            left = left.split()
            mountid, parentid, devid, root, path = left[:5]
            major, minor = devid.split(":")
            option = " ".join(left[5:-1])

            # split right-side part #
            right = right.split()
            fs, dev = right[0:2]
            soption = " ".join(right[2:])

            if ":" in dev:
                major, minor = dev.split(":")
            else:
                major = minor = -1

            # save mount info #
            mountList[path] = {
                "major": major,
                "minor": minor,
                "mountid": mountid,
                "fs": fs,
                "opt": option,
                "subopt": soption,
            }

        return mountList

    @staticmethod
    def getMountInfo():
        # check whether there is mount info in saved buffer #
        infoBuf = SysMgr.systemInfoBuffer

        if infoBuf == "":
            return

        # get area info #
        mountPosStart = infoBuf.find("Storage Info")
        if mountPosStart == -1:
            return

        mountPosStart = infoBuf.find(twoLine, mountPosStart + 1)
        if mountPosStart == -1:
            return

        mountPosStart = infoBuf.find(twoLine, mountPosStart + 1)
        if mountPosStart == -1:
            return

        mountPosStart = infoBuf.find("\n", mountPosStart)
        if mountPosStart == -1:
            return

        mountPosEnd = infoBuf.find(oneLine, mountPosStart)
        if mountPosEnd == -1:
            return

        # split string to list #
        try:
            mountTable = []
            tempTable = infoBuf[mountPosStart:mountPosEnd].split("\n")
            for idx, line in enumerate(tempTable):
                nrItem = len(line.split())
                if 1 < nrItem < 4:
                    mountTable.append("%s %s" % (line, tempTable[idx + 1]))
        except:
            pass

        init_mountData = {"dev": " ", "filesystem": " ", "mount": " "}

        # parse items #
        for item in mountTable:
            m = re.match(
                (
                    r"(?P<dev>\S+)\s+\((?P<devt>\S+)\)\s+\[(?P<range>\S+)\]\s+"
                    r"(?P<maj>[0-9]+):(?P<min>[0-9]+)\s+(?P<readSize>\S+)\s+"
                    r"(?P<writeSize>\S+)\s+(?P<totalSize>\S+)\s+"
                    r"(?P<freeSize>\S+)\s+(?P<Usage>\S+)\s+(?P<nrFile>\S+)\s+"
                    r"(?P<filesystem>\S+)\s+(?P<mount>.+)"
                ),
                item,
            )
            if not m:
                continue

            d = m.groupdict()
            mid = "%s:%s" % (d["maj"], d["min"])
            SysMgr.savedMountTree[mid] = dict(init_mountData)
            SysMgr.savedMountTree[mid]["dev"] = d["dev"]
            SysMgr.savedMountTree[mid]["filesystem"] = d["filesystem"]
            SysMgr.savedMountTree[mid]["mount"] = d["mount"]

            # add block range info #
            try:
                start, end = d["range"].split("-")
                SysMgr.savedMountTree[mid]["start"] = long(start)
                SysMgr.savedMountTree[mid]["end"] = long(end)
            except:
                pass

    @staticmethod
    def getProcTreeInfo():
        # check whether there is procTreeInfo in saved buffer #
        infoBuf = SysMgr.systemInfoBuffer

        if infoBuf == "":
            return

        magic = "!!!!!"

        # get tree pos #
        treePos = infoBuf.find(magic)
        if treePos == -1:
            return

        newPos = treePos + len(magic)

        # get comm pos #
        commPos = infoBuf[newPos:].find(magic)

        # check whether there is procTreeInfo in saved buffer #
        if commPos < 0:
            procTree = infoBuf[newPos:]
            procTree = procTree[: procTree.find("\n")].split(",")
        else:
            procTree = infoBuf[newPos : newPos + commPos].split(",")

        # parse task tree #
        for pair in procTree:
            try:
                ids = pair.split("#")
                tid = ids[0]
                pid = ids[1]

                # get pid and comm #
                if not pid.isdigit():
                    group = pid
                    pidPos = group.find("(")
                    pid = group[:pidPos]
                    comm = group[pidPos + 1 :].rstrip(")")
                    SysMgr.savedProcComm[pid] = comm

                SysMgr.savedProcTree[tid] = pid
            except:
                continue

        # remove task tree info #
        if commPos < 0:
            SysMgr.systemInfoBuffer = infoBuf[:treePos]
        else:
            commData = infoBuf[newPos + commPos + len(magic) :]
            commData = commData[: commData.find("\n")]
            SysMgr.commCache = UtilMgr.convStr2Dict(commData)
            SysMgr.systemInfoBuffer = infoBuf[: newPos - len(magic)]

    @staticmethod
    def applyLaunchOption():
        # check whether there is launch option in saved buffer #
        infoBuf = SysMgr.systemInfoBuffer

        # get position of launch option #
        if infoBuf == "":
            return

        launchPosStart = infoBuf.find("Launch")
        if launchPosStart == -1:
            return

        launchPosEnd = infoBuf.find("\n", launchPosStart)
        if launchPosEnd == -1:
            return

        SysMgr.launchBuffer = infoBuf[launchPosStart:launchPosEnd]

        # check version #
        try:
            verPosStart = infoBuf.find("Version")
            verPosEnd = infoBuf.find("\n", verPosStart)
            recVer = infoBuf[verPosStart:verPosEnd].split()[1]
            if recVer != __version__:
                SysMgr.printWarn(
                    "data version %s is different from current software %s"
                    % (__version__, recVer),
                    True,
                )
        except:
            pass

        # get arch type #
        archPosStart = infoBuf.find("CPU")
        archPosEnd = infoBuf.find("\n", archPosStart)

        # apply arch type #
        if not SysMgr.archOption:
            try:
                arch = infoBuf[archPosStart:archPosEnd].split()[1]
                SysMgr.setArch(arch)
            except SystemExit:
                sys.exit(0)
            except:
                pass

        # print arch type #
        if archPosStart >= 0 and archPosEnd >= 0:
            analOption = "{0:20} {1:<100}".format(
                "Analysis", "# %s" % (" ".join(sys.argv))
            )
            SysMgr.systemInfoBuffer = "%s\n%s\n%s" % (
                infoBuf[:archPosEnd],
                analOption,
                infoBuf[archPosEnd + 1 :],
            )

        # apply mode option #
        if SysMgr.isDrawMode():
            SysMgr.printInfo("<DRAW MODE>")

        if (
            " funcrec " in SysMgr.launchBuffer
            or " funcrecord " in SysMgr.launchBuffer
        ):
            SysMgr.threadEnable = False
            SysMgr.functionEnable = True
            if not SysMgr.isDrawMode():
                SysMgr.printInfo("<FUNCTION MODE>")
        else:
            SysMgr.threadEnable = True
            if not SysMgr.isDrawMode():
                SysMgr.printInfo("<THREAD MODE>")

        # apply filter option #
        filterList = None
        launchPosStart = SysMgr.launchBuffer.find(" -g")
        if SysMgr.isThreadMode() and launchPosStart > -1:
            filterList = SysMgr.launchBuffer[launchPosStart + 3 :]
            filterList = filterList[: filterList.find(" -")].strip()
            SysMgr.filterGroup = filterList.split(",")
            SysMgr.filterGroup = UtilMgr.cleanItem(SysMgr.filterGroup)
            SysMgr.printInfo(
                "only specific threads [ %s ] were recorded"
                % ", ".join(SysMgr.filterGroup)
            )

        # check filter list #
        if SysMgr.filterGroup:
            if not SysMgr.groupProcEnable:
                SysMgr.printInfo(
                    "only specific threads [ %s ] are shown"
                    % ", ".join(SysMgr.filterGroup)
                )
            else:
                SysMgr.printInfo(
                    (
                        "only specific threads that involved "
                        "in the process group [ %s ] are shown"
                    )
                    % ", ".join(SysMgr.filterGroup)
                )

        # apply dependency option #
        if " -D" in SysMgr.launchBuffer:
            SysMgr.depEnable = True

        # apply syscall option #
        if " -t" in SysMgr.launchBuffer:
            SysMgr.sysEnable = True

        # apply disable option #
        launchPosStart = SysMgr.launchBuffer.find(" -d")
        if launchPosStart > -1:
            filterList = SysMgr.launchBuffer[launchPosStart + 3 :]
            filterList = filterList[: filterList.find(" -")]
            if "a" in filterList:
                SysMgr.disableAll = True
            if "c" in filterList:
                SysMgr.cpuEnable = False
                SysMgr.latEnable = False
            if "l" in filterList:
                SysMgr.latEnable = False

        # apply enable option #
        launchPosStart = SysMgr.launchBuffer.find(" -e")
        if launchPosStart > -1:
            filterList = SysMgr.launchBuffer[launchPosStart + 3 :]
            filterList = filterList[: filterList.find(" -")]
            if "u" in filterList:
                dlist = SysMgr.getOption("d")
                if not dlist or not "u" in dlist:
                    SysMgr.userEnable = True
                    SysMgr.userRecordEnable = True
            if "m" in filterList:
                SysMgr.memEnable = True
            if "b" in filterList:
                SysMgr.blockEnable = True
            if "P" in filterList:
                SysMgr.powerEnable = True
            if "w" in filterList:
                SysMgr.wqEnable = True
            if "B" in filterList:
                SysMgr.binderEnable = True
            if "I" in filterList:
                SysMgr.i2cEnable = True
            if "f" in filterList:
                SysMgr.fsEnable = True
            if "h" in filterList:
                SysMgr.heapEnable = True
            if "L" in filterList:
                SysMgr.lockEnable = True
            if "i" in filterList:
                SysMgr.irqEnable = True
            if "n" in filterList:
                SysMgr.networkEnable = True

            # memory type #
            if "S" in filterList:
                SysMgr.pssEnable = True
            elif "u" in filterList:
                SysMgr.ussEnable = True
            elif not SysMgr.isDrawMode():
                SysMgr.rssEnable = True
        elif not SysMgr.isDrawMode():
            SysMgr.rssEnable = True

        # apply custom option #
        launchPosStart = SysMgr.launchBuffer.find(" -c")
        if launchPosStart > -1:
            filterList = SysMgr.launchBuffer[launchPosStart + 3 :]
            endIdx = filterList.find(" -")
            if endIdx >= 0:
                filterList = filterList[:endIdx]
            filterList = filterList.strip().split(",")
            for idx, item in enumerate(filterList):
                tempItem = filterList[idx].split("/")
                if len(tempItem) == 2:
                    filterList[idx] = tempItem[1]
                    SysMgr.customEventList.append(tempItem[1])
                elif len(tempItem) == 1:
                    filterList[idx] = tempItem[0]
                    SysMgr.customEventList.append(tempItem[0])
                else:
                    filterList.pop(idx)
            if filterList:
                SysMgr.printInfo(
                    "profiled custom events [ %s ]" % ", ".join(filterList)
                )
                if not SysMgr.customCmd:
                    SysMgr.customCmd = filterList

        # apply user event option #
        launchPosStart = SysMgr.launchBuffer.find(" -U")
        if launchPosStart > -1:
            SysMgr.ueventEnable = True
            filterList = SysMgr.launchBuffer[launchPosStart + 3 :]
            filterList = filterList[: filterList.find(" -")].strip()
            SysMgr.userCmd = str(filterList).split(",")
            SysMgr.userCmd = UtilMgr.cleanItem(SysMgr.userCmd)
            SysMgr.printInfo(
                "profiled user events [ %s ]"
                % ", ".join([cmd.strip() for cmd in SysMgr.userCmd])
            )
            SysMgr.userEventList = [
                cmd.split(":")[0].strip() for cmd in SysMgr.userCmd
            ]

        # apply kernel event option #
        launchPosStart = SysMgr.launchBuffer.find(" -K")
        if launchPosStart > -1:
            SysMgr.keventEnable = True
            filterList = SysMgr.launchBuffer[launchPosStart + 3 :]
            filterList = filterList[: filterList.find(" -")].strip()
            SysMgr.kernelCmd = str(filterList).split(",")
            SysMgr.kernelCmd = UtilMgr.cleanItem(SysMgr.kernelCmd)
            SysMgr.printInfo(
                "profiled kernel events [ %s ]"
                % ", ".join([cmd.strip() for cmd in SysMgr.kernelCmd])
            )
            SysMgr.kernelEventList = [
                cmd.split(":")[0].strip() for cmd in SysMgr.kernelCmd
            ]

        # apply arch option #
        launchPosStart = SysMgr.launchBuffer.find(" -A")
        if launchPosStart > -1:
            filterList = SysMgr.launchBuffer[launchPosStart + 3 :]
            filterList = filterList[: filterList.find(" -")].strip()

            if SysMgr.arch != filterList:
                SysMgr.printErr(
                    (
                        "arch(%s) of recorded target is different with "
                        "current arch(%s), use -A option with %s"
                    )
                    % (filterList, SysMgr.arch, filterList)
                )
                sys.exit(-1)

    @staticmethod
    def writeEvent(message, show=True):
        # check mount path #
        if not SysMgr.mountPath:
            SysMgr.mountPath = SysMgr.getDebugfsPath()

        # check trace file #
        if not SysMgr.eventLogFd:
            if not SysMgr.eventLogPath:
                SysMgr.eventLogPath = "%s%s" % (
                    SysMgr.mountPath,
                    "../trace_marker",
                )

            try:
                SysMgr.eventLogFd = open(SysMgr.eventLogPath, "w")
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenWarn(
                    "failed to open %s" % SysMgr.eventLogPath, True, True
                )
                return

        # write trace log #
        if SysMgr.eventLogFd:
            try:
                SysMgr.eventLogFd.write(message)
                event = message[message.find("_") + 1 :]
                if show:
                    SysMgr.printInfo("wrote '%s' event" % event)

                try:
                    SysMgr.eventLogFd.flush()
                except:
                    pass

                return True
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn(
                    "failed to write %s event" % (message), reason=True
                )
                return
        else:
            SysMgr.printErr(
                "failed to write %s event because of no file\n" % message
            )

    @staticmethod
    def infoBufferPrint(line):
        SysMgr.systemInfoBuffer = "%s%s\n" % (SysMgr.systemInfoBuffer, line)

    @staticmethod
    def clearInfoBuffer():
        SysMgr.systemInfoBuffer = ""

    @staticmethod
    def printPipWarn(name, pkg):
        SysMgr.printWarn(
            (
                "failed to import python package: %s, "
                "try to run 'pip%s install %s'"
            )
            % (name, sys.version_info[0], pkg),
            True,
        )

    @staticmethod
    def drawTimeline(
        inputPath=None,
        inputData=None,
        outputPath=None,
        configPath=None,
        configData=None,
        taskList=None,
        start=0,
        annotation=None,
        yval=None,
        begin=0,
        end=0,
    ):
        def _addUserEvent(inputData):
            if not inputData or not "EVENT" in SysMgr.environList:
                return

            for item in SysMgr.environList["EVENT"]:
                try:
                    values = item.split(":")
                    if not (3 <= len(values) <= 5):
                        SysMgr.printErr(
                            (
                                "failed to recognize %s in X:Y:NAME:[CPU|MEM"
                                "|IO]:[BOX|CIRCLE|LARROW|RARROW] format"
                            )
                            % item
                        )
                        sys.exit(-1)

                    x, y, name = values[:3]

                    # add timeline data #
                    inputData["segments"].append(
                        {
                            "group": long(y),
                            "text": name,
                            "id": None,
                            "state": "EVENT_USER",
                            "time_start": float(x),
                            "time_end": float(x) + 0.000001,
                        }
                    )

                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(
                        "failed to recognize event for timeline", reason=True
                    )
                    sys.exit(-1)

        # get svgwrite object #
        svgwrite = SysMgr.getPkg("svgwrite")

        if inputPath:
            inputStr = ' from "%s"' % inputPath
        else:
            inputStr = ""

        SysMgr.printStat("start drawing timeline%s..." % inputStr)

        try:
            dwg = svgwrite.Drawing(outputPath, profile="tiny", debug=True)

            config = Timeline.Config()
            if configPath or configData:
                config = Timeline.Config._load(configPath, configData)

            # check timeunit #
            if "TIMEUNIT" in SysMgr.environList:
                config.TIMEUNIT = SysMgr.environList["TIMEUNIT"][0].lower()
            else:
                config.TIMEUNIT = "us"

            # set font size #
            duration = 0
            if "DURATION" in SysMgr.environList:
                try:
                    duration = SysMgr.environList["DURATION"][0]
                    duration = long(duration)
                except:
                    SysMgr.printErr(
                        "failed to set duration to '%s'" % duration, True
                    )
                    sys.exit(-1)

            # set font size #
            durationMin = 0
            if "DURATIONMIN" in SysMgr.environList:
                try:
                    durationMin = SysMgr.environList["DURATIONMIN"][0]
                    durationMin = long(durationMin)
                except:
                    SysMgr.printErr(
                        "failed to set minimum duration to '%s'" % durationMin,
                        True,
                    )
                    sys.exit(-1)

            # apply user event #
            _addUserEvent(inputData)

            # set convert table #
            Timeline.conv_table = {}
            if "CONVGROUP" in SysMgr.environList:
                try:
                    for item in SysMgr.environList["CONVGROUP"]:
                        src, des = item.split(":", 1)
                        Timeline.conv_table[src.strip()] = des.strip()
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(
                        "failed to set group conversion table", True
                    )
                    sys.exit(-1)

            # load data #
            timeline = Timeline.load(
                inputPath,
                inputData,
                config,
                taskList,
                begin,
                end,
                duration,
                durationMin,
            )
            if not timeline:
                SysMgr.printErr("no time segment on timeline")
                return

            # set stroke candidate #
            if "STROKE" in SysMgr.environList:
                timeline.stroke_text = SysMgr.environList["STROKE"]
            else:
                timeline.stroke_text = None

            # set stroke interval #
            if "STROKEINTERVAL" in SysMgr.environList:
                try:
                    stroke_interval = SysMgr.environList["STROKEINTERVAL"][0]
                    timeline.stroke_interval = long(stroke_interval)
                except:
                    SysMgr.printErr(
                        "failed to set interval for stroke to '%s'"
                        % stroke_interval,
                        True,
                    )
                    sys.exit(-1)
            else:
                timeline.stroke_interval = 0

            # set stroke duration #
            if "STROKEDURATION" in SysMgr.environList:
                try:
                    stroke_duration = SysMgr.environList["STROKEDURATION"][0]
                    timeline.stroke_duration = long(stroke_duration)
                except:
                    SysMgr.printErr(
                        "failed to set duration for stroke to '%s'"
                        % stroke_duration,
                        True,
                    )
                    sys.exit(-1)
            else:
                timeline.stroke_duration = 0

            # draw timeslices #
            timeline.draw(dwg, start=start, annotation=annotation, yval=yval)

            dwg.save()
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to draw timeline", reason=True)
            return

        # get output size #
        fsize = UtilMgr.getFileSizeStr(outputPath)

        SysMgr.printStat(
            "wrote timeline segments into '%s'%s" % (outputPath, fsize)
        )

    @staticmethod
    def drawText(lines):
        # pylint: disable=import-error

        imageType = None

        # get textwrap object #
        textwrap = SysMgr.getPkg("textwrap", False)
        if not textwrap:
            SysMgr.printPipWarn("textwrap", "textwrap3")
            sys.exit(-1)

        # get PIL object #
        PIL = SysMgr.getPkg("PIL", False)
        if not PIL:
            SysMgr.printPipWarn("PIL", "pillow")
            sys.exit(-1)

        from PIL import Image, ImageFont, ImageDraw

        # load jpeg plugin #
        try:
            if not imageType:
                from PIL import JpegImagePlugin

                imageType = "jpg"
        except ImportError:
            err = sys.exc_info()[1]
            SysMgr.printWarn(
                "failed to import python package: %s" % err.args[0]
            )
        except SystemExit:
            sys.exit(0)

        # load bmp plugin instead of jpeg #
        try:
            if not imageType:
                from PIL import BmpImagePlugin

                imageType = "bmp"
        except ImportError:
            err = sys.exc_info()[1]
            SysMgr.printErr(
                "failed to import python package: %s" % err.args[0]
            )
            return
        except SystemExit:
            sys.exit(0)

        if not SysMgr.imagePath:
            SysMgr.printErr("failed to load image path")
            return

        # set image file extension #
        SysMgr.imagePath += ".%s" % imageType

        if SysMgr.fontPath:
            try:
                # load specific font #
                imageFont = ImageFont.truetype(SysMgr.fontPath, 10)
            except:
                SysMgr.printErr(
                    "failed to load font from %s" % SysMgr.fontPath
                )
                return
        else:
            try:
                # load default font #
                imageFont = ImageFont.load_default().font
            except:
                SysMgr.printErr(
                    (
                        "failed to load default font because %s, "
                        "try to use -T option"
                    )
                    % SysMgr.getErrMsg()
                )
                return

        # get default font size and image length #
        text = textwrap.fill("A", width=150)
        fontSizeX, fontSizeY = imageFont.getsize(text)

        # check input parameter #
        if type(lines) is list:
            lines = "".join(lines)

        # convert string to list #
        lines = lines.split("\n")

        # calculate image size #
        imageSizeX = fontSizeX * SysMgr.lineLength
        imageSizeY = fontSizeY * len(lines) + (fontSizeY * 2)
        imagePosY = 1

        # make new blink image #
        if imageType == "jpg":
            imageObject = Image.new(
                "RGB", (imageSizeX, imageSizeY), (255, 255, 255)
            )
        elif imageType == "bmp":
            imageObject = Image.new("RGB", (900, imageSizeY), (255, 255, 255))
        else:
            SysMgr.printErr("no output image type")
            return

        # make palette #
        drawnImage = ImageDraw.Draw(imageObject)

        for line in lines:
            text = textwrap.fill(line, width=170)

            imagePosY += fontSizeY

            # write text on image #
            drawnImage.text((1, imagePosY), text, (0, 0, 0), font=imageFont)

        try:
            # save image as file #
            imageObject.save(SysMgr.imagePath)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to save image as %s\n" % SysMgr.imagePath)
            return

        # get output size #
        fsize = UtilMgr.getFileSizeStr(SysMgr.imagePath)

        SysMgr.printStat(
            "saved image into %s%s successfully" % (SysMgr.imagePath, fsize)
        )

    @staticmethod
    def clearProcBuffer():
        SysMgr.procBufferSize = 0
        SysMgr.procBuffer = []

    @staticmethod
    def printProcBuffer(suffix="\n"):
        msg = " Detailed Statistics "
        stars = "*" * long((long(SysMgr.lineLength) - len(msg)) / 2)
        SysMgr.printPipe("\n\n%s%s%s\n\n" % (stars, msg, stars))
        if SysMgr.procBuffer:
            SysMgr.printPipe(SysMgr.procBuffer)
        else:
            SysMgr.printPipe("\n\tNone%s" % suffix)

    @staticmethod
    def addProcBuffer(data):
        SysMgr.procBuffer.insert(0, data)
        SysMgr.procBufferSize += len(data)

        bufferSize = SysMgr.bufferSize
        convSize = UtilMgr.convSize2Unit

        while SysMgr.procBufferSize > bufferSize > 0:
            # flush all data in buffer to the file #
            if not SysMgr.bufferLossEnable:
                SysMgr.printInfo(
                    (
                        "start writing interval statistics because "
                        "buffer (%s) exceed %s"
                    )
                    % (
                        convSize(SysMgr.procBufferSize),
                        convSize(bufferSize),
                    )
                )

                # create a new process #
                pid = SysMgr.createProcess(isDaemon=True, chPgid=True)
                # save output to file as child #
                if pid == 0:
                    # append time to the output file #
                    utcTime = UtilMgr.getUTCTime()
                    if utcTime:
                        now = utcTime
                    else:
                        now = long(SysMgr.getUptime())

                    # append PID to the output file #
                    SysMgr.fileSuffix = "%s_%s" % (now, SysMgr.pid)

                    # change priority #
                    SysMgr.setLowPriority(True)

                    # flush all data to the file and exit #
                    SysMgr.stopHandler()
                # clear buffer as parent #
                elif pid > 0:
                    SysMgr.clearProcBuffer()
                    break
                # pop old data in buffer because of fork failure #
                else:
                    pass

            # pop old data in buffer #
            if not SysMgr.bufferOverflowed:
                SysMgr.printWarn(
                    (
                        "new data is going to be overwritten to the buffer"
                        " because of buffer overflow\n"
                        "\tincrease buffer size (%s) "
                        "if you want to prevent data loss"
                    )
                    % convSize(bufferSize),
                    True,
                )
                SysMgr.bufferOverflowed = True

            if not SysMgr.procBuffer:
                break

            SysMgr.procBufferSize -= len(SysMgr.procBuffer[-1])
            SysMgr.procBuffer.pop(-1)

    @staticmethod
    def updateSession():
        if not SysMgr.addrListForPrint:
            return

        addrListForPrint = dict(SysMgr.addrListForPrint)
        for addr, cli in addrListForPrint.items():
            if cli.status == "SENT" and cli.ignore > 1:
                SysMgr.printInfo(
                    "unregistered %s:%d for PRINT" % (cli.ip, cli.port)
                )
                del SysMgr.addrListForPrint[addr]

    @staticmethod
    def printTopStats():
        # JSON mode #
        if SysMgr.jsonEnable:
            # print report in JSON format later #
            if SysMgr.reportEnable:
                pass
            else:
                # convert dict data to JSON string #
                jsonStr = UtilMgr.convDict2Str(SysMgr.jsonData, pretty=False)
                if not jsonStr:
                    SysMgr.printWarn(
                        "failed to convert report data to JSON format"
                    )
                else:
                    SysMgr.printPipe(jsonStr)
        # realtime mode #
        elif not SysMgr.outPath:
            if not SysMgr.streamEnable:
                SysMgr.clearScreen()
            SysMgr.doPrint()
        # pipe mode #
        elif SysMgr.pipeEnable:
            SysMgr.doPrint(addLine=True)
        # buffered mode #
        else:
            SysMgr.addProcBuffer(SysMgr.bufferString + "\n")

            # send output to nodes registered #
            SysMgr.sendOutput2Nodes(SysMgr.bufferString)

        # flush buffer #
        SysMgr.clearPrint()

    @staticmethod
    def checkCutCond(newline=0):
        if SysMgr.terminalOver:
            return True
        elif (
            not SysMgr.outPath
            and not SysMgr.jsonEnable
            and not SysMgr.streamEnable
            and SysMgr.bufferRows + newline
            >= SysMgr.ttyRows - SysMgr.ttyRowsMargin
        ):
            SysMgr.terminalOver = True
            SysMgr.addPrint("---more---", force=True)
            return True
        else:
            return False

    @staticmethod
    def updateTimer(interval=None):
        if not SysMgr.isLinux:
            return

        try:
            if interval:
                signal.alarm(long(interval))
            else:
                signal.alarm(SysMgr.intervalEnable)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to set interval timer", reason=True)
            sys.exit(-1)

    @staticmethod
    def updateOutPath():
        # dir #
        if SysMgr.outPath and os.path.isdir(SysMgr.outPath):
            SysMgr.inputFile = os.path.join(SysMgr.outPath, SysMgr.outFilePath)
        # file #
        else:
            SysMgr.inputFile = SysMgr.outPath

        # check output path #
        if not SysMgr.inputFile:
            return

        SysMgr.inputFile = os.path.realpath(SysMgr.inputFile)

        # check device node #
        if SysMgr.inputFile.startswith("/dev/"):
            return

        # append suffix to output file #
        if SysMgr.fileSuffix:
            dirname, filename = UtilMgr.getPath(SysMgr.inputFile)
            name, ext = os.path.splitext(filename)
            filepath = os.path.join(dirname, name)
            SysMgr.inputFile = "%s_%s%s" % (filepath, SysMgr.fileSuffix, ext)

        # append uptime to the output file #
        if not SysMgr.termFlag:
            SysMgr.inputFile = "%s_%s" % (
                SysMgr.inputFile,
                SysMgr.getRuntime(),
            )

    @staticmethod
    def sendOutput2Nodes(line):
        if not SysMgr.addrListForPrint:
            return
        elif not line:
            return

        addrListForPrint = dict(SysMgr.addrListForPrint)
        for addr, cli in addrListForPrint.items():
            udpSeg = 65507  # maximum UDP diagram size
            start = 0
            end = udpSeg
            while 1:
                # split by newline #
                if len(line) >= end:
                    pos = line[start:end].rfind("\n")
                    if pos > 0:
                        end = pos + start

                # send data #
                ret = cli.send(line[start:end])
                if not ret:
                    del SysMgr.addrListForPrint[addr]
                    break
                else:
                    cli.ignore += 1

                if end >= len(line):
                    break

                # update sending part #
                start = end
                end += udpSeg

    @staticmethod
    def printPipe(line="", newline=True, flush=False, pager=True, trim=True):
        # check logging option #
        if SysMgr.loggingEnable:
            SysMgr.printLog(line)

        # send output to nodes registered #
        SysMgr.sendOutput2Nodes(line)

        # check print flag #
        if not SysMgr.printEnable:
            return

        # convert list to string #
        if type(line) is list:
            if not line:
                line = ""
            elif line[0][-1] == "\n":
                line = "".join(line)
            else:
                line = "\n".join(line)

        # pager initialization #
        if (
            not pager
            or SysMgr.pipeForPager
            or SysMgr.outPath
            or SysMgr.streamEnable
        ):
            pass
        elif not SysMgr.isTopMode() or SysMgr.isHelpMode():
            try:
                if SysMgr.isLinux or SysMgr.isDarwin:
                    if UtilMgr.which("less"):
                        # defopt = '-FRSXMQi'
                        defopt = "-FRXMQi"

                        # set SIGCHLD #
                        signal.signal(signal.SIGCHLD, signal.SIG_DFL)

                        # verify pager option support #
                        ret = os.popen(
                            "echo | less %s 2>&1" % defopt, "r"
                        ).read()
                        if len(ret) <= 1:
                            poption = "less %s" % defopt
                        else:
                            poption = "less"

                        # run less as pager #
                        SysMgr.pipeForPager = os.popen(poption, "w")

                        # set signals to prevent abnormal terminal status #
                        SysMgr.setDefaultSignal()
                    elif UtilMgr.which("more"):
                        SysMgr.pipeForPager = os.popen("more", "w")
                elif sys.platform.startswith("win"):
                    try:
                        SysMgr.pipeForPager = os.popen("more", "w")
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass
                else:
                    # no supported OS #
                    SysMgr.pipeForPager = None

                SysMgr.encodeEnable = False

                SysMgr.setPipeHandler()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn("failed to use pager", True, reason=True)

        # pager output #
        if SysMgr.pipeForPager:
            try:
                if line:
                    SysMgr.pipeForPager.write(line)

                    if newline and line[-1] != "\n":
                        SysMgr.pipeForPager.write("\n")

                return
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("failed to print to pager\n", True)
                SysMgr.pipeForPager = None

        # file initialization #
        if SysMgr.outPath and not SysMgr.printFd:
            # profile #
            if SysMgr.isRuntimeMode():
                SysMgr.updateOutPath()
            # analysis #
            else:
                # dir #
                if os.path.isdir(SysMgr.outPath):
                    name, ext = os.path.splitext(
                        os.path.basename(SysMgr.inputFile)
                    )
                    if ext == "" or ext == ".dat":
                        name = "%s.out" % name
                    if name.endswith(".dat"):
                        name = name.replace(".dat", ".out")
                    SysMgr.inputFile = os.path.join(SysMgr.outPath, name)
                # file #
                else:
                    SysMgr.inputFile = SysMgr.outPath

            # convert abnormal characters from full path #
            SysMgr.inputFile = os.path.normpath(SysMgr.inputFile)

            # apply filename extension for compression #
            if SysMgr.compressEnable:
                if not SysMgr.inputFile.endswith(".gz"):
                    SysMgr.inputFile += ".gz"
                if SysMgr.outPath and not SysMgr.outPath.endswith(".gz"):
                    SysMgr.outPath += ".gz"

            # backup an exist file #
            SysMgr.backupFile(SysMgr.inputFile)

            # open file #
            try:
                # change permission #
                try:
                    os.chmod(SysMgr.inputFile, 0o777)
                except:
                    pass

                # open output file #
                SysMgr.printFd = open(SysMgr.inputFile, "wb")

                # apply compression to the file #
                if SysMgr.compressEnable:
                    compressor = SysMgr.getPkg("gzip", False)
                    if compressor:
                        SysMgr.printFd = compressor.GzipFile(
                            fileobj=SysMgr.printFd
                        )

                # print file name #
                if SysMgr.outPath:
                    SysMgr.printInfo(
                        "start writing statistics to '%s'" % SysMgr.inputFile
                    )
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenErr(SysMgr.inputFile)
                sys.exit(-1)

        # file output #
        if SysMgr.printFd:
            try:
                if line:
                    SysMgr.printFd.write(line.encode("utf-8"))

                    if newline and line[-1] != "\n":
                        SysMgr.printFd.write("\n".encode("utf-8"))

                if flush:
                    SysMgr.printFd.flush()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "failed to write to %s" % SysMgr.printFd.name, True
                )
        # console output #
        else:
            # set truncate size #
            if trim:
                cols = SysMgr.ttyCols
            else:
                cols = 0

            # append the end color character to head #
            if SysMgr.colorEnable and not SysMgr.jsonEnable:
                try:
                    line = ConfigMgr.ENDC + line
                except SystemExit:
                    sys.exit(0)
                except:
                    line = "%s%s" % (ConfigMgr.ENDC, line)

            # rstrip by terminal size #
            try:
                # no limit #
                if cols == 0 or SysMgr.jsonEnable:
                    line = "\n".join([nline for nline in line.split("\n")])
                # trim a colorful line by terminal width #
                elif (
                    not SysMgr.forceColorEnable
                    and SysMgr.colorEnable
                    and ConfigMgr.ENDC in line
                ):
                    if not SysMgr.ansiObj:
                        UtilMgr.removeColor("")
                    ansiObj = SysMgr.ansiObj
                    line = "\n".join(
                        [
                            ansiObj.sub("", n)[:cols]
                            if len(ansiObj.sub("", n)) > cols
                            else n
                            for n in line.split("\n")
                        ]
                    )
                # trim a normal line by terminal width #
                else:
                    line = "\n".join(
                        [nline[: cols - 1] for nline in line.split("\n")]
                    )
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn("failed to print to console", reason=True)
                return

            # convert to extended ascii #
            nline = SysMgr.convExtAscii(line)

            # print string to console #
            try:
                sys.stdout.write(nline)
            except SystemExit:
                sys.exit(0)
            except:
                if SysMgr.encodeEnable:
                    SysMgr.encodeEnable = False

                    sys.stdout.write(line)

            # print newline #
            if newline:
                sys.stdout.write("\n")
                SysMgr.newlined = True
            else:
                SysMgr.newlined = False

            # flush buffer #
            if flush or SysMgr.remoteRun:
                sys.stdout.flush()

    @staticmethod
    def convExtAscii(line):
        # pylint: disable=no-member
        # pylint: disable=undefined-variable
        if not SysMgr.encodeEnable:
            return line

        try:
            newline = line.replace("-------", "───────")
            newline = newline.replace("=", "═")
            newline = newline.replace("|-", "├─")
            newline = newline.replace("|", "│")

            if sys.version_info < (3, 0) and not SysMgr.encoding:
                if not sys.getdefaultencoding().lower().startswith("utf"):
                    try:
                        reload(sys)
                        sys.setdefaultencoding("utf-8")
                        SysMgr.encoding = sys.getdefaultencoding()
                    except:
                        pass

            return newline
        except:
            SysMgr.encodeEnable = False
            return line

    @staticmethod
    def printLog(log, level="INFO"):
        if SysMgr.dltEnable:
            DltAnalyzer.doLogDlt(msg=log, level=level)
        if SysMgr.kmsgEnable:
            LogMgr.doLogKmsg(msg=log)
        if SysMgr.syslogEnable:
            LogMgr.doLogSyslog(msg=log)
        if SysMgr.journalEnable:
            LogMgr.doLogJournal(msg=log)

    @staticmethod
    def printWarn(line, always=False, reason=False, newline=True):
        # print backtrace #
        # SysMgr.printBacktrace()

        if not SysMgr.logEnable or (not SysMgr.warnEnable and not always):
            return

        if reason:
            rstring = " because %s" % SysMgr.getErrMsg()
        else:
            rstring = ""

        proc = SysMgr.getProcInfo()

        log = "%s%s%s%s" % ("[WARN] ", proc, line, rstring)

        # log #
        if SysMgr.loggingOpsEnable:
            SysMgr.printLog(log, level="WARN")

        log = "\n%s" % (UtilMgr.convColor(log, "WARNING", force=True))

        if newline:
            log = "%s\n" % log

        # write log #
        if SysMgr.stdlog:
            SysMgr.stdlog.write(log)

        # write log #
        if "REMOTERUN" in os.environ:
            print(log.replace("\n", ""))
        else:
            SysMgr.writeErr(SysMgr.stderr, log)

    @staticmethod
    def printErr(line, reason=False):
        # print backtrace #
        # SysMgr.printBacktrace()

        if not SysMgr.logEnable and SysMgr.forceEnable:
            return

        SysMgr.flushAllForPrint()

        if reason:
            rstring = " because %s" % SysMgr.getErrMsg()
        else:
            rstring = ""

        try:
            line = line.rstrip("\n")
        except SystemExit:
            sys.exit(0)
        except:
            pass

        proc = SysMgr.getProcInfo()

        log = "%s%s%s%s" % ("[ERROR] ", proc, line, rstring)

        # log #
        if SysMgr.loggingOpsEnable:
            SysMgr.printLog(log, level="ERROR")

        log = "\n%s\n" % (UtilMgr.convColor(log, "FAIL", force=True))

        # write log to stdout #
        if SysMgr.stdlog:
            SysMgr.stdlog.write(log)

        # write log to stderr #
        if "REMOTERUN" in os.environ:
            print(log.replace("\n", ""))
        else:
            SysMgr.writeErr(SysMgr.stderr, log)

    @staticmethod
    def getProcInfo():
        if SysMgr.parentPid > 0:
            return "<%s(%s)> " % (SysMgr.comm, SysMgr.pid)
        else:
            return ""

    @staticmethod
    def printInfo(line, prefix=True, suffix=True, title=True):
        if not SysMgr.logEnable:
            return

        # title and task #
        if title:
            title = "[INFO] "
            proc = SysMgr.getProcInfo()
        else:
            title = ""
            proc = ""

        # prefix #
        if prefix:
            prefix = "\n"
        else:
            prefix = ""

        # add newline #
        if not SysMgr.newlined:
            prefix += "\n"
            SysMgr.newlined = True

        # build #
        log = "%s%s%s" % (title, proc, line)

        # log #
        if SysMgr.loggingOpsEnable:
            SysMgr.printLog(log)

        # color #
        log = UtilMgr.convColor(log, "BOLD", force=True)
        try:
            log = prefix + log
        except SystemExit:
            sys.exit(0)
        except:
            log = "%s%s" % (prefix, log)

        if SysMgr.stdlog:
            SysMgr.stdlog.write(log)

        if suffix:
            try:
                print(log)
            except SystemExit:
                sys.exit(0)
            except:
                return
        else:
            try:
                sys.stdout.write(log)
                sys.stdout.flush()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("failed to flush stdout", reason=True)

    @staticmethod
    def printGood(line):
        if not SysMgr.logEnable:
            return

        proc = SysMgr.getProcInfo()

        log = "%s%s%s" % ("[INFO] ", proc, line)
        log = "\n%s" % (UtilMgr.convColor(log, "OKGREEN", force=True))

        if SysMgr.stdlog:
            SysMgr.stdlog.write(log)

        print(log)

    @staticmethod
    def printLine(line):
        if not SysMgr.logEnable:
            return

        proc = SysMgr.getProcInfo()

        log = "%s%s" % (proc, line)
        log = "\n%s" % (UtilMgr.convColor(log, "UNDERLINE", force=True))

        if SysMgr.stdlog:
            SysMgr.stdlog.write(log)

        print(log)

    @staticmethod
    def printStat(line):
        if not SysMgr.logEnable:
            return

        proc = SysMgr.getProcInfo()

        log = "%s%s%s" % ("[STEP] ", proc, line)

        # log #
        if SysMgr.loggingOpsEnable:
            SysMgr.printLog(log)

        log = "\n%s" % (UtilMgr.convColor(log, "SPECIAL", force=True))

        if SysMgr.stdlog:
            SysMgr.stdlog.write(log)

        print(log)

    @staticmethod
    def isValidRequest(request):
        try:
            if request.startswith("EVENT_") or TaskAnalyzer.requestType.index(
                request
            ):
                pass
            else:
                raise Exception("wrong request")

            return True
        except SystemExit:
            sys.exit(0)
        except:
            return False

    @staticmethod
    def printOpenErr(path, reason=True):
        SysMgr.printErr("failed to open '%s'" % os.path.realpath(path), reason)

    @staticmethod
    def printOpenWarn(path, always=False, reason=True):
        SysMgr.printWarn(
            "failed to open '%s'" % os.path.realpath(path), always, reason
        )

    @staticmethod
    def addOption(option):
        if not SysMgr.optionList:
            SysMgr.parseOption()

        if type(SysMgr.optionList) is not list:
            return

        if not option in SysMgr.optionList:
            SysMgr.optionList.append(option)

    @staticmethod
    def parseOption(option=None):
        if not "ISMAIN" in os.environ:
            return

        if not option and SysMgr.optionList:
            return

        # parse options #
        parsedOpt = []
        prevIdx = 0

        # choose option #
        if option:
            optList = [sys.argv[1]] + option
        else:
            optList = sys.argv[1:]

        # parse option string #
        for idx, opt in enumerate(optList):
            if opt.startswith("-"):
                parsedOpt.append(" ".join(optList[prevIdx:idx])[1:])
                prevIdx = idx
        parsedOpt.append(" ".join(optList[prevIdx:])[1:])

        # save parsed option #
        SysMgr.optionList = parsedOpt[1:]

        # check redundant option #
        usedOpt = {}
        for opt in SysMgr.optionList:
            try:
                if not opt[0] in usedOpt or opt[0] == "-":
                    usedOpt[opt[0]] = True
                    continue
            except:
                continue

            SysMgr.printErr(
                "wrong -%s option because of redundant use" % opt[0]
            )
            sys.exit(-1)

    @staticmethod
    def findOption(option):
        if not "ISMAIN" in os.environ:
            return

        if len(sys.argv) <= 2 and not SysMgr.optionList:
            return False

        SysMgr.parseOption()

        for item in SysMgr.optionList:
            if item == "":
                pass
            elif item[0] == option:
                return True

        return False

    @staticmethod
    def getOption(option):
        if not "ISMAIN" in os.environ:
            return

        if len(sys.argv) <= 2 and not SysMgr.optionList:
            return None

        SysMgr.parseOption()

        for item in SysMgr.optionList:
            if item == "":
                pass
            elif item[0] == option and len(item[1:]) > 0:
                return item[1:].strip()

        return None

    @staticmethod
    def parseRuntimeOption(value):
        SysMgr.countEnable = True
        convNum = UtilMgr.convNum
        convTime = UtilMgr.convUnit2Time

        # split params #
        if value:
            repeatParams = UtilMgr.cleanItem(value.split(":"), False)

        # check interval value by other option #
        if SysMgr.getOption("i"):
            applyInterval = False
        else:
            applyInterval = True

        if not value:
            if applyInterval:
                SysMgr.intervalEnable = 1
            SysMgr.repeatCount = 1
            repeatParams = None
        elif len(repeatParams) == 2 or len(repeatParams) == 3:
            try:
                # get interval #
                interval = SysMgr.getOption("i")
                if interval:
                    interval = long(interval)
                else:
                    interval = convTime(repeatParams[0])

                if applyInterval:
                    SysMgr.intervalEnable = interval
                SysMgr.repeatInterval = interval

                # get count #
                cnt = repeatParams[1]
                if not cnt:
                    SysMgr.repeatCount = sys.maxsize
                elif cnt.isdigit():
                    SysMgr.repeatCount = long(cnt)
                else:
                    SysMgr.repeatCount = long(convTime(cnt) / interval)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    (
                        "wrong value for runtime option because %s, "
                        "input integer values"
                    )
                    % SysMgr.getErrMsg()
                )
                sys.exit(-1)
        elif len(repeatParams) == 1:
            try:
                interval = long(convTime(repeatParams[0]))

                # top mode #
                if SysMgr.isTopMode():
                    ival = SysMgr.getOption("i")
                    if ival:
                        ival = long(ival)
                        interval = long(interval / ival)
                        SysMgr.repeatCount = interval
                        SysMgr.repeatInterval = interval
                        if applyInterval:
                            SysMgr.intervalEnable = ival
                    else:
                        SysMgr.repeatCount = interval
                        SysMgr.repeatInterval = interval
                        if applyInterval:
                            SysMgr.intervalEnable = 1
                # record mode #
                else:
                    SysMgr.repeatCount = 1
                    SysMgr.repeatInterval = interval
                    if applyInterval:
                        SysMgr.intervalEnable = interval
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    (
                        "wrong value for runtime option because %s, "
                        "input integer values"
                    )
                    % SysMgr.getErrMsg()
                )
                sys.exit(-1)
        else:
            SysMgr.printErr(
                (
                    "wrong value for runtime option because %s, "
                    "input in the format INTERVAL:REPEAT"
                )
                % SysMgr.getErrMsg()
            )
            sys.exit(-1)

        # check variables #
        if (
            not SysMgr.intervalEnable
            or SysMgr.intervalEnable < 1
            or SysMgr.repeatCount < 1
        ):
            SysMgr.printErr(
                "wrong value for runtime option, input values bigger than 0"
            )
            sys.exit(-1)

        # change too big interval to prevent overflow #
        try:
            # just use maximum value for 32-bit system #
            if SysMgr.intervalEnable == sys.maxsize:
                SysMgr.intervalEnable = SysMgr.maxSize
            if SysMgr.repeatInterval == sys.maxsize:
                SysMgr.repeatInterval = SysMgr.maxSize
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                (
                    "wrong value for interval option because %s, "
                    "input integer value"
                )
                % SysMgr.getErrMsg()
            )
            sys.exit(-1)

        # get termination flag #
        if SysMgr.checkMode("req"):
            pass
        elif repeatParams and len(repeatParams) == 3:
            SysMgr.termFlag = False
            SysMgr.printInfo(
                "run every %s sec %s time"
                % (convNum(SysMgr.intervalEnable), convNum(SysMgr.repeatCount))
            )
        else:
            interval = SysMgr.intervalEnable
            repeat = SysMgr.repeatCount
            totalSec = convNum(interval)
            totalCnt = convNum(repeat)
            totalTime = convNum(long(interval * repeat))
            SysMgr.printInfo(
                "run only %s times in %s sec for a total of %s sec"
                % (totalCnt, totalSec, totalTime)
            )

    @staticmethod
    def reloadFileBuffer(path=None, retFd=False):
        # pylint: disable=no-member
        SysMgr.procBuffer = []

        # load raw data from the file #
        try:
            # get path #
            if path:
                pass
            elif SysMgr.printFd:
                path = SysMgr.printFd.name

                # close previous print fd #
                try:
                    SysMgr.printFd.close()
                    SysMgr.printFd = None
                except:
                    pass

                SysMgr.outPath = SysMgr.origOutPath

                # backup a exist output file #
                path = SysMgr.backupFile(path)
            else:
                SysMgr.printErr(
                    "failed to reload monitoring data because no target file"
                )
                return []

            # open file #
            if UtilMgr.isGzipFile(path):
                fd = SysMgr.getPkg("gzip", False).open(path, "r")
            else:
                fd = open(path, "r")

            # check fd option #
            if retFd:
                return fd

            # load data #
            buf = fd.read()

            # decode data #
            try:
                buf = buf.decode()
            except SystemExit:
                sys.exit(0)
            except:
                pass
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenErr(path)
            sys.exit(-1)

        # split each interval stats #
        try:
            buf = buf.replace("\n\n", "NEWSTAT\n\n")
            SysMgr.procBuffer = buf.split("NEWSTAT")

            if not path:
                SysMgr.printFd.seek(0, 0)
                SysMgr.printFd.truncate()
        except SystemExit:
            sys.exit(0)
        except:
            pass

        return SysMgr.procBuffer

    @staticmethod
    def addEnvironVar(name, value="SET"):
        SysMgr.environList.setdefault(name, [])
        if type(value) is list:
            SysMgr.environList[name] += value
        elif SysMgr.environList[name] and value == "SET":
            pass
        else:
            SysMgr.environList[name].append(value)

    @staticmethod
    def checkLogCond(log, cond):
        try:
            # check condition #
            if not cond or not UtilMgr.isValidStr(log, cond):
                return

            SysMgr.printWarn(
                "detected '%s' in %s" % (", ".join(cond), [log]), True
            )

            # execute watch commands #
            if "WATCHLOGCMD" in SysMgr.environList:
                args = SysMgr.environList["WATCHLOGCMD"]
                SysMgr.executeCommand(args)

            # check exit condition #
            if "WATCHLOGEXIT" in SysMgr.environList:
                os.kill(SysMgr.pid, signal.SIGINT)
                signal.pause()
        except SystemExit:
            sys.exit(0)
        except:
            pass

    @staticmethod
    def applyLimitVars(varList=[]):
        try:
            if not varList:
                varList = SysMgr.environList

            for item in ("LIMITCPU", "LIMITMEM", "LIMITREAD", "LIMITWRITE"):
                if not item in varList:
                    continue

                # set values #
                if item == "LIMITCPU":
                    res = "cpu"
                    name = "cfs_quota_us"
                    func = SysMgr.limitCpu
                elif item == "LIMITMEM":
                    res = "memory"
                    name = "limit_in_bytes"
                    func = SysMgr.limitMemory
                elif item == "LIMITREAD":
                    res = "I/O read"
                    name = "read_bps_device"
                    func = SysMgr.limitBlock
                elif item == "LIMITWRITE":
                    res = "I/O write"
                    name = "write_bps_device"
                    func = SysMgr.limitBlock
                else:
                    continue

                for limit in varList[item]:
                    # get target info #
                    limit = limit.split("@", 1)
                    if len(limit) == 1:
                        limit = limit[0]
                        targets = []
                    else:
                        limit, targets = limit

                    # get limit info #
                    values = limit.split(":")
                    if len(values) == 1:
                        val = UtilMgr.convUnit2Size(values[0])
                    elif len(values) == 2:
                        name, val = values
                        val = UtilMgr.convUnit2Size(val)
                    else:
                        SysMgr.printErr(
                            "failed to parse '%s' to limit %s" % (item, res)
                        )
                        sys.exit(-1)

                    # change %-per-sec to ms #
                    if item == "LIMITCPU":
                        unitSize = "%s%%" % val
                        val = long(val) * 10000
                    else:
                        unitSize = UtilMgr.convSize2Unit(val)

                    # set attributes #
                    attrs = [[name, val]]

                    SysMgr.printInfo("limit %s usage to %s" % (res, unitSize))

                    # get limit pids #
                    if targets:
                        pids = SysMgr.getTids(
                            targets,
                            isThread=not SysMgr.processEnable,
                            sibling=SysMgr.groupProcEnable,
                        )
                        if not pids:
                            continue

                        # set resource of specific tasks #
                        if "EACHTASK" in varList:
                            for pid in pids:
                                func([pid], attrs)
                        else:
                            func(pids, attrs)
                    else:
                        # limit resource of mine #
                        func([SysMgr.pid], attrs)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to apply %s limit values" % res, True)
            sys.exit(-1)

    @staticmethod
    def applyEnvironVars():
        def _applyVar(name, tobj, tvar):
            if not name in SysMgr.environList:
                return

            var = SysMgr.environList[name][0]
            if var.strip().isdigit():
                if hasattr(tobj, tvar):
                    setattr(tobj, tvar, long(var))
                else:
                    SysMgr.printErr("no %s in %s" % (tvar, tobj))
                    sys.exit(-1)
            else:
                SysMgr.printErr("wrong value %s for %s" % (var, name))
                sys.exit(-1)

        # set maximum top rank #
        if "NRTOPRANK" in SysMgr.environList:
            SysMgr.nrTopRank = UtilMgr.getEnvironNum("NRTOPRANK", isInt=True)

        # set kernel log size #
        if "NRKLOG" in SysMgr.environList:
            SysMgr.kmsgLine = UtilMgr.getEnvironNum("NRKLOG", isInt=True)

        def _setLogger(options):
            SysMgr.dltEnable = "d" in options
            SysMgr.kmsgEnable = "k" in options
            SysMgr.journalEnable = "j" in options
            SysMgr.syslogEnable = "s" in options
            if any(
                [
                    SysMgr.dltEnable,
                    SysMgr.kmsgEnable,
                    SysMgr.journalEnable,
                    SysMgr.syslogEnable,
                ]
            ):
                SysMgr.colorEnable = False
                return True
            else:
                return False

        # set operation logging #
        if "OPSLOG" in SysMgr.environList:
            options = SysMgr.environList["OPSLOG"][0]
            SysMgr.loggingOpsEnable = _setLogger(options)

        # set standard logging #
        if "STDLOG" in SysMgr.environList:
            options = SysMgr.environList["STDLOG"][0]
            SysMgr.loggingEnable = _setLogger(options)

        # ignore size unit converting #
        if "NOSIZEUNIT" in SysMgr.environList:
            UtilMgr.convSize2Unit = UtilMgr.convSize2UnitIgn

        convSize2Unit = UtilMgr.convSize2Unit
        convUnit2Size = UtilMgr.convUnit2Size

        # get limited dir info #
        if "LIMITDIR" in SysMgr.environList:
            for dirInfo in SysMgr.environList["LIMITDIR"]:
                # get target dir and limit size #
                try:
                    path, size = UtilMgr.cleanItem(
                        dirInfo.split(":", 1), union=False
                    )
                    if not path or not size:
                        continue
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(
                        "failed to get target dir info to be limited", True
                    )
                    continue

                # get limit size #
                try:
                    size = convSize2Unit(size)
                    if not size:
                        continue
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(
                        "failed to convert reclaim size '%s'" % size, True
                    )
                    sys.exit(-1)

                # register limit dir info #
                SysMgr.limitDirList[path] = size

        # get limited report dir info #
        if "LIMITREPDIR" in SysMgr.environList:
            try:
                size = convUnit2Size(SysMgr.environList["LIMITREPDIR"][0])
                SysMgr.limitRepDirSize = size
                SysMgr.printInfo(
                    "limit report directory to [%s]" % convSize2Unit(size)
                )
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "failed to get the limit size of report directory", True
                )
                sys.exit(-1)

        # register exit commands #
        if "EXITCMD" in SysMgr.environList:
            SysMgr.addExitFunc(
                SysMgr.executeCommand, [SysMgr.environList["EXITCMD"]]
            )

            SysMgr.printInfo(
                "registered exit commands '%s'"
                % ", ".join(SysMgr.environList["EXITCMD"])
            )

        # limit resources #
        SysMgr.applyLimitVars()

        # define threshold list #
        varList = [
            ("STARTCONDTIME", "startUptime"),
            ("STARTCONDCPUMORE", "startCondCpuMore"),
            ("STARTCONDCPULESS", "startCondCpuLess"),
            ("STARTCONDMEMMORE", "startCondMemMore"),
            ("STARTCONDMEMLESS", "startCondMemLess"),
            ("EXITCONDTIME", "deadlineUptime"),
            ("EXITCONDCPUMORE", "exitCondCpuMore"),
            ("EXITCONDCPULESS", "exitCondCpuLess"),
            ("EXITCONDMEMMORE", "exitCondMemMore"),
            ("EXITCONDMEMLESS", "exitCondMemLess"),
        ]

        # apply items #
        for item in varList:
            _applyVar(item[0], SysMgr, item[1])

        # wait for bigger CPU condition #
        if SysMgr.startCondCpuMore:
            SysMgr.waitForResource(
                cpuRes=SysMgr.startCondCpuMore, cpuCond="MORE"
            )

        # wait for lesser CPU condition #
        if SysMgr.startCondCpuLess:
            SysMgr.waitForResource(
                cpuRes=SysMgr.startCondCpuLess, cpuCond="LESS"
            )

        # wait for bigger memory condition #
        if SysMgr.startCondMemMore:
            SysMgr.waitForResource(
                memRes=SysMgr.startCondMemMore, memCond="MORE"
            )

        # wait for lesser memory condition #
        if SysMgr.startCondMemLess:
            SysMgr.waitForResource(
                memRes=SysMgr.startCondMemLess, memCond="LESS"
            )

    @staticmethod
    def checkOptVal(option, value):
        if not value:
            SysMgr.printErr("no input value with -%s option" % option)
            sys.exit(-1)

    @staticmethod
    def applySaveOption(value=None):
        # apply default path #
        if not value:
            value = "."

        # change output path #
        try:
            if not SysMgr.isWritable(value):
                raise Exception("not writable")

            if os.path.isdir(value):
                SysMgr.outputFile = "%s/guider.dat" % value
            else:
                SysMgr.outputFile = value
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("wrong path '%s'" % os.path.realpath(value), True)
            sys.exit(-1)

        # remove double slashes #
        SysMgr.outputFile = os.path.normpath(SysMgr.outputFile)

        # support no-report record mode #
        if SysMgr.checkMode("filerec") or SysMgr.checkMode("genrec"):
            if SysMgr.outputFile.endswith(".dat"):
                SysMgr.outPath = (
                    "%s.out" % os.path.splitext(SysMgr.outputFile)[0]
                )
            else:
                SysMgr.outPath = SysMgr.outputFile

    @staticmethod
    def removeOptionArgs():
        if len(sys.argv) < 3:
            return

        # find first option args #
        firstOptIdx = None
        for idx, item in enumerate(sys.argv):
            if item.startswith("-"):
                firstOptIdx = idx
                break

        # update args #
        if firstOptIdx:
            sys.argv = sys.argv[:firstOptIdx]

    @staticmethod
    def parseAnalOption(option=None):
        if not "ISMAIN" in os.environ:
            return

        # check call history #
        if not option and SysMgr.parsedAnalOption:
            return
        else:
            SysMgr.parsedAnalOption = True

        # set default processor option #
        if SysMgr.isTopMode():
            if SysMgr.findOption("a") or SysMgr.isDrawMode():
                SysMgr.cpuEnable = True
                SysMgr.gpuEnable = True
            else:
                SysMgr.cpuEnable = False

        # check argument count #
        if option:
            optionList = option.split()
            SysMgr.parseOption(optionList)
        elif len(sys.argv) <= 2:
            return
        else:
            optionList = None

        for item in SysMgr.optionList:
            if not item:
                continue

            option = item[0]
            value = item[1:].strip()

            if option == "i":
                # set default interval #
                if not value:
                    SysMgr.intervalEnable = 1
                    continue

                try:
                    SysMgr.intervalEnable = long(value)

                    if SysMgr.intervalEnable <= 0:
                        SysMgr.printErr(
                            (
                                "wrong value '%s' for interval, "
                                "input number bigger than 0"
                            )
                            % value
                        )
                        sys.exit(0)
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(
                        (
                            "wrong value '%s' for interval, "
                            "input number in integer format"
                        )
                        % value
                    )
                    sys.exit(-1)

            elif SysMgr.isCommonOption(option):
                SysMgr.parseCommonOption(option, value)

            elif option == "I":
                SysMgr.inputParam = value.strip()

            elif option == "w":
                SysMgr.checkOptVal(option, value)
                SysMgr.rcmdList = SysMgr.parseCustomRecordCmd(value)

            elif option == "a":
                SysMgr.printOptionWarn(option, value)
                SysMgr.showAll = True

            elif option == "P":
                SysMgr.printOptionWarn(option, value)
                SysMgr.groupProcEnable = True

            elif option == "p":
                SysMgr.checkOptVal(option, value)

                SysMgr.preemptGroup = UtilMgr.cleanItem(value.split(","))

            elif option == "Y":
                SysMgr.checkOptVal(option, value)
                if SysMgr.prio is None:
                    SysMgr.applyPriority(value)

            elif option == "J":
                SysMgr.printOptionWarn(option, value)
                SysMgr.jsonEnable = True

            elif option == "k":
                SysMgr.checkOptVal(option, value)
                if not SysMgr.isKillMode():
                    SysMgr.applyKillVal(value)

            elif option == "d":
                SysMgr.checkOptVal(option, value)
                options = value.replace(" ", "")

                if "b" in options:
                    SysMgr.bufferLossEnable = True

                if "p" in options:
                    SysMgr.printEnable = False

                if "u" in options:
                    SysMgr.userEnable = False

                if "c" in options:
                    SysMgr.cpuEnable = False

                if "C" in options:
                    SysMgr.cloneEnable = False

                if "B" in options:
                    SysMgr.barGraphEnable = False

                if "O" in options:
                    SysMgr.colorEnable = False

                if "E" in options:
                    SysMgr.execEnable = False

                if "x" in options:
                    SysMgr.eventHandleEnable = False

                if "t" in options:
                    SysMgr.truncEnable = False

                if "T" in options:
                    SysMgr.taskEnable = False

                if "e" in options:
                    SysMgr.encodeEnable = False

                if "a" in options:
                    SysMgr.freeMemEnable = True

                if "G" in options:
                    SysMgr.gpuEnable = False

                if "A" in options:
                    SysMgr.cpuAvgEnable = False

                if "L" in options:
                    SysMgr.logEnable = False

                if "g" in options:
                    SysMgr.generalEnable = False

                if "D" in options:
                    SysMgr.dwarfEnable = False

                if "l" in options:
                    SysMgr.latEnable = False

            elif option == "c":
                itemList = UtilMgr.splitString(value)

                # set union option #
                if SysMgr.isTraceMode() or SysMgr.checkMode("cli"):
                    union = False
                else:
                    union = True

                SysMgr.customCmd = UtilMgr.cleanItem(itemList, union=union)

            elif option == "g":
                itemList = UtilMgr.splitString(value)
                SysMgr.filterGroup = UtilMgr.cleanItem(itemList)

            elif "F" in option:
                SysMgr.checkOptVal(option, value)

                SysMgr.drawFormat = value.strip()

            elif option == "e":
                options = value.replace(" ", "")

                if "g" in options:
                    SysMgr.graphEnable = True

                if "D" in options:
                    SysMgr.dwarfEnable = True

                if "l" in options:
                    SysMgr.thresholdEnable = True

                if "t" in options:
                    SysMgr.processEnable = False

                if "H" in options:
                    if not SysMgr.checkMode("ttop"):
                        SysMgr.printErr(
                            "sched option is supported only in thread mode"
                        )
                        sys.exit(-1)
                    SysMgr.schedEnable = True

                if "Y" in options:
                    SysMgr.checkRootPerm()
                    SysMgr.delayEnable = True

                # no more options except for top mode #
                if not SysMgr.isTopMode():
                    continue

                if "T" in options:
                    SysMgr.totalEnable = True

                if "c" in options:
                    SysMgr.cpuEnable = True

                if "p" in options:
                    SysMgr.pipeEnable = True

                if "P" in options:
                    SysMgr.perfEnable = True
                    if SysMgr.findOption("g"):
                        SysMgr.perfGroupEnable = True

                if "i" in options:
                    SysMgr.irqEnable = True

                if "b" in options:
                    if SysMgr.checkDiskTopCond():
                        SysMgr.blockEnable = True
                    else:
                        sys.exit(-1)

                if "B" in options:
                    SysMgr.barGraphEnable = True

                if "s" in options:
                    if SysMgr.checkStackTopCond():
                        SysMgr.stackEnable = True
                    else:
                        sys.exit(-1)

                if "S" in options:
                    SysMgr.checkRootPerm()
                    SysMgr.pssEnable = True
                    SysMgr.sort = "m"

                if "u" in options:
                    SysMgr.checkRootPerm()
                    SysMgr.ussEnable = True
                    SysMgr.sort = "m"

                if "L" in options:
                    SysMgr.cmdlineEnable = True

                # check last field #
                if "a" in options:
                    TaskAnalyzer.setLastField("affinity")
                elif "o" in options:
                    TaskAnalyzer.setLastField("oom")
                elif "W" in options:
                    TaskAnalyzer.setLastField("wchan")
                elif "h" in options:
                    TaskAnalyzer.setLastField("signal")

                if "f" in options:
                    SysMgr.floatEnable = True

                    # set default interval to 3 for accuracy #
                    if not SysMgr.findOption("i") and not SysMgr.findOption(
                        "R"
                    ):
                        SysMgr.intervalEnable = 3

                if "F" in options:
                    SysMgr.wfcEnable = True

                if "R" in options:
                    SysMgr.reportEnable = True
                    SysMgr.reportFileEnable = True

                if "e" in options:
                    SysMgr.encodeEnable = True

                if "m" in options:
                    if SysMgr.checkMemTopCond():
                        SysMgr.memEnable = True
                    else:
                        sys.exit(-1)

                if "M" in options:
                    SysMgr.minStatEnable = True

                if "w" in options:
                    if SysMgr.checkWssTopCond():
                        SysMgr.memEnable = True
                        SysMgr.wssEnable = True
                        SysMgr.sort = "m"
                    else:
                        sys.exit(-1)

                if "n" in options:
                    SysMgr.networkEnable = True

                if "N" in options:
                    SysMgr.nsEnable = True

                if "P" in options:
                    if SysMgr.checkPerfTopCond():
                        SysMgr.perfEnable = True
                        if SysMgr.findOption("g"):
                            SysMgr.perfGroupEnable = True
                    else:
                        sys.exit(-1)

                if "r" in options:
                    SysMgr.reportEnable = True

                if "I" in options:
                    SysMgr.reportEnable = True
                    SysMgr.elasticEnable = True

                if "d" in options:
                    SysMgr.diskEnable = True

                if "E" in options:
                    SysMgr.execEnable = True

                if "G" in options:
                    SysMgr.cgroupEnable = True

                if "C" in options:
                    SysMgr.compressEnable = True

                if "q" in options:
                    SysMgr.exitFlag = True

                if "x" in options:
                    SysMgr.fixTargetEnable = True

                if not SysMgr.isValidEnableOption(options):
                    SysMgr.printErr(
                        "unrecognized option -%s to enable" % options
                    )
                    sys.exit(-1)

            elif option == "O":
                SysMgr.checkOptVal(option, value)

                # split core values #
                perCoreList = UtilMgr.cleanItem(value.split(","))
                if not perCoreList:
                    SysMgr.printErr("no input value for filter" % option)
                    sys.exit(-1)

                perCoreList = UtilMgr.convxrange(perCoreList)

                # check value type #
                for item in perCoreList:
                    if not item.isdigit():
                        SysMgr.printErr(
                            (
                                "wrong value for core list, "
                                "input number in integer format"
                            )
                            % option
                        )
                        sys.exit(-1)

                SysMgr.printInfo(
                    "only specific cores [ %s ] are shown"
                    % ", ".join(perCoreList)
                )

                # convert items to number #
                SysMgr.perCoreList = list(map(long, perCoreList))

                if SysMgr.isDrawMode():
                    SysMgr.perCoreDrawList = SysMgr.perCoreList
                    SysMgr.perCoreList = []

            # ignore below options for function mode #
            elif SysMgr.isFuncMode():
                SysMgr.functionEnable = True

            elif option == "l":
                # BOUNDARY #
                if SysMgr.isDrawMode():
                    SysMgr.boundaryLine = UtilMgr.cleanItem(value.split(","))

                    try:
                        cval = sorted(list(map(long, SysMgr.boundaryLine)))

                        SysMgr.printInfo(
                            "set boundary line [%s]"
                            % ", ".join(SysMgr.boundaryLine)
                        )

                        SysMgr.boundaryLine = cval
                    except SystemExit:
                        sys.exit(0)
                    except:
                        SysMgr.printErr(
                            "failed to convert [%s] to number"
                            % ", ".join(SysMgr.boundaryLine),
                            True,
                        )
                        sys.exit(-1)
                # LOG #
                else:
                    options = value
                    SysMgr.dltEnable = "d" in options
                    SysMgr.kmsgEnable = "k" in options
                    SysMgr.journalEnable = "j" in options
                    SysMgr.syslogEnable = "s" in options
                    if any(
                        [
                            SysMgr.dltEnable,
                            SysMgr.kmsgEnable,
                            SysMgr.journalEnable,
                            SysMgr.syslogEnable,
                        ]
                    ):
                        SysMgr.loggingEnable = True
                        SysMgr.colorEnable = False

            elif option == "r":
                if value.strip():
                    SysMgr.rootPath = value
                else:
                    SysMgr.recursionEnable = True

            elif option == "T":
                SysMgr.checkOptVal(option, value)

                if SysMgr.checkMode("convert"):
                    SysMgr.fontPath = value
                elif SysMgr.isDrawMode():
                    try:
                        SysMgr.nrTop = long(value)
                    except:
                        SysMgr.printErr(
                            (
                                "wrong value for the number of task, "
                                "input number in integer format"
                            )
                            % option
                        )
                        sys.exit(-1)
                # this value will be used in various mode #
                else:
                    try:
                        SysMgr.utilProc = long(value)
                    except:
                        pass

            elif option == "t" and not SysMgr.isRecordMode():
                syscallList = UtilMgr.cleanItem(value.split(","))
                enabledSyscall = []
                disabledSyscall = []

                for val in syscallList:
                    try:
                        if val.startswith("^"):
                            exceptFlag = True
                            val = val[1:]
                        else:
                            exceptFlag = False

                        # convert syscall name #
                        if not val.startswith("sys_") and not val.startswith(
                            "*"
                        ):
                            val = "sys_%s" % val

                        # get syscall index #
                        nrList = []
                        if "*" in val:
                            for idx, syscall in enumerate(ConfigMgr.sysList):
                                if UtilMgr.isValidStr(syscall, [val]):
                                    nrList.append(idx)
                        else:
                            nrList = [SysMgr.getNrSyscall(val)]

                        # classify syscall #
                        for nrSyscall in nrList:
                            if exceptFlag:
                                disabledSyscall.append(
                                    ConfigMgr.sysList[nrSyscall]
                                )
                            else:
                                enabledSyscall.append(
                                    ConfigMgr.sysList[nrSyscall]
                                )

                            if exceptFlag:
                                SysMgr.syscallExceptList.append(nrSyscall)
                            else:
                                SysMgr.syscallList.append(nrSyscall)
                    except SystemExit:
                        sys.exit(0)
                    except:
                        SysMgr.printErr(
                            "no %s syscall in %s ABI" % (val, SysMgr.arch)
                        )
                        sys.exit(-1)

                    # no syscall #
                    if syscallList and not SysMgr.syscallList:
                        SysMgr.printErr(
                            "no %s syscall in %s ABI" % (val, SysMgr.arch)
                        )
                        sys.exit(-1)

                # print logs #
                if not enabledSyscall:
                    SysMgr.printInfo("enabled syscall list [ ALL ]")
                else:
                    SysMgr.printInfo(
                        "enabled syscall list [ %s ]"
                        % ", ".join(enabledSyscall)
                    )

                if disabledSyscall:
                    SysMgr.printInfo(
                        "disabled syscall list [ %s ]"
                        % ", ".join(disabledSyscall)
                    )

            elif option == "m":
                try:
                    SysMgr.ttyEnable = True

                    if not value:
                        SysMgr.setTTYAuto()
                    else:
                        rows = cols = 0
                        term = value.split(":")

                        # get size #
                        term[0] = term[0].strip()
                        if term[0].isdigit():
                            rows = long(term[0])

                        if len(term) > 1:
                            term[1] = term[1].strip()
                            if term[1].isdigit():
                                cols = long(term[1])

                        # update system terminal #
                        if len(term) > 2 and term[2].upper() == "SYSTEM":
                            SysMgr.setTTY(rows, cols)
                        # update local terminal #
                        else:
                            if rows > 0:
                                SysMgr.ttyRows = rows
                            if cols > 0:
                                SysMgr.ttyCols = cols
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(
                        (
                            "wrong value for screen size, "
                            "input number in COLS:ROWS format"
                        )
                        % option,
                        reason=True,
                    )
                    sys.exit(-1)

            elif option == "b" and not SysMgr.isRecordMode():
                SysMgr.checkOptVal(option, value)
                try:
                    if value.isdigit():
                        bsize = long(value) << 10
                    else:
                        bsize = UtilMgr.convUnit2Size(value)

                    if bsize >= 0:
                        SysMgr.bufferSize = bsize
                    else:
                        SysMgr.printErr(
                            (
                                "wrong value %s for buffer size, "
                                "input number bigger than 0"
                            )
                            % option
                        )
                        sys.exit(0)
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(
                        (
                            "wrong value %s for buffer size, "
                            "input number in integer format"
                        )
                        % option
                    )
                    sys.exit(-1)

            elif option == "N":
                SysMgr.checkOptVal(option, value)
                networkList = UtilMgr.cleanItem(value.split(","))
                for item in networkList:
                    service, ip, port = NetworkMgr.parseAddr(item)
                    NetworkMgr.setRemoteNetwork(service, ip, port)

            elif option == "j":
                if not SysMgr.checkRepTopCond(value):
                    sys.exit(-1)

            elif option == "x":
                SysMgr.checkOptVal(option, value)
                service, ip, port = NetworkMgr.parseAddr(value)
                ret = NetworkMgr.setServerNetwork(ip, port, verb=True)
                if not ret:
                    sys.exit(-1)

            elif option == "X":
                if not SysMgr.findOption("x"):
                    service, ip, port = NetworkMgr.parseAddr(value)
                    NetworkMgr.setServerNetwork(None, None)

                NetworkMgr.setRemoteServer(value)

            elif option == "S":
                if not SysMgr.setSortValue(value):
                    sys.exit(-1)

            # Ignore options #
            elif SysMgr.isValidOption(option):
                continue

            else:
                SysMgr.printErr(
                    "unrecognized option -%s for analysis" % option
                )
                sys.exit(-1)

    @staticmethod
    def printOptionWarn(option, value):
        if not value:
            return

        SysMgr.printWarn("the %s option does not require value" % option, True)

    @staticmethod
    def parseCommonOption(option, value):
        if value:
            value = value.strip()

        if option == "f":
            SysMgr.printOptionWarn(option, value)
            SysMgr.forceEnable = True

        elif option == "L":
            if not value:
                SysMgr.printErr("no input value with -%s option" % option)
                sys.exit(-1)
            elif SysMgr.isDrawMode():
                SysMgr.layout = value
            elif not SysMgr.stdlog:
                if os.path.isdir(value):
                    value = os.path.join(value, "guider.log")
                SysMgr.printInfo("apply '%s' to log path" % value)
                SysMgr.stdlog = LogMgr(value)

        elif option == "o":
            # apply default path #
            if value == "":
                value = "."

            # check writable access #
            if not SysMgr.isWritable(value):
                SysMgr.printErr(
                    "wrong path '%s' for output because of permission" % value
                )
                sys.exit(-1)

            SysMgr.origOutPath = SysMgr.outPath = os.path.normpath(value)

        elif option == "s":
            SysMgr.applySaveOption(value)

        elif option == "H":
            try:
                if not value:
                    SysMgr.funcDepth = 32
                else:
                    SysMgr.funcDepth = long(value)

                if SysMgr.funcDepth < 0:
                    raise Exception("wrong depth")
            except:
                SysMgr.printErr(
                    "wrong input value for depth, "
                    "input an unsigned integer value"
                )
                sys.exit(-1)

        elif option == "Q":
            SysMgr.printOptionWarn(option, value)
            SysMgr.setStream()

        elif option == "q":
            SysMgr.checkOptVal(option, value)

            # NOTE: variables are already parsed in SysMgr.initEnvironment() #

            # apply environ variables #
            SysMgr.applyEnvironVars()

        elif option == "R":
            # set maximum count #
            if not value:
                value = str(sys.maxsize)
            SysMgr.parseRuntimeOption(value)

        elif option == "z":
            SysMgr.checkOptVal(option, value)
            SysMgr.parseAffinityOption(
                UtilMgr.cleanItem(value.split(",")), launch=True
            )

        elif option == "A":
            SysMgr.checkOptVal(option, value)
            SysMgr.archOption = value
            SysMgr.setArch(value)

        elif option == "W":
            # uptime deadline #
            if SysMgr.startUptime > 0:
                start = SysMgr.startUptime
                SysMgr.printStat(
                    "wait until %s seconds for uptime"
                    % (UtilMgr.convNum(start))
                )
                # wait until the uptime #
                SysMgr.waitUptime(start)
            elif value:
                if not SysMgr.waitEnable:
                    SysMgr.waitEnable = UtilMgr.convUnit2Time(value)
                    SysMgr.printStat(
                        "wait %s more seconds"
                        % (UtilMgr.convNum(SysMgr.waitEnable))
                    )
            else:
                SysMgr.waitEnable = True

        elif option == "C":
            if not ConfigMgr.confData:
                if value:
                    SysMgr.confFileName = os.path.realpath(value)
                else:
                    SysMgr.confFileName = os.path.realpath(SysMgr.confFileName)

                # load configuration #
                ret = SysMgr.loadConfig(SysMgr.confFileName)
                if SysMgr.isDrawMode():
                    pass
                elif not ret:
                    sys.exit(-1)

                # launch commands #
                cmdList = SysMgr.getConfigItem("command")
                if (
                    cmdList
                    and "apply" in cmdList
                    and cmdList["apply"] == "true"
                ):
                    SysMgr.executeCommand(cmdList["list"])

        elif option == "E":
            SysMgr.cacheDirPath = value
            SysMgr.printInfo("use '%s' as the cache directory" % value)

        elif option == "G":
            SysMgr.checkOptVal(option, value)
            itemList = UtilMgr.splitString(value)
            SysMgr.ignoreItemList = UtilMgr.cleanItem(itemList)
            SysMgr.printInfo(
                "applied ignore keyword [ %s ]"
                % ", ".join(SysMgr.ignoreItemList)
            )

        elif option == "u":
            SysMgr.printOptionWarn(option, value)
            SysMgr.runBackgroundMode()

    @staticmethod
    def isCommonOption(option):
        optionList = "ACEGHLQRWfoqsuz"
        if option in optionList:
            return True
        else:
            return False

    @staticmethod
    def parseRecordOption():
        if not "ISMAIN" in os.environ:
            return
        elif len(sys.argv) <= 2:
            return

        SysMgr.parseOption()

        for item in SysMgr.optionList:
            try:
                option = item[0]
                value = item[1:].strip()
            except:
                continue

            if option == "b":
                try:
                    if value.isdigit():
                        osize = bsize = long(value) << 10
                    else:
                        osize = UtilMgr.convUnit2Size(value)
                        bsize = osize >> 10

                    if bsize > 0:
                        SysMgr.bufferSize = bsize

                        SysMgr.printInfo(
                            "set buffer size to %s"
                            % UtilMgr.convSize2Unit(osize)
                        )
                    else:
                        SysMgr.printErr(
                            "wrong value for buffer size, "
                            "input number bigger than 0"
                        )
                        sys.exit(-1)
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(
                        "wrong value for buffer size, "
                        "input number in integer format"
                    )
                    sys.exit(-1)

            elif option == "Y":
                SysMgr.applyPriority(value)

            elif option == "e":
                options = value.replace(" ", "")

                if "i" in options:
                    SysMgr.irqEnable = True

                if "m" in options:
                    SysMgr.memEnable = True

                if "n" in options:
                    SysMgr.networkEnable = True

                if "h" in options:
                    SysMgr.heapEnable = True

                if "b" in options:
                    SysMgr.blockEnable = True

                if "p" in options:
                    SysMgr.pipeEnable = True

                if "P" in options:
                    SysMgr.powerEnable = True

                if "w" in options:
                    SysMgr.wqEnable = True

                if "B" in options:
                    SysMgr.binderEnable = True

                if "d" in options:
                    SysMgr.diskEnable = True

                if "o" in options:
                    SysMgr.iouringEnable = True

                if "k" in options:
                    SysMgr.kvmEnable = True

                if "I" in options:
                    SysMgr.i2cEnable = True

                if "f" in options:
                    SysMgr.fsEnable = True

                if "r" in options:
                    SysMgr.resetEnable = True

                if "g" in options:
                    SysMgr.graphEnable = True

                if "L" in options:
                    SysMgr.lockEnable = True

                if "c" in options:
                    SysMgr.cgroupEnable = True

                if "u" in options:
                    SysMgr.userEnable = True

                if not SysMgr.isValidEnableOption(options):
                    SysMgr.printErr(
                        "unrecognized option '%s' to enable" % options
                    )
                    sys.exit(-1)

            elif option == "g":
                itemList = UtilMgr.splitString(value)
                SysMgr.filterGroup = UtilMgr.cleanItem(itemList)
                if not SysMgr.filterGroup:
                    SysMgr.printErr("no input value for filter")
                    sys.exit(-1)

                SysMgr.printInfo(
                    "only specific threads [ %s ] are recorded"
                    % ", ".join(SysMgr.filterGroup)
                )

            elif option == "w":
                SysMgr.rcmdList = SysMgr.parseCustomRecordCmd(value)

            elif option == "U":
                SysMgr.ueventEnable = True
                itemList = UtilMgr.splitString(value)
                SysMgr.userCmd = UtilMgr.cleanItem(itemList)

            elif option == "K":
                SysMgr.keventEnable = True
                itemList = UtilMgr.splitString(value)
                SysMgr.kernelCmd = UtilMgr.cleanItem(itemList)

            elif option == "M":
                SysMgr.objdumpPath = value

                SysMgr.printInfo(
                    "use '%s' as the objdump path" % SysMgr.objdumpPath
                )

            elif option == "F":
                SysMgr.printOptionWarn(option, value)
                SysMgr.fileEnable = True

            elif option == "B":
                # get output path #
                if not value:
                    value = SysMgr.cmdFileName

                # change output path #
                try:
                    if not SysMgr.isWritable(value):
                        raise Exception("not writable")

                    if os.path.isdir(value):
                        SysMgr.cmdEnable = "%s/%s" % (
                            value,
                            SysMgr.cmdFileName,
                        )
                    else:
                        SysMgr.cmdEnable = value
                except:
                    SysMgr.printErr(
                        "wrong value for command script path" % value
                    )
                    sys.exit(-1)

                # remove double slashes #
                SysMgr.cmdEnable = os.path.normpath(SysMgr.cmdEnable)

            elif option == "t":
                SysMgr.sysEnable = True
                syscallList = UtilMgr.cleanItem(value.split(","))
                enabledSyscall = []

                for val in syscallList:
                    try:
                        # convert syscall name #
                        if not val.startswith("sys_") and not val.startswith(
                            "*"
                        ):
                            val = "sys_%s" % val

                        # get syscall index #
                        nrList = []
                        if "*" in val:
                            for idx, syscall in enumerate(ConfigMgr.sysList):
                                if UtilMgr.isValidStr(syscall, [val]):
                                    nrList.append(idx)
                        else:
                            nrList = [SysMgr.getNrSyscall(val)]

                        # classify syscall #
                        for nrSyscall in nrList:
                            enabledSyscall.append(ConfigMgr.sysList[nrSyscall])
                            SysMgr.syscallList.append(nrSyscall)
                    except SystemExit:
                        sys.exit(0)
                    except:
                        SysMgr.printErr(
                            "no %s syscall in %s ABI" % (val, SysMgr.arch)
                        )
                        sys.exit(-1)

                # no syscall #
                if syscallList and not SysMgr.syscallList:
                    SysMgr.printErr(
                        "no %s syscall in %s ABI" % (val, SysMgr.arch)
                    )
                    sys.exit(-1)

                # print logs #
                if not enabledSyscall:
                    SysMgr.printInfo("enabled syscall list [ ALL ]")
                else:
                    SysMgr.printInfo(
                        "enabled syscall list [ %s ]"
                        % ", ".join(enabledSyscall)
                    )

            elif SysMgr.isCommonOption(option):
                SysMgr.parseCommonOption(option, value)

            elif option == "c":
                itemList = UtilMgr.splitString(value)
                SysMgr.customCmd = UtilMgr.cleanItem(itemList)
                if not SysMgr.customCmd:
                    SysMgr.printErr("failed to recognize custom events")
                    sys.exit(-1)

            elif option == "d":
                options = value.replace(" ", "")

                if "c" in options:
                    SysMgr.cpuEnable = False
                    SysMgr.latEnable = False

                if "m" in options:
                    SysMgr.memEnable = False

                if "h" in options:
                    SysMgr.heapEnable = False

                if "b" in options:
                    SysMgr.blockEnable = False

                if "p" in options:
                    SysMgr.printEnable = False

                if "l" in options:
                    SysMgr.latEnable = False

                if "L" in options:
                    SysMgr.logEnable = False

                if "a" in options:
                    SysMgr.disableAll = True

                if "C" in options:
                    SysMgr.compressEnable = False

                if "g" in options:
                    SysMgr.generalEnable = False

            elif option == "D":
                SysMgr.printOptionWarn(option, value)
                SysMgr.depEnable = True

            # Ignore options #
            elif SysMgr.isValidOption(option):
                continue

            else:
                SysMgr.printErr(
                    "unrecognized option -%s for recording" % option
                )
                sys.exit(-1)

    @staticmethod
    def makeKerSymTable(symbol):
        try:
            restPath = "%s/sys/kernel/kptr_restrict" % SysMgr.procPath
            with open(restPath, "w+") as fd:
                fd.write("0")
        except SystemExit:
            sys.exit(0)
        except:
            pass

        try:
            symPath = "%s/kallsyms" % SysMgr.procPath
            f = open(symPath, "r")
        except IOError:
            SysMgr.printOpenWarn(symPath)
        except SystemExit:
            sys.exit(0)

        ret = None
        startPos = len(SysMgr.kerSymTable)
        curPos = 0

        while 1:
            line = f.readline()
            curPos += 1

            if startPos > curPos:
                continue

            # Cache address and symbol #
            line = line.split()
            SysMgr.kerSymTable[line[2]] = line[0]

            if line[2] == symbol:
                ret = line[0]
                break

        f.close()
        return ret

    @staticmethod
    def getKerAddr(symbol):
        try:
            return SysMgr.kerSymTable[symbol]
        except:
            return SysMgr.makeKerSymTable(symbol)

    @staticmethod
    def isRecordMode():
        if len(sys.argv) > 1 and sys.argv[1] in (
            "rec",
            "funcrec",
            "iorec",
            "sysrec",
            "filerec",
            "genrec",
        ):
            return True
        else:
            return False

    @staticmethod
    def isHelpMode():
        if len(sys.argv) > 1 and sys.argv[1] == "help":
            return True
        elif set(["-help", "--help", "-h"]) & set(sys.argv):
            return True
        else:
            return False

    @staticmethod
    def checkMode(mode, orig=False):
        # set target list #
        if orig:
            target = SysMgr.origArgs
        else:
            target = sys.argv

        # check value #
        if len(target) > 1 and target[1] == mode:
            return True
        else:
            return False

    @staticmethod
    def isKillMode():
        if len(sys.argv) < 2:
            return False
        elif sys.argv[1] in ("kill", "send", "tkill"):
            return True
        else:
            return False

    @staticmethod
    def isWritable(value):
        # file exist #
        if os.access(value, os.F_OK):
            if not os.access(value, os.W_OK):
                return False
        # no file exist #
        else:
            dirPath = os.path.dirname(value)
            if not dirPath:
                dirPath = "."

            # no dir exist #
            if not os.path.isdir(dirPath):
                return False
            # dir is not writable #
            elif not os.access(dirPath, os.W_OK):
                return False

        return True

    @staticmethod
    def isTopMode():
        if len(sys.argv) > 1 and sys.argv[1] in (
            "top",
            "atop",
            "bgtop",
            "btop",
            "cgtop",
            "ctop",
            "dbustop",
            "disktop",
            "dlttop",
            "ftop",
            "ktop",
            "mtop",
            "ntop",
            "ptop",
            "pytop",
            "rtop",
            "slabtop",
            "stacktop",
            "systop",
            "ttop",
            "utop",
            "vtop",
            "wtop",
        ):
            return True
        else:
            return False

    @staticmethod
    def isTraceMode():
        if len(sys.argv) > 1 and sys.argv[1] in (
            "strace",
            "utrace",
            "btrace",
            "remote",
            "pytrace",
            "leaktrace",
            "sigtrace",
        ):
            return True
        else:
            return False

    @staticmethod
    def isRuntimeMode():
        if (
            SysMgr.isRecordMode()
            or SysMgr.isTopMode()
            or SysMgr.isTraceMode()
            or SysMgr.checkMode("req")
        ):
            return True

        return False

    @staticmethod
    def checkCmdMode():
        # parse options #
        SysMgr.parseAnalOption()

        # set tty setting automatically #
        if not SysMgr.ttyEnable:
            SysMgr.setTTYAuto(True, False, False)

        # wait for input #
        if SysMgr.waitEnable:
            SysMgr.waitUserInput(SysMgr.waitEnable, msg="DEFAULT", force=True)

        # LIST MODE #
        if SysMgr.checkMode("list"):
            SysMgr.setStream(not SysMgr.streamEnable)
            SysMgr.printBgProcs()

        # SERVER MODE #
        elif SysMgr.checkMode("server"):
            SysMgr.runServerMode()

        # CLIENT MODE #
        elif SysMgr.checkMode("cli"):
            SysMgr.runClientMode()

        # START / STOP MODE #
        elif SysMgr.checkMode("start") or SysMgr.checkMode("stop"):
            # make list of arguments #
            if len(sys.argv) > 2:
                argList = sys.argv[2:]
            else:
                argList = None

            SysMgr.sendSignalProcs(signal.SIGINT, argList)

        # KILL MODE #
        elif SysMgr.isKillMode():
            # make list of arguments #
            if len(sys.argv) > 2:
                argList = sys.argv[2:]
            else:
                argList = [" "]

            # remove additional options #
            if len(argList) > 1:
                idx = 0
                for idx, item in enumerate(argList[1:]):
                    if item.strip().startswith("-"):
                        break

                if argList[-1].strip().startswith("-"):
                    argList = argList[: idx + 1]
                else:
                    argList = argList[: idx + 2]

            # print signal list #
            if SysMgr.findOption("l"):
                for idx, sig in enumerate(ConfigMgr.SIG_LIST):
                    if idx == 0:
                        continue
                    elif idx % 5 == 0:
                        newline = True
                    else:
                        newline = False

                    SysMgr.printPipe(
                        "{0:>2}) {1:<12}".format(idx, sig), newline=newline
                    )

                sys.exit(0)

            while 1:
                # set target type #
                if SysMgr.checkMode("tkill"):
                    isThread = True
                else:
                    isThread = False

                # send signal #
                SysMgr.sendSignalArgs(list(argList), isThread=isThread)

                # check interval #
                if SysMgr.intervalEnable:
                    time.sleep(SysMgr.intervalEnable)
                else:
                    break

        # TOPDIFF MODE #
        elif SysMgr.checkMode("topdiff"):
            # remove option args #
            SysMgr.removeOptionArgs()

            # get file list #
            if SysMgr.hasMainArg():
                argList = SysMgr.getMainArg().split(",")
                argList = UtilMgr.getFileList(argList)
            else:
                argList = None

            SysMgr.printLogo(big=True, onlyFile=True)

            TaskAnalyzer.doDiffReports(argList)

        # TOPSUM MODE #
        elif SysMgr.checkMode("topsum"):
            # check input #
            if SysMgr.hasMainArg():
                inputArg = SysMgr.getMainArgs()
            elif SysMgr.inputParam:
                inputArg = str(SysMgr.inputParam).split(",")
                inputArg = UtilMgr.cleanItem(inputArg, True)
            else:
                SysMgr.printErr("no input for PATH")
                sys.exit(-1)

            # convert input files #
            inputArg = UtilMgr.getFileList(inputArg, sort=True, exceptDir=True)

            TaskAnalyzer.doSumReport(inputArg)

        # PAUSE MODE #
        elif SysMgr.checkMode("pause"):
            # get target list #
            if SysMgr.hasMainArg():
                targets = SysMgr.getMainArgs()
            else:
                targets = SysMgr.filterGroup

            if not targets:
                SysMgr.printErr("no input value for COMM or TID")
                sys.exit(-1)

            targetList = []
            sibling = SysMgr.groupProcEnable

            # convert comm to tid #
            targetList = SysMgr.convTaskList(
                targets, isThread=True, exceptMe=True, sibling=sibling
            )
            targetList = list(set(targetList))

            # check target list #
            if not targetList:
                SysMgr.printErr("no task related to '%s'" % ", ".join(targets))
                sys.exit(-1)

            Debugger.pauseThreads(targetList)

        # READELF MODE #
        elif SysMgr.checkMode("readelf"):
            # get path #
            if SysMgr.hasMainArg():
                path = SysMgr.getMainArg()
            elif SysMgr.inputParam:
                path = SysMgr.inputParam
            else:
                SysMgr.printErr("no input value for path")
                sys.exit(-1)

            SysMgr.printLogo(big=True, onlyFile=True)

            # set debug flag #
            if SysMgr.jsonEnable:
                debug = False
            else:
                debug = True

            # run ELF analyzer #
            try:
                if path == "vdso":
                    obj = SysMgr.getVDSO(debug=debug)
                else:
                    obj = ElfAnalyzer(path, debug, incArg=True)

                if SysMgr.jsonEnable:
                    jsonStr = UtilMgr.convDict2Str(
                        obj.attr, pretty=not SysMgr.streamEnable
                    )
                    SysMgr.printPipe(jsonStr)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("failed to analyze '%s'" % path, True)

        # LEAKTRACE MODE #
        elif SysMgr.checkMode("leaktrace"):
            SysMgr.doLeaktrace()

        # ADDR2SYM MODE #
        elif SysMgr.checkMode("addr2sym"):
            SysMgr.doAddr2sym()

        # SYM2ADDR MODE #
        elif SysMgr.checkMode("sym2addr"):
            SysMgr.doSym2addr()

        # MKCACHE MODE #
        elif SysMgr.checkMode("mkcache"):
            SysMgr.doMkCache()

        # READAHEAD MODE #
        elif SysMgr.checkMode("readahead"):
            # get list path #
            if SysMgr.hasMainArg():
                path = SysMgr.getMainArg(path=True)
            elif SysMgr.inputParam:
                path = SysMgr.inputParam
            else:
                path = "readahead.list"

            SysMgr.doReadahead(path)

        # PRINTEXT MODE #
        elif SysMgr.checkMode("printext"):
            SysMgr.doPrintExt()

        # PRINTDIR MODE #
        elif SysMgr.checkMode("printdir"):
            SysMgr.printLogo(big=True, onlyFile=True)

            # get start dir #
            if SysMgr.hasMainArg():
                rootList = SysMgr.getMainArgs()
            elif SysMgr.inputParam:
                rootList = SysMgr.inputParam.split(",")
                rootList = UtilMgr.cleanItem(rootList, True)
            else:
                rootList = ["."]

            # get depth #
            if not SysMgr.funcDepth:
                maxLevel = -1
            else:
                maxLevel = SysMgr.funcDepth

            # start printing dirs #
            for root in rootList:
                SysMgr.printDirs(root, maxLevel)

        # PRINTCGROUP MODE #
        elif SysMgr.checkMode("printcg"):
            SysMgr.cgroupEnable = True
            SysMgr().printCgroupInfo(printTitle=False)
            SysMgr.printInfoBuffer()

        # LOGJRL MODE #
        elif SysMgr.checkMode("logjrl"):
            SysMgr.doLogMode("journal")

        # LOGDLT MODE #
        elif SysMgr.checkMode("logdlt"):
            SysMgr.doLogMode("dlt")

        # LOGKMSG MODE #
        elif SysMgr.checkMode("logkmsg"):
            SysMgr.doLogMode("kmsg")

        # LOGSYS MODE #
        elif SysMgr.checkMode("logsys"):
            SysMgr.doLogMode("syslog")

        # PRINTDBUS MODE #
        elif SysMgr.checkMode("printdbus"):
            # set console info #
            SysMgr.setStream()

            SysMgr.printLogo(big=True, onlyFile=True)

            DbusMgr.runDbusSnooper(mode="print")

        # PRINTDBUSSTAT MODE #
        elif SysMgr.checkMode("printdbusstat"):
            SysMgr.printLogo(big=True, onlyFile=True)

            DbusMgr.runDbusSnooper(mode="printstat")

        # PRINTDBUSINTRO MODE #
        elif SysMgr.checkMode("printdbusintro"):
            SysMgr.printLogo(big=True, onlyFile=True)

            DbusMgr.runDbusSnooper(mode="printintro")

        # PRINTDBUSSUB MODE #
        elif SysMgr.checkMode("printdbussub"):
            SysMgr.printLogo(big=True, onlyFile=True)

            DbusMgr.runDbusSnooper(mode="signal")

        elif SysMgr.isPrintLogMode():
            # set console info #
            SysMgr.setStream(cut=False)

            # get console option #
            console = SysMgr.findOption("Q")

            # set alarm handler #
            if SysMgr.intervalEnable > 0:
                signal.signal(signal.SIGALRM, SysMgr.onAlarm)
                signal.alarm(SysMgr.intervalEnable)

            SysMgr.printLogo(big=True, onlyFile=True)

            # PRINTSYSLOG MODE #
            if SysMgr.checkMode("printsys"):
                LogMgr.printSyslog(console)

            # PRINTKMSG MODE #
            elif SysMgr.checkMode("printkmsg"):
                LogMgr.printKmsg(console)

            # PRINTJRL MODE #
            elif SysMgr.checkMode("printjrl"):
                LogMgr.printJournal(console)

            # PRINTDLT MODE #
            elif SysMgr.checkMode("printdlt"):
                DltAnalyzer.runDltReceiver(mode="print")

        # PRINTSIG MODE #
        elif SysMgr.checkMode("printsig"):
            SysMgr.doPrintSig()

        # PAGE MODE #
        elif SysMgr.checkMode("mem"):
            SysMgr.printLogo(big=True, onlyFile=True)

            # check input #
            if SysMgr.hasMainArg():
                target = SysMgr.getMainArgs(union=False)
            else:
                target = SysMgr.filterGroup

            PageAnalyzer.getPageInfo(target, SysMgr.inputParam)

        # LIMIT MODE #
        elif SysMgr.isLimitMode():
            # change the CPU scheduling priority for tasks #
            if SysMgr.prio is None:
                SysMgr.setPriority(SysMgr.pid, "C", -20)

            # get argument #
            if SysMgr.hasMainArg():
                filterGroup = SysMgr.getMainArgs()
            else:
                filterGroup = SysMgr.filterGroup

            if SysMgr.checkMode("limitcpu"):
                limitInfo = SysMgr.getLimitCpuInfo(filterGroup)

                SysMgr.doLimitCpu(limitInfo, SysMgr.processEnable)

        # PSTREE MODE #
        elif SysMgr.checkMode("pstree"):
            # get target #
            if SysMgr.hasMainArg():
                targets = SysMgr.getMainArgs()
            else:
                targets = None

            SysMgr.doPstree(targets=targets)

        # COMP MODE #
        elif SysMgr.checkMode("comp"):
            try:
                SysMgr.doCompress()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("failed to compress", True)

        # DECOMP MODE #
        elif SysMgr.checkMode("decomp"):
            try:
                SysMgr.doDecompress()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("failed to decompress", True)

        # PS MODE #
        elif SysMgr.checkMode("systat"):
            SysMgr.doSystat()

        # DRAWTIMELINE MODE #
        elif SysMgr.checkMode("drawtime"):
            SysMgr.doDrawTimeline()

        # CPUTEST MODE #
        elif SysMgr.checkMode("cputest"):
            SysMgr.setStream()

            SysMgr.doCpuTest()

        # IOTEST MODE #
        elif SysMgr.checkMode("iotest"):
            SysMgr.doIoTest()

        # NETTEST MODE #
        elif SysMgr.checkMode("nettest"):
            SysMgr.doNetTest()

        # MEMTEST MODE #
        elif SysMgr.checkMode("memtest"):
            # remove option args #
            SysMgr.removeOptionArgs()

            SysMgr.setStream(cut=False)

            SysMgr.doMemTest()

        # FLUSH MODE #
        elif SysMgr.checkMode("flush"):
            SysMgr.doFlush()

        # EXEC MODE #
        elif SysMgr.checkMode("exec"):
            # check config file #
            if SysMgr.findOption("C"):
                # search config file #
                SysMgr.updateConfigPath()

                # load config file #
                if ConfigMgr.confData:
                    pass
                elif not SysMgr.loadConfig(SysMgr.confFileName):
                    sys.exit(-1)

            SysMgr.doExec()

        # REQUEST MODE #
        elif SysMgr.checkMode("req"):
            SysMgr.setStream()

            SysMgr.printLogo(big=True, onlyFile=True)

            SysMgr.doRequest()

        # SETCPU MODE #
        elif SysMgr.checkMode("setcpu"):
            # remove option args #
            SysMgr.removeOptionArgs()

            SysMgr.doSetCpu()

        # SETSCHED MODE #
        elif SysMgr.checkMode("setsched"):
            SysMgr.doSetSched()

        # RLIMIT MODE #
        elif SysMgr.checkMode("rlimit"):
            SysMgr.doRlimit()

        # CONVERT MODE #
        elif SysMgr.checkMode("convert"):
            SysMgr.doConvert()

        # DRAWREQ MODE #
        elif SysMgr.checkMode("drawreq"):
            SysMgr.doDrawReq()

        # MOUNT MODE #
        elif SysMgr.checkMode("mount"):
            SysMgr.doMount()

        # UNMOUNT MODE #
        elif SysMgr.checkMode("umount"):
            SysMgr.doUnmount()

        # STRINGS MODE #
        elif SysMgr.checkMode("strings"):
            SysMgr.setStream(cut=False)

            SysMgr.doStrings()

        # PRINT MODE #
        elif SysMgr.checkMode("print"):
            SysMgr.doPrintFile()

        # DUMP MODE #
        elif SysMgr.checkMode("dump"):
            SysMgr.doDump()

        # STRACE MODE #
        elif SysMgr.checkMode("strace"):
            # just print syscall list #
            if SysMgr.findOption("l"):
                SysMgr.setStream()

                lineLen = 0
                for idx, item in enumerate(ConfigMgr.sysList):
                    if item == "sys_null":
                        continue
                    elif lineLen + len(item) > SysMgr.ttyCols / 2:
                        newline = True
                        lineLen = 0
                    else:
                        newline = False
                        lineLen += len(item) + 5

                    SysMgr.printPipe(
                        "%3s) %s  " % (idx, UtilMgr.lstrip(item, "sys_")),
                        newline=newline,
                    )

                SysMgr.printPipe()
                sys.exit(0)

            SysMgr.doTrace("syscall")

        # UTRACE MODE #
        elif SysMgr.checkMode("utrace"):
            SysMgr.doTrace("usercall")

        # REMOTE MODE #
        elif SysMgr.checkMode("remote"):
            SysMgr.doTrace("remote")

        # HOOK MODE #
        elif SysMgr.checkMode("hook"):
            SysMgr.doTrace("hook")

        # HOOK MODE #
        elif SysMgr.checkMode("printbind"):
            SysMgr.doTrace("bind")

        # BTRACE MODE #
        elif SysMgr.checkMode("btrace"):
            SysMgr.doTrace("breakcall")

        # PYTRACE MODE #
        elif SysMgr.checkMode("pytrace"):
            SysMgr.doTrace("pytrace")

        # WATCH MODE #
        elif SysMgr.checkMode("watch"):
            SysMgr.doWatch()

        # SIGTRACE MODE #
        elif SysMgr.checkMode("sigtrace"):
            SysMgr.doTrace("signal")

        # PRINTENV MODE #
        elif SysMgr.checkMode("printenv"):
            SysMgr.doPrintEnv()

        # PRINTSLAB MODE #
        elif SysMgr.checkMode("printslab"):
            SysMgr.doPrintSlab()

        # PRINTVMALLOC MODE #
        elif SysMgr.checkMode("printvma"):
            SysMgr.doPrintVmalloc()

        # PRINTKCONF MODE #
        elif SysMgr.checkMode("printkconf"):
            SysMgr.doPrintKconf()

        # PRINTNS MODE #
        elif SysMgr.checkMode("printns"):
            SysMgr.doPrintNs()

        # PRINTSVC MODE #
        elif SysMgr.checkMode("printsvc"):
            SysMgr.doPrintSvc()

        # PRINTINFO MODE #
        elif SysMgr.checkMode("printinfo"):
            SysMgr.doPrintInfo()

        # SETAFFINITY MODE #
        elif SysMgr.checkMode("setafnt"):
            SysMgr.doSetAffinity()

        # GETAFFINITY MODE #
        elif SysMgr.checkMode("getafnt"):
            SysMgr.doGetAffinity()

        # CGROUP MODE #
        elif SysMgr.checkMode("cgroup"):
            # set console info #
            SysMgr.setStream()

            SysMgr.doCgroup()

        # FREEZE MODE #
        elif SysMgr.checkMode("freeze"):
            SysMgr.doFreeze()

        # PING MODE #
        elif SysMgr.checkMode("ping"):
            SysMgr.setStream()
            SysMgr.ping()

        # EVENT MODE #
        elif SysMgr.checkMode("event"):
            SysMgr.handleEventInput()

        else:
            return

        sys.exit(0)

    @staticmethod
    def isLimitMode():
        if SysMgr.checkMode("limitcpu"):
            return True
        else:
            return False

    @staticmethod
    def isDrawAvgMode():
        if len(SysMgr.origArgs) > 1 and SysMgr.origArgs[1] in (
            "drawavg",
            "drawcpuavg",
            "drawmemavg",
            "drawvssavg",
            "drawrssavg",
        ):
            return True
        else:
            return False

    @staticmethod
    def isDrawMode():
        orig = SysMgr.drawMode
        SysMgr.drawMode = True

        if len(sys.argv) == 1:
            return False
        elif sys.argv[1] == "draw" or orig:
            return True
        elif len(SysMgr.origArgs) > 1 and SysMgr.origArgs[1] in (
            "drawcpu",
            "drawdelay",
            "drawflame",
            "drawbitmap",
            "drawmem",
            "drawvss",
            "drawrss",
            "drawleak",
            "drawio",
            "drawtime",
        ):
            return True
        elif SysMgr.isDrawAvgMode():
            return True
        else:
            SysMgr.drawMode = orig
            return False

    @staticmethod
    def isPrintLogMode():
        if len(sys.argv) > 1 and sys.argv[1] in (
            "printsys",
            "printkmsg",
            "printjrl",
            "printdlt",
        ):
            return True
        else:
            return False

    @staticmethod
    def checkPerfTopCond():
        # check root permission #
        if not SysMgr.checkRootPerm(exit=False, msg="use PMU"):
            return False
        elif not os.path.isfile(
            "%s/sys/kernel/perf_event_paranoid" % SysMgr.procPath
        ):
            SysMgr.printErr("failed to use PMU, please check kernel config")
            return False
        else:
            return True

    @staticmethod
    def checkMemTopCond():
        if not SysMgr.checkRootPerm(exit=False, msg="analyze memory details"):
            return False
        else:
            return True

    @staticmethod
    def checkBgTopCond():
        if SysMgr.outPath:
            return True

        logPath = "/var/log"
        tmpPath = SysMgr.tmpPath

        if os.path.isdir(logPath) and os.access(logPath, os.W_OK):
            SysMgr.outPath = logPath
            return True
        elif os.path.isdir(tmpPath) and os.access(tmpPath, os.W_OK):
            SysMgr.outPath = tmpPath
            return True
        else:
            SysMgr.printErr("failed to get path to save output, use -o option")
            return False

    @staticmethod
    def checkRepTopCond(val=None, ignore=True):
        # check whether report option is already enabled #
        if SysMgr.reportEnable:
            return True

        if SysMgr.streamEnable:
            SysMgr.reportObject = sys.stdout
            reportPath = SysMgr.nullPath
        else:
            # ignore printing text-based stats #
            if ignore and not "TEXTREPORT" in SysMgr.environList:
                SysMgr.printEnable = False

            # check stdout report option #
            if not val:
                reportPath = SysMgr.getOption("j")
            else:
                reportPath = val

            # check report path #
            if not reportPath or not reportPath:
                reportPath = SysMgr.tmpPath

            # check report directory #
            if not os.path.isdir(reportPath):
                upDirPos = reportPath.rfind("/")
                if upDirPos > 0 and not os.path.isdir(reportPath[:upDirPos]):
                    SysMgr.printErr(
                        "wrong path '%s' to report stats" % reportPath
                    )
                    return False
            # check report file #
            else:
                reportPath = "%s/guider.report" % reportPath

            # remove redundant slashes and save it as the global report path #
            reportPath = os.path.normpath(reportPath)

            # backup a exist output file #
            SysMgr.backupFile(reportPath)

            # open report file #
            try:
                if SysMgr.truncEnable:
                    perm = "w"
                else:
                    perm = "a"

                SysMgr.reportObject = open(reportPath, perm)
                os.chmod(reportPath, 0o777)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenErr(reportPath)
                sys.exit(-1)

        # report option is enabled #
        SysMgr.reportEnable = True

        SysMgr.printInfo(
            "start writing report in JSON format to '%s'" % reportPath
        )

        return True

    @staticmethod
    def checkWssTopCond():
        if not SysMgr.hasMainArg() and not SysMgr.filterGroup:
            SysMgr.printErr("no target task")
            return False
        elif not SysMgr.checkRootPerm(exit=False, msg="clear refcnts"):
            return False
        else:
            return True

    @staticmethod
    def checkIdlePageCond():
        if os.path.exists("/sys/kernel/mm/page_idle/bitmap"):
            return True

        # check kernel version #
        ver = float(".".join(SysMgr.getKernelVersion().split(".")[0:2]))
        if ver < 4.3:
            SysMgr.printErr(
                (
                    "failed to use Idle Page Tracking "
                    "because kernel version %s is lesser than 4.3"
                )
                % UtilMgr.convFloat2Str(ver)
            )
        else:
            SysMgr.printErr(
                "failed to use Idle Page Tracking, "
                "please check kernel CONFIG_IDLE_PAGE_TRACKING"
            )

        return False

    @staticmethod
    def checkDiskTopCond():
        if SysMgr.forceEnable:
            return True

        procPath = SysMgr.procPath
        if SysMgr.isLinux:
            if not SysMgr.checkRootPerm(
                exit=False, msg="analyze block I/O for tasks"
            ):
                return False
            elif not os.path.isfile("%s/self/io" % procPath):
                SysMgr.printErr(
                    "failed to use bio event to analyze block I/O for tasks, "
                    "please check kernel configs"
                )
                return False
        return True

    @staticmethod
    def checkStackTopCond():
        if SysMgr.forceEnable:
            return True
        elif not SysMgr.checkRootPerm(exit=False, msg="collect stacks"):
            return False
        elif not os.path.isfile("%s/self/stack" % SysMgr.procPath):
            SysMgr.printErr(
                "failed to sample stack, please check kernel configs"
            )
            return False
        else:
            return True

    @staticmethod
    def convCIDR(addr):
        if addr in SysMgr.ipAddrCache:
            return SysMgr.ipAddrCache[addr]

        addrList = []

        # slice last 64bits for IPv6 #
        try:
            addr = addr[-8:]
        except:
            pass

        # check 0 #
        if long(addr, 16) == 0:
            retval = "*"
        else:
            # convert IP #
            splitAddr = [addr[i : i + 2] for i in xrange(0, len(addr), 2)]
            for num in reversed(splitAddr):
                addrList.append(str(long(num, base=16)))

            # build IP string #
            retval = ".".join(addrList)

        # cache result #
        SysMgr.ipAddrCache[addr] = retval

        return retval

    @staticmethod
    def mountDebugfs(mp=None):
        if not mp:
            mp = SysMgr.debugfsPath

        # check root permission #
        SysMgr.checkRootPerm(msg="mount debugfs")

        # mount debugfs #
        SysMgr.mountCmd = "mount -t debugfs nodev %s 2> /dev/null" % mp
        os.system(SysMgr.mountCmd)

        # check debugfs #
        SysMgr.mountPath = SysMgr.getDebugfsPath()
        if not SysMgr.mountPath:
            SysMgr.printErr("failed to mount debugfs to trace events")
            sys.exit(-1)

    @staticmethod
    def handleEventInput():
        def _sendEvent(event, ip, port):
            # get uptime #
            uptime = SysMgr.getUptime()

            # convert event name #
            for idx, item in enumerate(list(event)):
                if not item.startswith("EVENT_"):
                    event[idx] = "EVENT_%s" % item

            # create a network object #
            networkObject = NetworkMgr("client", ip, long(port))
            ip = networkObject.ip
            port = networkObject.port

            # check network object #
            if not ip or not port:
                SysMgr.printWarn(
                    "failed to use '%s:%s' as the remote address" % (ip, port)
                )
                return

            # send events #
            for item in event:
                try:
                    networkObject.request = item
                    networkObject.send("%s@%s" % (item, uptime))
                    SysMgr.printInfo(
                        "sent event '%s' to %s:%s" % (item, ip, port)
                    )
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printWarn(
                        "failed to send event '%s' to %s:%s"
                        % (item, ip, port),
                        True,
                    )

        # get event #
        if SysMgr.hasMainArg():
            event = SysMgr.getMainArgs(False)
        elif SysMgr.inputParam:
            event = SysMgr.inputParam.split(",")
            event = UtilMgr.cleanItem(event, False)
        else:
            event = None

        # mount debug fs #
        SysMgr.mountPath = SysMgr.getDebugfsPath()
        if not SysMgr.mountPath:
            SysMgr.printWarn("failed to get debugfs mount point", True)

        # check target address #
        if SysMgr.remoteServObj:
            # use default address #
            if SysMgr.remoteServObj == "NONE":
                ip = SysMgr.localServObj.ip
                port = SysMgr.defaultServPort
            else:
                ip = SysMgr.remoteServObj.ip
                port = SysMgr.remoteServObj.port
        else:
            ip = port = None

            # check root permission #
            SysMgr.checkRootPerm(
                msg="send event, try to use the target address"
            )

        # convert pid #
        try:
            if not ip:
                target = list(set(list(map(long, SysMgr.filterGroup))))
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to get PID '%s' for Guider processes"
                % ", ".join(SysMgr.filterGroup),
                True,
            )
            sys.exit(-1)

        # oneshot #
        if event:
            for item in event:
                SysMgr.writeEvent("EVENT_%s" % item)

            # deliver events to specific address #
            if ip:
                _sendEvent(event, ip, port)
            # deliver events to specific processes #
            else:
                SysMgr.broadcastEvent(event, target)

            return

        while 1:
            SysMgr.printStat("input event name... [ STOP(Ctrl+c) ]")

            # get events from user input #
            try:
                event = sys.stdin.readline().strip()
            except SystemExit:
                sys.exit(0)
            except:
                continue

            # convert events #
            if event:
                event = UtilMgr.cleanItem(event.split(","), False)
            else:
                event = ["USER"]

            # deliver events to specific address #
            if ip:
                _sendEvent(event, ip, port)
            # deliver events to specific processes #
            else:
                SysMgr.broadcastEvent(event, target)

    @staticmethod
    def getSocketAddrList(addrList):
        portList = []

        # get udp list #
        portList += SysMgr.getUdpList(addrList)

        # get tcp list #
        portList += SysMgr.getTcpList(addrList)

        return list(set(portList))

    @staticmethod
    def getProcSocketObjs(pid):
        socketAddrList = []
        fdlistPath = "%s/%s/fd" % (SysMgr.procPath, pid)

        # save file info per process #
        try:
            fdlist = os.listdir(fdlistPath)
        except:
            SysMgr.printOpenWarn(fdlistPath)
            return socketAddrList

        # save fd info of process #
        for fd in fdlist:
            try:
                long(fd)
            except:
                continue

            try:
                # add file info into fdList #
                fdPath = "%s/%s" % (fdlistPath, fd)
                filename = os.readlink(fdPath)

                if filename.startswith("socket"):
                    socketAddrList.append(filename.split("[")[1][:-1])
            except:
                SysMgr.printOpenWarn(fdPath)

        return socketAddrList

    @staticmethod
    def getProcNetAddrs(name):
        if not SysMgr.isLinux or not name:
            return None

        # get pids #
        pids = SysMgr.getProcPids(name)

        # get only Guider server processes #
        if len(pids) > 1 and name == __module__:
            servers = []
            for pid in pids:
                try:
                    cmdline = SysMgr.getCmdline(pid).split()
                    if len(cmdline) > 2 and cmdline[2] == "server":
                        servers.append(pid)
                except:
                    SysMgr.printWarn(
                        "failed to get cmdline for %s(%s)"
                        % (pid, SysMgr.getComm(pid, cache=True)),
                        True,
                    )
            pids = servers

        # get target network info #
        if len(pids) == 1:
            # get socket objects #
            objs = SysMgr.getProcSocketObjs(pids[0])

            # get bind address #
            addrs = SysMgr.getSocketAddrList(objs)
            if not addrs:
                SysMgr.printWarn(
                    "failed to get socket attribute of server", True
                )
                return None

            # get server address #
            addr = addrs[0]

            return addr[addr.find(">") + 1 :]
        elif len(pids) > 1:
            SysMgr.printWarn(
                "Found multiple running %s processes" % name, True
            )
            SysMgr.printBgProcs(cache=True)
        else:
            SysMgr.printWarn(
                "failed to find the process with PID %s" % name, True
            )

        return None

    @staticmethod
    def getProcPids(name):
        if not SysMgr.isLinux:
            return None

        pidList = []
        myPid = str(SysMgr.pid)

        pids = SysMgr.getPidList()
        for pid in pids:
            if myPid == pid:
                continue

            # check pid #
            try:
                nrPid = long(pid)
            except:
                continue

            # check comm #
            comm = SysMgr.getComm(pid)
            if comm and comm.startswith(name):
                pidList.append(nrPid)

        return pidList

    @staticmethod
    def getRuntime(sec=False):
        # init start time #
        if SysMgr.startRunTime == 0:
            try:
                statPath = "%s/self/stat" % (SysMgr.procPath)
                with open(statPath, "r") as fd:
                    stat = fd.read().split()
                    runtimeIdx = ConfigMgr.STAT_ATTR.index("STARTTIME")
                    SysMgr.startRunTime = float(stat[runtimeIdx]) / 100
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn("failed to get runtime", True, True)

        # calculate runtime #
        runtime = SysMgr.getUptime() - SysMgr.startRunTime

        # return runtime #
        if sec:
            return runtime
        else:
            return UtilMgr.convTime(long(runtime))

    @staticmethod
    def getUptime():
        if not SysMgr.isLinux:
            # get psutil object #
            try:
                psutil = SysMgr.getPkg("psutil", False)
                if not psutil:
                    return -1
                return time.time() - psutil.boot_time()
            except SystemExit:
                sys.exit(0)
            except:
                return -1

        # read uptime buf #
        try:
            uptime = SysMgr.readProcStat(
                SysMgr.uptimeFd, "uptime", SysMgr, "uptimeFd"
            )
            return float(uptime[0].split()[0])
        except SystemExit:
            sys.exit(0)
        except:
            return -1

    @staticmethod
    def updateUptime():
        SysMgr.prevUptime = SysMgr.uptime
        SysMgr.uptime = SysMgr.getUptime()
        SysMgr.uptimeDiff = SysMgr.uptime - SysMgr.prevUptime
        return SysMgr.uptime

    @staticmethod
    def broadcastEvent(event, pids=[]):
        if type(event) is not list:
            event = [event]

        # convert event name #
        for idx, item in enumerate(list(event)):
            if not item.startswith("EVENT_"):
                event[idx] = "EVENT_%s" % item

        # get pid list of Guider processes #
        if not pids:
            pids = SysMgr.getProcPids(__module__)
            if not pids:
                if SysMgr.checkMode("event"):
                    print("\nno running process in the background\n")
                else:
                    SysMgr.printWarn(
                        "failed to find running %s process to send event"
                        % __module__
                    )
                return []

        # update uptime #
        uptime = SysMgr.getUptime()

        # get socket inode address list of Guider processes #
        for pid in pids:
            # get UDP port list of Guider processes #
            if pid in SysMgr.netAddrCache:
                addrs = SysMgr.netAddrCache[pid]
            else:
                objs = SysMgr.getProcSocketObjs(pid)
                addrs = SysMgr.getSocketAddrList(objs)
                SysMgr.netAddrCache[pid] = addrs

            # send event to Guider processes #
            for addr in addrs:
                try:
                    attr, addr = addr.split(">", 1)
                    ip, port = addr.split(":")
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printWarn(
                        "failed to use '%s' as the remote address" % addr,
                        reason=True,
                    )
                    continue

                # create a network object #
                networkObject = NetworkMgr("client", ip, long(port))
                ip = networkObject.ip
                port = networkObject.port

                # check network object #
                if not ip or not port:
                    SysMgr.printWarn(
                        "failed to use '%s:%s' as the remote address"
                        % (ip, port)
                    )
                    continue

                # get comm #
                comm = SysMgr.getComm(pid, save=True)

                # send events #
                for item in event:
                    try:
                        networkObject.request = item
                        networkObject.send("%s@%s" % (item, uptime))
                        SysMgr.printInfo(
                            "sent event '%s' to %s:%s for %s(%s)"
                            % (item, ip, port, comm, pid)
                        )
                    except SystemExit:
                        sys.exit(0)
                    except:
                        SysMgr.printWarn(
                            "failed to send event '%s' to %s:%s for %s(%s)"
                            % (item, ip, port, comm, pid)
                        )

        return pids

    @staticmethod
    def updateBgProcs(cache=False):
        if SysMgr.bgProcList and cache:
            return

        SysMgr.bgProcList = SysMgr.getBgProcList()

    @staticmethod
    def checkBgProcs():
        # scan background tasks #
        SysMgr.updateBgProcs()

        # ignore my siblings #
        if SysMgr.bgProcList:
            ppid = os.getppid()
            myComm = SysMgr.getComm(SysMgr.pid)
            parentComm = SysMgr.getComm(ppid)
            if myComm == parentComm:
                bgList = SysMgr.bgProcList.split("\n")
                tempBgList = list(bgList)
                for idx, line in enumerate(tempBgList):
                    rline = line.lstrip()
                    if not rline or rline.startswith("("):
                        continue
                    pid = long(line.split()[0])
                    if pid == ppid:
                        bgList.pop(idx)
                SysMgr.bgProcList = "\n".join(bgList)

        if SysMgr.bgProcList:
            SysMgr.printWarn(SysMgr.getBgProcString(), True)

    @staticmethod
    def getBgProcCount(update=True, cache=False):
        if update:
            SysMgr.updateBgProcs(cache)

        cnt = 0
        for line in SysMgr.bgProcList.split("\n"):
            rline = line.lstrip()
            if rline and not rline.startswith("("):
                cnt += 1

        return cnt

    @staticmethod
    def getBgProcString():
        if not SysMgr.bgProcList:
            return ""

        procList = SysMgr.bgProcList
        procs = SysMgr.getBgProcCount(update=False)

        bgStr = "\n[Running Process] [TOTAL: %s]\n" % procs
        bgStr = "%s%s\n%7s %7s %7s %8s %5s %12s %s\n%s\n" % (
            bgStr,
            twoLine,
            "PID",
            "PPID",
            "COMM",
            "STATE",
            "RSS",
            "RUNTIME",
            "COMMAND",
            oneLine,
        )
        bgStr = "%s%s%s" % (bgStr, procList, oneLine)

        return bgStr

    @staticmethod
    def printBgProcs(cache=False, pager=False):
        if SysMgr.jsonEnable:
            result = SysMgr.getBgProcList(isJson=True)
            jsonResult = UtilMgr.convDict2Str(
                result, pretty=not SysMgr.streamEnable
            )
            SysMgr.printPipe(jsonResult)
            return

        SysMgr.updateBgProcs(cache)
        if not SysMgr.bgProcList:
            SysMgr.printPipe(
                "\nno running process in the background\n", pager=False
            )
        else:
            SysMgr.printPipe(SysMgr.getBgProcString(), pager=False)

    @staticmethod
    def getTids(
        name, isThread=True, sibling=False, main=False, inc=False, cache=False
    ):
        def _checkWait(pidList, waitTime):
            if not waitTime:
                return False

            SysMgr.printWarn(
                "wait for '%s' for %s sec because no task yet"
                % (name, waitTime)
            )

            time.sleep(waitTime)

            return True

        # define wait time for target #
        if "WAITTASK" in SysMgr.environList:
            waitTime = (
                UtilMgr.getEnvironNum("WAITTASK", False, 100, False) / 1000
            )
        else:
            waitTime = 0

        # define lists #
        pidList = []
        prevTargetList = []
        tidList = []

        # check input #
        if not name:
            return pidList

        # split items #
        try:
            nameList = name.split("|")
        except SystemExit:
            sys.exit(0)
        except:
            nameList = [name]

        # check tid #
        if not SysMgr.isLinux:
            try:
                psutil = SysMgr.getPkg("psutil")
                procs = psutil.process_iter(
                    attrs=["pid", "name"], ad_value=None
                )

                for proc in procs:
                    pid = proc.info["pid"]
                    comm = proc.info["name"]
                    if pid in nameList:
                        pidList.append(pid)
                    elif UtilMgr.isValidStr(comm, nameList, inc=inc):
                        pidList.append(pid)

                return pidList
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn(
                    "failed to find tasks related to '%s'" % name, reason=True
                )
                return pidList

        # check tid #
        for item in nameList:
            if "ONLYCOMM" in SysMgr.environList:
                break

            # check task #
            if not UtilMgr.isNumber(item) or not os.path.isdir(
                "%s/%s" % (SysMgr.procPath, item)
            ):
                continue

            # add sibling tasks #
            if sibling:
                path = "%s/%s/task" % (SysMgr.procPath, item)
                for pid in os.listdir(path):
                    if pid.isdigit():
                        pidList.append(pid)
            # add only main task #
            elif main:
                pidList.append(set([item, SysMgr.getTgid(item)]))
            # add a task #
            else:
                pidList.append(item)

            tidList.append(item)

        # pop tids from list #
        nameList = list(set(nameList) - set(tidList))
        if not nameList or "ONLYPID" in SysMgr.environList:
            return pidList

        # define ONLYPROC variable #
        onlyProc = True if "ONLYPROC" in SysMgr.environList else False

        # define PIDCACHE variable #
        pidcache = False if "NOPIDCACHE" in SysMgr.environList else True

        while 1:
            # set check list #
            targetList = SysMgr.getPidList()
            curList = set(targetList) - set(prevTargetList)
            if pidcache:
                prevTargetList = targetList

            for pid in curList:
                if not pid.isdigit():
                    continue

                # process #
                if not isThread:
                    # get comm #
                    comm = SysMgr.getComm(pid, cache)
                    if UtilMgr.isValidStr(comm, nameList, inc=inc):
                        pidList.append(pid)
                    continue

                # thread #
                try:
                    threadPath = "%s/%s/task" % (SysMgr.procPath, pid)
                    tids = os.listdir(threadPath)
                except SystemExit:
                    sys.exit(0)
                except:
                    continue

                for tid in tids:
                    if not tid.isdigit():
                        continue

                    # get comm #
                    comm = SysMgr.getComm(tid, cache=cache)
                    if not UtilMgr.isValidStr(comm, nameList, inc=inc):
                        continue

                    # include all siblings #
                    if sibling:
                        pidList += tids
                        break

                    # include the main thread #
                    if main or onlyProc:
                        pidList.append(pid)

                        # skip other threads #
                        if onlyProc:
                            continue

                    # include a thread #
                    pidList.append(tid)

            # check retry condition #
            if not pidList and _checkWait(pidList, waitTime):
                continue

            return list(set(pidList))

    @staticmethod
    def mount(source, path, fs, flags=0, data=0):
        try:
            # get ctypes object #
            SysMgr.importPkgItems("ctypes")

            # device #
            if source:
                sourcep = c_char_p(source.encode())
            else:
                sourcep = 0

            # path #
            if path:
                pathp = c_char_p(path.encode())
            else:
                pathp = 0

            # filesystem #
            if fs:
                fsp = c_char_p(fs.encode())
            else:
                fsp = 0

            # call mount syscall #
            ret = SysMgr.syscall("mount", sourcep, pathp, fsp, flags, data)
            if ret != 0:
                SysMgr.printWarn(
                    "failed to mount(%s, %s, %s, %s, %s)"
                    % (source, path, fs, flags, data)
                )
            return ret
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn(
                "failed to call mount(%s, %s, %s, %s, %s)"
                % (source, path, fs, flags, data),
                True,
                True,
            )

    @staticmethod
    def umount(target, flags=0):
        try:
            # get ctypes object #
            SysMgr.importPkgItems("ctypes")

            # path #
            if target:
                targetp = c_char_p(target.encode())
            else:
                targetp = 0

            # call umount2 syscall #
            ret = SysMgr.syscall("umount2", targetp, flags)
            if ret != 0:
                SysMgr.printWarn(
                    "failed to call umount2(%s, %s)" % (target, flags)
                )
            return ret
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn(
                "failed to call umount2(%s, %s)" % (target, flags), True, True
            )

    @staticmethod
    def readahead(path, offset, size=0, closeFd=False, raMax=0):
        # pylint: disable=not-callable
        if not SysMgr.readaheadFunc:
            # load libc #
            SysMgr.loadLibcObj()

            # check readahead #
            if not hasattr(SysMgr.libcObj, "readahead"):
                SysMgr.printErr("no readahead function in libc")
                sys.exit(-1)

            # define readahead #
            SysMgr.readaheadFunc = getattr(SysMgr.libcObj, "readahead")
            SysMgr.readaheadFunc.argtypes = [c_int, c_int64, c_int]
            SysMgr.readaheadFunc.restype = c_int

        # get fd #
        try:
            fd = SysMgr.rawFdCache[path]
        except SystemExit:
            sys.exit(0)
        except:
            try:
                fd = os.open(path, os.O_RDONLY)
                SysMgr.rawFdCache[path] = fd
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenErr(path)
                return False

        # change size 0 to total #
        if not size:
            try:
                size = os.stat(path).st_size
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "failed to get file size for '%s'" % path, True
                )
                return True

        # split readahead chunks #
        if raMax:
            chunk = raMax
        else:
            chunk = SysMgr.readaheadMaxSize
        remain = size
        coffset = offset

        # readahead chunks #
        while 1:
            # split by chunk size #
            if remain < chunk:
                csize = remain
            else:
                csize = chunk

            # readahead a chunk #
            os.lseek(fd, coffset, 0)
            SysMgr.readaheadFunc(c_int(fd), c_int64(coffset), c_int(csize))

            # check break condition #
            if csize < chunk:
                break

            # update offset and remain size #
            coffset += chunk
            remain -= chunk

        # close fd #
        if closeFd:
            try:
                os.close(fd)
            except SystemExit:
                sys.exit(0)
            except:
                pass

            # remove cache #
            SysMgr.rawFdCache.pop(path, None)

        return True

    @staticmethod
    def doReadahead(path):
        # change priority #
        SysMgr.setLowPriority(force=False, cpuVal=10, verb=True)

        # get readahead items #
        (
            raPath,
            raMin,
            raAllowList,
            raDenyList,
            raAddList,
        ) = FileAnalyzer.getReadaheadItems()

        # get readahead max size #
        raMax = SysMgr.readaheadMaxSize
        if "RAMAX" in SysMgr.environList:
            try:
                raMax = SysMgr.environList["RAMAX"][0]
                raMax = long(raMax)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    (
                        "failed to set the maximum size to '%s'"
                        "for readahead chunk"
                    )
                    % raMax,
                    True,
                )

        # get absolute path #
        path = os.path.realpath(path)
        SysMgr.printInfo("start readahead from '%s'" % path)
        startTime = time.time()

        # open list #
        try:
            raData = open(path, "rb").read()
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenErr(path)
            sys.exit(-1)

        # set system maximum fd number #
        SysMgr.setMaxFd()

        # get name list size #
        try:
            pos = 4
            chunkSize = 20
            nameListSize = struct.unpack("I", raData[:pos])[0]
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to get name list size for readahead", True)
            sys.exit(-1)

        # get file list #
        try:
            nameList = raData[pos : pos + nameListSize]
            nameList = nameList.decode().split("#")
            pos = pos + nameListSize
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to get name list for readahead", True)

        # check filter #
        raAllowIndexList = []
        raDenyIndexList = []
        if raAllowList or raDenyList:
            for idx, path in enumerate(nameList):
                # check allow list #
                if raAllowList and not UtilMgr.isValidStr(path, raAllowList):
                    raAllowIndexList.append(idx)
                # check deny list #
                elif raDenyList and UtilMgr.isValidStr(path, raDenyList):
                    raDenyIndexList.append(idx)

        # do readahead #
        totalSize = 0
        failFileList = {}
        while 1:
            try:
                # check break condition #
                nextPos = pos + chunkSize
                if len(raData) < nextPos:
                    break

                # get a chunk #
                fid, offset, size = struct.unpack("HQI", raData[pos:nextPos])

                # update values #
                pos = nextPos

                # check fail list #
                if fid in failFileList:
                    continue
                elif fid in raDenyIndexList:
                    continue
                elif raAllowList and not fid in raAllowIndexList:
                    continue
                elif raMin > size:
                    continue

                # get file name #
                fname = nameList[fid]

                # print workload #
                if SysMgr.warnEnable:
                    SysMgr.printWarn(
                        "try to readahead %s|%s|%s" % (fname, offset, size)
                    )

                # readahead a chunk #
                ret = SysMgr.readahead(fname, offset, size, raMax=raMax)
                if not ret:
                    failFileList[fid] = 0
                    continue

                totalSize += size
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn("failed to readahead", True, True)

        # readahead from add list #
        for item in raAddList:
            # parse file info #
            finfo = item.split(":")
            try:
                item = finfo[0]
                offset = size = 0

                if len(finfo) == 1:
                    pass
                elif len(finfo) == 2:
                    if finfo[1]:
                        size = UtilMgr.convUnit2Size(finfo[1])
                else:
                    offset = UtilMgr.convUnit2Size(finfo[1])
                    if finfo[2]:
                        size = UtilMgr.convUnit2Size(finfo[2])

                # set full size #
                if size == 0:
                    size = UtilMgr.getFileSize(item, False)

                # print workload #
                if SysMgr.warnEnable:
                    SysMgr.printWarn(
                        "try to readahead %s|%s|%s" % (item, offset, size)
                    )

                # readahead a chunk #
                ret = SysMgr.readahead(item, offset, size, raMax=raMax)

                totalSize += size
            except SystemExit:
                sys.exit(0)
            except:
                fname = SysMgr.environList["RAADDLIST"][0]
                SysMgr.printErr(
                    "failed to readahead '%s' from '%s'" % (item, fname), True
                )

        # get elapsed time #
        elapsed = time.time() - startTime

        # get CPU usage #
        try:
            dobj = Debugger(pid=os.getpid(), attach=False)
            dobj.initValues()
            dobj.getCpuUsage()
            cpu = "using CPU %s%% " % dobj.prevCpuStat[0]
        except SystemExit:
            sys.exit(0)
        except:
            cpu = ""

        # print results #
        logStr = "finished readahead a total of %s data %sfor %.3f sec" % (
            UtilMgr.convSize2Unit(totalSize),
            cpu,
            elapsed,
        )
        SysMgr.printInfo(logStr)
        LogMgr.doLogKmsg(logStr)

    @staticmethod
    def getBgProcList(checkCmdline=False, isJson=False):
        printBuf = ""
        printDict = {}
        myPid = str(SysMgr.pid)
        gstatList = ConfigMgr.STAT_ATTR
        commIdx = ConfigMgr.STAT_ATTR.index("COMM")

        # update uptime #
        uptime = SysMgr.getUptime()

        # get my info #
        myComm = SysMgr.getComm(SysMgr.pid)
        myCmdline = SysMgr.getCmdline(SysMgr.pid, True)
        myExeName = SysMgr.getExeName(SysMgr.pid)

        # get pid list #
        pids = SysMgr.getPidList()

        for pid in pids:
            if not pid.isdigit() or myPid == pid:
                continue

            # ignore tasks except for python #
            exeName = SysMgr.getExeName(pid, verb=False)
            if myExeName != exeName:
                continue

            # check comm #
            comm = SysMgr.getComm(pid)
            if not comm or not comm.startswith(myComm):
                continue

            # check cmdline again #
            if myComm != __module__ and checkCmdline:
                cmdlineList = SysMgr.getCmdline(pid, True)
                if len(cmdlineList) > 2 and myCmdline[:2] != cmdlineList[:2]:
                    continue

            runtime = "?"

            # info #
            try:
                # other OS #
                if not SysMgr.isLinux:
                    psutil = SysMgr.getPkg("psutil", False)
                    proc = psutil.Process(long(pid))
                    ppid = proc.ppid()
                    runtime = long(time.time() - proc.create_time())
                    cmdline = SysMgr.getCmdline(pid)
                    state = proc.status()
                    rss = UtilMgr.convSize2Unit(proc.memory_info()[0], True)
                    raise Exception()

                statPath = "%s/%s/stat" % (SysMgr.procPath, pid)
                with open(statPath, "r") as fd:
                    statList = fd.read().split()

                if len(statList) + 1 < len(ConfigMgr.STAT_ATTR):
                    SysMgr.printWarn(
                        "failed to read stat for %s(%s)" % (comm, pid)
                    )
                    continue

                statList = SysMgr.mergeCommStat(statList, commIdx)

                # runtime #
                procStart = float(statList[gstatList.index("STARTTIME")]) / 100
                runtime = long(uptime - procStart)

                # ppid #
                ppid = statList[gstatList.index("PPID")]

                # state #
                try:
                    state = ConfigMgr.PROC_STAT_TYPE[
                        statList[gstatList.index("STATE")]
                    ]
                except SystemExit:
                    sys.exit(0)
                except:
                    state = "N/A"

                # rss #
                rss = long(statList[gstatList.index("RSS")])
                rss = UtilMgr.convSize2Unit(rss << 12, True)
            except SystemExit:
                sys.exit(0)
            except:
                pass

            # runtime #
            if runtime != "?":
                runtime = UtilMgr.convTime(runtime)

            # socket #
            try:
                if not SysMgr.isLinux:
                    raise Exception()

                objs = SysMgr.getProcSocketObjs(pid)
                addrs = SysMgr.getSocketAddrList(objs)

                # merge address #
                netDict = {}
                for item in addrs:
                    ret = item.split("/")
                    if len(ret) == 2:
                        addr, stat = ret
                    else:
                        addr = ret[0]
                        stat = None

                    if not addr in netDict:
                        netDict[addr] = []

                    if stat:
                        netDict[addr].append(stat)

                # build string #
                netList = ""
                for addr, stat in netDict.items():
                    if stat:
                        netList = "%s%s/%s|" % (netList, addr, "/".join(stat))
                    else:
                        netList = "%s%s|" % (netList, addr)
                if netList:
                    network = "(%s)" % netList[:-1]
                else:
                    network = ""
            except SystemExit:
                sys.exit(0)
            except:
                network = ""

            # cmdline #
            try:
                cmdline = SysMgr.getCmdline(pid)
            except SystemExit:
                sys.exit(0)
            except:
                cmdline = "?"

            # build #
            if isJson:
                printDict[pid] = {
                    "comm": comm,
                    "ppid": ppid,
                    "state": state,
                    "rss": rss,
                    "runtime": runtime,
                    "cmdline": cmdline,
                    "network": network,
                }
            else:
                status = "%7s %7s %7s %8s %5s %12s" % (
                    pid,
                    ppid,
                    comm,
                    state,
                    rss,
                    runtime,
                )
                indent = len(status) * " "
                addline = "%s %s" % (cmdline, network)

                remain = SysMgr.ttyCols - (len(status) + len(addline))
                if remain < 0:
                    status = "%s %s\n%s %s" % (
                        status,
                        cmdline,
                        indent,
                        network,
                    )
                else:
                    status = "%s %s" % (status, addline)

                printBuf = "%s%s\n" % (printBuf, status)

        # return result #
        if isJson:
            return printDict
        else:
            return printBuf

    @staticmethod
    def waitUptime(deadline):
        while 1:
            current = SysMgr.getUptime()
            if current <= deadline:
                time.sleep(0.1)
                SysMgr.printWarn(
                    "%.1f seconds left until %s seconds"
                    % (deadline - current, deadline)
                )
            else:
                return

    @staticmethod
    def waitUserInput(wait=0, msg=None, newline=True, force=False):
        # check condition #
        if force:
            pass
        elif (
            SysMgr.outPath
            or SysMgr.bgStatus
            or not sys.stdin
            or SysMgr.checkMode("rtop")
            or SysMgr.checkMode("btop")
            or not SysMgr.selectEnable
            or "REMOTERUN" in os.environ
        ):
            return

        # get select object #
        selectObj = SysMgr.getPkg("select", False)
        if not selectObj:
            SysMgr.selectEnable = False
            return

        # convert infinite value #
        if wait is True:
            wait = 0

        # set default message #
        if msg == "DEFAULT":
            msg = "\ninput ENTER to continue or Ctrl+c to quit..."
        elif SysMgr.idList:
            msg = "input a task index... ( Help / Quit)"
        elif msg:
            pass
        else:
            msg = "input a command... ( Help / Quit )"

        # wait for user input #
        try:
            SysMgr.inWaitStatus = True

            # set suffix #
            if newline:
                suffix = "\n"
            else:
                suffix = ""

            # set input list #
            if SysMgr.bgStatus:
                inputList = []
            else:
                stdinPath = SysMgr.getFdName(SysMgr.pid, sys.stdin.fileno())
                if stdinPath and stdinPath.startswith("/dev/null"):
                    inputList = []
                else:
                    inputList = [sys.stdin]

            # there was user input #
            if selectObj.select(inputList, [], [], wait) == (
                [sys.stdin],
                [],
                [],
            ):
                sys.stdout.write("\b" * SysMgr.ttyCols)
                sys.stdout.write(msg + suffix)
                sys.stdout.flush()

                # flush buffered enter key #
                sys.stdin.readline()

                sys.stdout.write("=> ")
                sys.stdout.flush()

                # process user input #
                SysMgr.procUserInput(sys.stdin.readline())
            elif wait == 0:
                sys.stdout.write(msg + suffix)
                sys.stdout.flush()
                if force:
                    SysMgr.waitEvent()
                else:
                    sys.stdin.readline()
                    sys.stdout.write("\033[F")
        except SystemExit:
            sys.exit(0)
        except Exception as ex:
            SysMgr.printWarn("failed to read user input", reason=True)
            if type(ex).__name__ == "IOError":
                sys.stdin = None
        finally:
            SysMgr.inWaitStatus = False

        return True

    @staticmethod
    def procUserInput(uinput):
        def _printHelp():
            SysMgr.printPipe(
                """
[Filter]   {COMM|PID}
  exam) f init, 1234

[Sched]    {SCHED:PRIO:COMM|PID}
  exam) s r:1:123, c:-1:1234

[Kill]     {-SIGNAL} {COMM|PID}
  exam) k -sigstop 123, a.out

[Affinity] {MASK} {COMM|PID}
  exam) a 1f 123, a.out

[Sort]     {VAL}
  exam) S p

[Option]   {VAL}
  exam) o -e bs -g task

[Run]      {COMMAND}
  exam) r utop a.out
  exam) r btrace a.out
            """
            )

            # wait for enter #
            SysMgr.printPipe("input ENTER to continue...")
            sys.stdin.readline()

        ulist = uinput.split()
        if not ulist:
            return

        cmd = ulist[0]
        ucmd = cmd.upper()

        # hotkey #
        if SysMgr.idList and cmd.isdigit():
            try:
                pid = SysMgr.idList[long(cmd)]
            except:
                return

            SysMgr.executeCommand(pid=pid)
            return

        # help #
        if ucmd == "HELP" or ucmd == "H":
            _printHelp()
        # kill #
        elif ucmd == "KILL" or ucmd == "K":
            if len(ulist) > 1:
                SysMgr.sendSignalArgs(ulist[1:])
            else:
                _printHelp()
        # sched #
        elif ucmd == "SCHED" or cmd == "s":
            if len(ulist) > 1:
                SysMgr.applyPriority((" ".join(ulist[1:])))
            else:
                _printHelp()
        # sort #
        elif ucmd == "SORT" or cmd == "S":
            if len(ulist) > 1:
                SysMgr.setSortValue(ulist[1])
            else:
                _printHelp()
        # affinity #
        elif ucmd == "AFFINITY" or cmd == "a":
            if len(ulist) > 2:
                pids = (" ".join(ulist[2:])).split(",")
                pids = SysMgr.convTaskList(pids, isThread=True)
                SysMgr.setAffinity(ulist[1], pids)
            else:
                _printHelp()
        # filter #
        elif ucmd == "FILTER" or cmd == "f":
            if len(ulist) == 1:
                SysMgr.filterGroup = []
            else:
                SysMgr.filterGroup = (" ".join(ulist[1:])).split(",")

            SysMgr.filterGroup = UtilMgr.cleanItem(SysMgr.filterGroup)

            if SysMgr.isThreadMode():
                mode = "threads"
            else:
                mode = "processes"

            SysMgr.printInfo(
                "only specific %s [ %s ] are shown"
                % (mode, ", ".join(SysMgr.filterGroup))
            )
        # option #
        elif ucmd == "OPTION" or cmd == "o":
            if len(ulist) > 1:
                SysMgr.parseAnalOption(uinput[1:].strip())
            else:
                _printHelp()
        # run #
        elif ucmd == "RUN" or cmd == "r":
            if len(ulist) > 1:
                cmd = SysMgr.getExeCmd(SysMgr.pid)
                cmd.extend(ulist[1:])

                # launch new command #
                pid = SysMgr.createProcess(cmd)
                if pid < 0:
                    sys.exit(-1)

                # ignore signals and wait for children #
                SysMgr.setIgnoreSignal()
                os.wait()
                SysMgr.setNormalSignal()
            else:
                _printHelp()
        # quit #
        elif ucmd == "QUIT" or ucmd == "Q":
            sys.exit(0)

        """
        SysMgr.printPipe("input ENTER to continue...")
        sys.stdin.readline()
        """

    @staticmethod
    def getLimitCpuInfo(limitInfo):
        SysMgr.checkRootPerm()

        if not limitInfo:
            SysMgr.printErr("no input value for task limit info")
            sys.exit(-1)

        limitList = {}
        try:
            for item in limitInfo:
                (tid, per) = item.split(":")

                # get ID for tasks #
                if tid.isdigit():
                    limitList[tid] = long(per)
                else:
                    tidList = SysMgr.getTids(tid)
                    for tid in tidList:
                        limitList[tid] = long(per)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("wrong input value for task limit info", True)
            sys.exit(-1)

        return limitList

    @staticmethod
    def ignoreWarn():
        try:
            import warnings

            warnings.simplefilter("ignore", UserWarning)
        except:
            pass

    @staticmethod
    def executeCommand(cmds=None, pid=None, comm=None):
        if not cmds:
            cmds = SysMgr.customCmd

        # execute command #
        for cmd in cmds:
            # convert PID #
            if pid:
                cmd = cmd.replace("PID", pid)

            # convert COMM #
            if comm:
                cmd = cmd.replace("COMM", comm)

            # convert TIME #
            cmd = cmd.replace("TIME", str(SysMgr.uptime))

            SysMgr.printInfo("executed '%s'" % cmd)

            # launch Guider #
            if cmd.startswith("GUIDER "):
                # build command list #
                cmdList = UtilMgr.parseCommand(UtilMgr.lstrip(cmd, "GUIDER "))

                # launch command #
                try:
                    ret = SysMgr.launchGuider(
                        cmdList,
                        pipe=False,
                        stderr=True,
                        stream=False,
                        logo=False,
                        log=True,
                    )
                except SystemExit:
                    sys.exit(0)
                except:
                    ret = False
                    SysMgr.printErr(
                        "failed to launch %s" % __module__, reason=True
                    )
            # launch command #
            else:
                ret = SysMgr.createProcess(cmd.split())

            # check return #
            if ret is False or ret < 0:
                continue

            # ignore signals and wait for children #
            try:
                SysMgr.setIgnoreSignal()
                os.wait()
            except SystemExit:
                sys.exit(0)
            except:
                pass
            finally:
                try:
                    SysMgr.setNormalSignal()
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

    @staticmethod
    def getEnvList():
        def _applyList(myEnv, envList):
            for env in envList:
                var = env.split("=", 1)
                if len(var) > 1:
                    myEnv[var[0]] = var[1].rstrip()

        try:
            # copy original variables #
            myEnv = deepcopy(os.environ)

            # parse new variables #
            if "ENV" in SysMgr.environList:
                envList = SysMgr.environList["ENV"]
            else:
                envList = []

            # parse new variables from file #
            if "ENVFILE" in SysMgr.environList:
                envFileList = SysMgr.environList["ENVFILE"]
            else:
                envFileList = []

            # apply new variables from process #
            if "ENVPROC" in SysMgr.environList:
                SysMgr.checkRootPerm()

                # get PIDs #
                tasks = SysMgr.environList["ENVPROC"]
                pids = SysMgr.convTaskList(tasks, exceptMe=True)
                if not pids:
                    SysMgr.printErr(
                        "no process related to '%s'" % ", ".join(tasks)
                    )
                    return None

                # copy variables #
                for pid in pids:
                    comm = SysMgr.getComm(pid, True)
                    myEnv.update(SysMgr.getEnv(pid, retdict=True))
                    SysMgr.printInfo(
                        "applied environment variables for %s(%s)"
                        % (comm, pid)
                    )

            # check return condition #
            if not envList and not envFileList:
                return myEnv

            _applyList(myEnv, envList)

            # read variables from files #
            for fname in envFileList:
                try:
                    with open(fname, "r") as fd:
                        envList = fd.readlines()
                        _applyList(myEnv, envList)
                except:
                    SysMgr.printErr(
                        "failed to parse environment variable from %s" % fname,
                        True,
                    )
                    sys.exit(-1)

            return myEnv
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to parse environment variables", reason=True
            )
            return None

    @staticmethod
    def executeProcess(cmd=None, mute=False, closeFd=True, resetPri=False):
        # get new environ variables #
        env = SysMgr.getEnvList()

        # reset priority #
        if resetPri:
            SysMgr.setPriority(SysMgr.pid, "C", 0)

        # exec #
        try:
            SysMgr.resetFileTable(mute, closeFd)

            os.execvpe(cmd[0], cmd, env)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to execute '%s'" % " ".join(cmd), True)
            return -1

    @staticmethod
    def initTimes(first=True):
        # update start time #
        if first:
            newtime = SysMgr.updateUptime()
        else:
            newtime = SysMgr.getUptime()
        SysMgr.startInitTime = SysMgr.startTime = newtime
        SysMgr.startRecTime = 0  # start time for Recording #
        SysMgr.startRunTime = 0  # start time for Process #

    @staticmethod
    def initSystemContext():
        if not SysMgr.outPath or "FASTINIT" in SysMgr.environList:
            SysMgr(onlyInstance=True)
        else:
            SysMgr()

    @staticmethod
    def initEnvironment():
        # init times #
        SysMgr.initTimes()

        # save original args #
        SysMgr.origArgs = deepcopy(sys.argv)

        # register exit handler #
        atexit.register(SysMgr.doExit)

        # print logo #
        SysMgr.printLogo(big=True, pager=False)

        # increase stack depth #
        sys.setrecursionlimit(2000)

        # check environment #
        SysMgr.checkEnv()

        # print help #
        SysMgr.printHelp()

        # set default I/O #
        SysMgr.inputFile = sys.argv[1]
        SysMgr.outputFile = None

        # check log level #
        SysMgr.warnEnable = SysMgr.findOption("v")

        # set error logger #
        SysMgr.setErrorLogger()

        # import Guider native module #
        SysMgr.importNative()

        # create shared memory #
        SysMgr.shmObj = SysMgr.createShm()

        # set oom_adj #
        SysMgr.setOOMAdj()

        # set pid #
        SysMgr.getMaxPid()
        SysMgr.pid = os.getpid()

        # set arch #
        SysMgr.setArch(SysMgr.getArch())

        # set default signal #
        SysMgr.setSimpleSignal()

        # shrink heap #
        SysMgr.shrinkHeap()

        # get environment variables #
        value = SysMgr.getOption("q")
        if value:
            itemList = UtilMgr.splitString(value)
            SysMgr.environList = UtilMgr.convList2Dict(itemList, cap=True)

        # set comm #
        if "COMM" in SysMgr.environList:
            name = SysMgr.environList["COMM"][0]
        else:
            name = __module__
        SysMgr.setComm(name)
        SysMgr.comm = SysMgr.getComm(SysMgr.pid)

        # remove environment variables #
        if "REMOVEENV" in SysMgr.environList:
            for var in SysMgr.environList["REMOVEENV"]:
                os.environ.pop(var, None)

    @staticmethod
    def getOutput(fd, retLine=False, progress=False):
        # get select object #
        selectObj = SysMgr.getPkg("select")

        output = ""

        while 1:
            # wait for event #
            [read, write, error] = selectObj.select([fd], [], [])

            if progress:
                UtilMgr.printProgress()

            if read:
                line = read[0].readline()
                if retLine:
                    return line
                elif line == "":
                    return output

                output += line

    @staticmethod
    def launchGuider(
        cmd,
        log=False,
        mute=False,
        pipe=True,
        stderr=False,
        wait=False,
        stream=True,
        logo=True,
        copyOpt=True,
    ):
        """
        - desc: launch a new Guider process as a child
        - pros: can save memory such as ELF caches
                can control Guider functions such as logo, stdio
        - cons: should use global variables well
        """

        # check mute #
        if mute:
            pipe = False

        # create pipe #
        if pipe:
            rd, wr = os.pipe()

            # set SIGPIPE handler #
            SysMgr.setPipeHandler()
        else:
            rd = wr = None

        # create a new process #
        pid = SysMgr.createProcess(mute=mute)

        # parent #
        if pid > 0:
            if pipe:
                os.close(wr)
                rdFd = os.fdopen(rd, "r")
            else:
                rdFd = None

            # wait for children temrination #
            if wait:
                SysMgr.waitChild(pid)
                return pid

            if pipe:
                return (pid, rdFd)
            else:
                return pid

        # child #
        elif pid == 0:
            # disable alarm #
            signal.alarm(0)

            # set main environment #
            os.environ["ISMAIN"] = "True"

            # reinitialize static variables #
            # globals().update(vars(SysMgr))

            # disable pager, print output both to file and to stdout #
            if stream:
                SysMgr.setStream()

            # inherit options #
            disOptVal = SysMgr.getOption("d")
            enOptVal = SysMgr.getOption("e")
            if copyOpt and (disOptVal or enOptVal):
                applyDisable = False
                applyEnable = False

                # append option values #
                for idx, val in enumerate(cmd):
                    if val.startswith("-d") and disOptVal:
                        cmd[idx] = val + disOptVal
                        applyDisable = True
                    elif val.startswith("-e") and enOptVal:
                        cmd[idx] = val + enOptVal
                        applyEnable = True

                # append option #
                if disOptVal and not applyDisable:
                    cmd.append("-d %s" % disOptVal)
                if enOptVal and not applyEnable:
                    cmd.append("-e %s" % enOptVal)

            # disable logo #
            if not logo:
                SysMgr.logoEnable = False

            # disable logs #
            if not log:
                SysMgr.logEnable = False

            # change standard I/O #
            if pipe:
                os.dup2(wr, 1)
                os.close(wr)
                os.close(rd)

            # close stderr #
            if not stderr:
                sys.stderr.close()

            # init time variables #
            SysMgr.startInitTime = 0
            SysMgr.startTime = 0
            SysMgr.startRecTime = 0
            SysMgr.startRunTime = 0
            SysMgr.startOverheadTime = 0

            # init resource variables #
            SysMgr.taskEnable = True
            SysMgr.cpuEnable = True
            SysMgr.memEnable = False
            SysMgr.blockEnable = False
            SysMgr.diskEnable = False
            SysMgr.reportEnable = False
            SysMgr.networkEnable = False

            # init print variables #
            SysMgr.inputFile = None
            SysMgr.outPath = None
            SysMgr.printFd = None
            SysMgr.printEnable = True
            SysMgr.encodeEnable = False
            SysMgr.reportEnable = SysMgr.jsonEnable = False

            # init number variables #
            SysMgr.nrTopRank = 10
            SysMgr.repeatCount = 0
            SysMgr.progressCnt = 0
            SysMgr.repeatInterval = 0
            SysMgr.intervalEnable = 0
            SysMgr.maxInterval = 0

            # init other variables #
            SysMgr.parsedAnalOption = False
            SysMgr.groupProcEnable = False
            SysMgr.optionList = []
            ConfigMgr.confData = {}
            SysMgr.procBuffer = []
            SysMgr.exitFuncList = []
            SysMgr.customCmd = []
            SysMgr.rcmdList = {}

            # clear print buffer #
            SysMgr.clearPrint()

            # launch Guider command #
            main(cmd)

            sys.exit(0)

        # error #
        else:
            SysMgr.printErr("failed to launch Guider because of fork fail")
            return -1

    @staticmethod
    def executeCommandRes(cmd, stdout=1, stderr=True):
        # create pipe #
        rd, wr = os.pipe()

        # set SIGPIPE handler #
        SysMgr.setPipeHandler()

        # create a new process #
        pid = SysMgr.createProcess()

        # parent #
        if pid > 0:
            os.close(wr)
            rdFd = os.fdopen(rd, "r")
            output = []

            while 1:
                ret = rdFd.readline().rstrip("\n")
                if not ret:
                    break
                output.append(ret)

            return output

        # child #
        elif pid == 0:
            # change standard I/O #
            os.dup2(wr, stdout)
            os.close(wr)
            os.close(rd)

            # close stderr #
            if not stderr:
                sys.stderr.close()

            if type(cmd) is str:
                cmd = cmd.split()

            # execute #
            SysMgr.executeProcess(cmd=cmd)

            sys.exit(0)

        # error #
        else:
            SysMgr.printErr(
                "failed to execute %s because of fork failure" % cmd
            )
            return -1

    @staticmethod
    def waitChild(pid=None, hang=True):
        # wait for all children #
        if not pid:
            while 1:
                try:
                    os.waitpid(-1, 0)
                except:
                    pass

                if SysMgr.condExit:
                    break

                # check children #
                SysMgr.updateChildList()
                if SysMgr.isNoChild():
                    break
            return

        # set blocking flag #
        if hang:
            flag = 0
        else:
            flag = os.WNOHANG

        # wait for a specific child #
        try:
            return os.waitpid(pid, flag)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("failed to wait %s task" % pid, reason=True)

    @staticmethod
    def spawnProcess(func=None, args=[], cnt=1, wait=True):
        # load multiprocessing #
        multiprocessing = SysMgr.getPkg("multiprocessing")

        plist = []
        pidlist = []

        for _ in xrange(cnt):
            try:
                # create a new process #
                p = multiprocessing.Process(target=func, args=args)

                # run a new process #
                p.start()

                # save process info #
                plist.append(p)
                pidlist.append(p.pid)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("failed to create a new process", reason=True)
                continue

        # sync #
        if wait:
            for p in plist:
                p.join()
        else:
            return pidlist

    @staticmethod
    def execBgCmd(cmd, mute=True, wait=True):
        # launch Guider #
        if (UtilMgr.isString(cmd) and cmd.startswith("GUIDER ")) or (
            type(cmd) is list and cmd[0] == "GUIDER"
        ):

            # build command list #
            if type(cmd) is list:
                cmdList = cmd[1:]
            else:
                cmdList = UtilMgr.parseCommand(cmd.lstrip("GUIDER "))

            # launch command #
            try:
                ret = SysMgr.launchGuider(
                    cmdList,
                    pipe=False,
                    stderr=True,
                    stream=False,
                    logo=False,
                    log=True,
                )
            except SystemExit:
                sys.exit(0)
            except:
                ret = False
                SysMgr.printErr(
                    "failed to launch %s" % __module__, reason=True
                )
        # launch command #
        else:
            ret = SysMgr.createProcess(cmd, mute=mute)

        # check task #
        if ret is False or ret < 0:
            return -1
        elif ret > 0:
            if wait:
                os.waitpid(ret, 0)
            return

        # temrinate #
        os._exit(0)

    @staticmethod
    def createProcess(
        cmd=None, isDaemon=False, mute=False, chPgid=False, chMid=False
    ):

        # flush print buffer before fork #
        SysMgr.flushAllForPrint()

        # save tty info #
        if cmd and SysMgr.ttyData is None:
            SysMgr.saveTTY()

        # create a new process #
        try:
            pid = os.fork()
        except SystemExit:
            sys.exit(0)
        except:
            # multiprocessing #
            try:
                ret = SysMgr.spawnProcess(wait=False)
                if ret:
                    return ret[0]
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("failed to create a new process", True)
            return -1

        # parent #
        if pid > 0:
            if not isDaemon:
                SysMgr.childList[pid] = True

            return pid
        # child #
        elif pid == 0:
            # init times #
            SysMgr.initTimes(False)
            SysMgr.getRuntime()

            # update parent PID #
            SysMgr.parentPid = SysMgr.pid

            # initialize child list #
            SysMgr.clearChildList()

            if chPgid:
                os.setpgid(0, 0)

            # close fd for output #
            SysMgr.closePrintFd()

            # Guider #
            if not cmd:
                # update master pid #
                if chMid:
                    SysMgr.masterPid = SysMgr.pid

                # update pid #
                SysMgr.fileSuffix = SysMgr.pid = os.getpid()

                # init shared resources #
                SysMgr.initSharedResource(mute)

                return 0

            # split command #
            if UtilMgr.isString(cmd):
                cmd = cmd.split()

            # convert ~ to realpath #
            cmd[0] = os.path.expanduser(cmd[0])

            # execute #
            SysMgr.executeProcess(cmd, mute)

            # execute fail #
            os._exit(0)
        # fail #
        else:
            SysMgr.printErr("failed to create a new process")
            return -1

    @staticmethod
    def redirectFd(path, fileno):
        try:
            SysMgr.printInfo("redirect fd(%s) to '%s'" % (fileno, path))
            fd = os.open(path, os.O_RDWR | os.O_CREAT | os.O_APPEND)
            os.dup2(fd, fileno)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to redirect %s to '%s'" % (fileno, path), True
            )
            sys.exit(-1)

    @staticmethod
    def initSharedResource(mute, net=True):
        # set mute #
        if mute:
            SysMgr.closeStdFd(stderr=False)

        # clear threshold condition #
        SysMgr.prevThresholdData = SysMgr.thresholdData
        SysMgr.thresholdData = {}
        SysMgr.eventCommandList = {}
        SysMgr.eventLockList = {}

        # reset report resource #
        SysMgr.reportEnable = False
        SysMgr.reportObject = None

        # reinit network #
        if net and SysMgr.localServObj:
            ip = SysMgr.localServObj.ip

            # remove previous socket #
            try:
                SysMgr.localServObj.close()
            except:
                pass

            NetworkMgr.setServerNetwork(ip, None, force=True, anyPort=True)

    @staticmethod
    def closeStdFd(stdin=False, stdout=True, stderr=True):
        try:
            if not SysMgr.nullFd:
                SysMgr.nullFd = open(SysMgr.nullPath, "w")
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("failed to open '%s'" % SysMgr.nullPath, True)
            return

        # get null fd #
        nullFd = SysMgr.nullFd.fileno()

        # redirect stdin to file #
        if "STDIN" in SysMgr.environList:
            path = SysMgr.environList["STDIN"][0]
            if path != "SET":
                SysMgr.redirectFd(path, sys.stdin.fileno())
        # redirect stdin to null #
        elif stdin:
            os.dup2(nullFd, sys.stdin.fileno())

        # redirect stdout to file #
        if "STDOUT" in SysMgr.environList:
            path = SysMgr.environList["STDOUT"][0]
            if path != "SET":
                SysMgr.redirectFd(path, sys.stdout.fileno())
        elif stdout:
            os.dup2(nullFd, sys.stdout.fileno())

        # redirect stderr to file #
        if "STDERR" in SysMgr.environList:
            path = SysMgr.environList["STDERR"][0]
            if path != "SET":
                SysMgr.redirectFd(path, sys.stderr.fileno())
        elif stderr:
            os.dup2(nullFd, sys.stderr.fileno())

    @staticmethod
    def resetFileTable(mute=True, closeFd=True):
        # redirect stdout and stderr to null #
        try:
            if mute:
                SysMgr.closeStdFd(stderr=False)
        except SystemExit:
            sys.exit(0)
        except:
            pass

        if not closeFd:
            return

        # close all file descriptors except for stds #
        try:
            # set path for descriptor list #
            path = "%s/self/fd" % SysMgr.procPath

            # close descriptors #
            for fd in os.listdir(path):
                try:
                    fd = long(fd)
                    if fd > 2:
                        os.close(fd)
                except SystemExit:
                    sys.exit(0)
                except:
                    pass
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to get file descriptors in %s" % path, reason=True
            )
            return

    @staticmethod
    def runBackgroundMode():
        if SysMgr.bgStatus:
            return

        # update start overhead time #
        if SysMgr.startOverheadTime == 0:
            SysMgr.getRuntime()
            SysMgr.startOverheadTime = (
                SysMgr.startInitTime - SysMgr.startRunTime
            )

        # create a new process #
        pid = SysMgr.createProcess(isDaemon=True)
        if pid > 0:
            # wait a minute for child message #
            time.sleep(0.1)

            # terminate parent process #
            sys.exit(0)
        else:
            SysMgr.bgStatus = True

            # continue child process #
            SysMgr.printStat(
                "run %s(%s) in background"
                % (SysMgr.getComm(SysMgr.pid), SysMgr.pid)
            )

    @staticmethod
    def setDefaultSignal():
        if not SysMgr.isLinux and not SysMgr.isDarwin:
            return

        signal.signal(signal.SIGINT, signal.SIG_DFL)
        signal.signal(signal.SIGQUIT, signal.SIG_DFL)
        signal.signal(signal.SIGCHLD, signal.SIG_DFL)
        signal.signal(signal.SIGPIPE, signal.SIG_DFL)

    @staticmethod
    def setSimpleSignal():
        if not SysMgr.isLinux and not SysMgr.isDarwin:
            return

        SysMgr.setCommonSignal()

        signal.signal(signal.SIGINT, SysMgr.exitHandler)
        signal.signal(signal.SIGQUIT, SysMgr.exitHandler)
        signal.signal(signal.SIGPIPE, signal.SIG_IGN)
        signal.signal(signal.SIGHUP, signal.SIG_IGN)

    @staticmethod
    def setPipeHandler():
        if not SysMgr.isLinux and not SysMgr.isDarwin:
            return

        signal.signal(signal.SIGPIPE, SysMgr.exitHandler)

    @staticmethod
    def setCommonSignal():
        if not SysMgr.isLinux and not SysMgr.isDarwin:
            return

        signal.signal(signal.SIGCHLD, SysMgr.chldHandler)
        signal.signal(signal.SIGWINCH, SysMgr.winchHandler)
        signal.signal(signal.SIGCONT, SysMgr.fgHandler)
        signal.signal(signal.SIGTSTP, SysMgr.bgHandler)
        signal.signal(signal.SIGTTIN, SysMgr.bgHandler)
        signal.signal(signal.SIGTTOU, signal.SIG_IGN)
        signal.signal(signal.SIGUSR1, SysMgr.defaultHandler)
        signal.signal(signal.SIGUSR2, SysMgr.defaultHandler)

    @staticmethod
    def setIgnoreSignal():
        if not SysMgr.isLinux and not SysMgr.isDarwin:
            return

        signal.signal(signal.SIGALRM, signal.SIG_IGN)
        signal.signal(signal.SIGINT, signal.SIG_IGN)
        signal.signal(signal.SIGQUIT, signal.SIG_IGN)
        signal.signal(signal.SIGPIPE, signal.SIG_IGN)

    @staticmethod
    def blockSignal(sig=None, act="block", wait=False):
        # load libc #
        if not SysMgr.libcObj:
            if not SysMgr.loadLibcObj():
                return False

        # set default signal #
        if not sig:
            sig = signal.SIGINT

        if not SysMgr.sigsetObj:
            NWORDS = long(1024 / (8 * sizeof(c_uint)))

            class sigset_t(Structure):
                _fields_ = [("__sigbits", c_uint * NWORDS)]

            SysMgr.sigsetObj = sigset_t()
            SysMgr.sigsetOldObj = sigset_t()

        sigset = SysMgr.sigsetObj
        sigsetold = SysMgr.sigsetOldObj

        # check act #
        if act == "block":
            atype = SIG_BLOCK = 0
        elif act == "unblock":
            atype = SIG_UNBLOCK = 1
        else:
            SysMgr.printErr("no supported '%s' for blocking signal" % act)
            return

        SysMgr.libcObj.memset(byref(sigset), 0, sizeof(sigset))

        if type(sig) is not list:
            sig = [sig]

        for sigbit in sig:
            if hasattr(SysMgr.libcObj, "sigaddset"):
                SysMgr.libcObj.sigaddset(byref(sigset), sigbit)

        SysMgr.libcObj.sigprocmask(atype, byref(sigset), byref(sigsetold))

        if wait:
            if hasattr(SysMgr.libcObj, "sigsuspend"):
                SysMgr.libcObj.sigsuspend(byref(sigsetold))

        return True

    @staticmethod
    def pendingSignal(sig):
        # load libc #
        if not SysMgr.libcObj and not SysMgr.loadLibcObj():
            return False
        elif not SysMgr.sigsetObj:
            return False

        sigset = SysMgr.sigsetObj

        # get pending list #
        SysMgr.libcObj.sigpending(byref(sigset))

        if type(sig) is not list:
            sig = [sig]

        pendList = []
        for item in sig:
            if SysMgr.libcObj.sigismember(byref(sigset), item):
                pendList.append(item)

        return set(list(pendList))

    @staticmethod
    def callSigHandler(sig, frame=None):
        try:
            sh = signal.getsignal(sig)
            sh(sig, frame)
        except SystemExit:
            sys.exit(0)
        except:
            if sh == signal.SIG_IGN:
                reason = " because %s is ignored" % sig
            elif sh == signal.SIG_DFL:
                reason = " because %s is handled in default" % sig
            else:
                reason = ""

            SysMgr.printWarn(
                "failed to call signal handler for %s%s" % (sig, reason)
            )

    @staticmethod
    def setNormalSignal():
        if not SysMgr.isLinux and not SysMgr.isDarwin:
            return

        SysMgr.setCommonSignal()

        signal.signal(signal.SIGALRM, SysMgr.alarmHandler)
        signal.signal(signal.SIGINT, SysMgr.stopHandler)
        signal.signal(signal.SIGQUIT, SysMgr.newHandler)
        signal.signal(signal.SIGPIPE, signal.SIG_IGN)

    @staticmethod
    def runServerMode():
        nodeList = {}
        agentList = {}

        def _sendErrMsg(netObj, message):
            message = "ERROR|%s:%s:%s" % (message, netObj.ip, netObj.port)
            netObj.send(message)

        def _updateNodeList(ret=False):
            # close sockets for terminated connections #
            for addr in list(nodeList):
                if not NetworkMgr.requestPing(addr, verb=SysMgr.warnEnable):
                    try:
                        nodeList[addr]["sock"].close()
                    except:
                        pass
                    finally:
                        nodeList.pop(addr, None)

            # get network info #
            try:
                netinfo = " [%s/%s]" % (
                    NetworkMgr.getHostName(),
                    NetworkMgr.getPublicIp(),
                )
            except SystemExit:
                sys.exit(0)
            except:
                netinfo = ""

            # print node list #
            idx = 0
            current = time.time()
            listStr = "[Service Node List]%s\n%s\n" % (netinfo, twoLine)
            listStr += "{0:^5} {1:^13} {2:^25} {3:<1} \n{4:1}\n".format(
                "Idx", "Time", "Addr", "Host", oneLine
            )
            for addr, value in sorted(
                nodeList.items(), key=lambda e: e[1]["time"]
            ):
                diff = current - value["time"]
                listStr += "[{0:>3}] {1:^13} {2:<25} {3:<1}\n".format(
                    idx, UtilMgr.convTime(diff), addr, value["host"]
                )
                idx += 1
            listStr += (
                "%s\n" % oneLine if nodeList else "\tNone\n%s\n" % oneLine
            )
            SysMgr.printWarn(listStr, True)

            if ret:
                return listStr

        def _onDownload(netObj, value, response):
            # pick path #
            try:
                files = UtilMgr.cleanItem(value.split("@", 1), False)
                if len(files) == 2:
                    src, des = files
                    if src and not des:
                        des = src
                    elif not src:
                        raise Exception()
                else:
                    src = des = files[0]
            except:
                SysMgr.printWarn("failed to recognize %s" % value, True)
                _sendErrMsg(
                    netObj,
                    "wrong format for path, input in the format {SRC@DES}",
                )
                return

            # response from command request #
            netObj.send(response)

            # transfer file #
            try:
                NetworkMgr.sendFile(netObj, netObj.ip, netObj.port, src, des)
            except:
                SysMgr.printErr(
                    "failed to upload %s to %s in %s:%s"
                    % (src, des, netObj.ip, netObj.port),
                    True,
                )
            finally:
                try:
                    netObj.send("@DONE#0".encode())
                    netObj.close()
                except:
                    pass

        def _onUpload(netObj, value, response):
            try:
                files = UtilMgr.cleanItem(value.split("@", 1), False)
                if len(files) == 2:
                    src, des = files
                    if src and not des:
                        des = src
                    elif not src:
                        raise Exception()
                else:
                    src = files[0]
                    des = None
            except:
                SysMgr.printWarn("failed to recognize %s" % value, True)
                _sendErrMsg(
                    netObj,
                    "wrong format for path, input in the format {SRC@DES}",
                )
                return

            # send response #
            netObj.send(response)

            # receive file #
            try:
                NetworkMgr.recvFile(netObj, netObj.ip, netObj.port, src, des)
            except:
                SysMgr.printErr(
                    "failed to download %s from %s in %s:%s"
                    % (src, des, netObj.ip, netObj.port),
                    True,
                )
            finally:
                netObj.close()

        def _onNew(connObj, value, response):
            try:
                # reply message #
                connObj.send("PONG")

                host, addr = value.rsplit("/", 1)

                # register node info #
                if not addr in nodeList or nodeList[addr]["sock"] != connObj:
                    nodeList[addr] = {
                        "sock": connObj,
                        "time": time.time(),
                        "host": host,
                    }

                SysMgr.printInfo(
                    "registered '%s' as a service node successfully" % value
                )

                # update service node list #
                _updateNodeList()
            except:
                SysMgr.printWarn(
                    "failed to register '%s' as a service node" % value,
                    reason=True,
                )

        def _onClear(connObj, value, response):
            try:
                # send message packet #
                connObj.send("MSG:terminated all worker processes")

                # terminate worker processes #
                SysMgr.killChildren(sig=signal.SIGINT)

                # get pstree #
                SysMgr.doPstree(
                    [str(SysMgr.pid)], False, SysMgr.infoBufferPrint
                )
                pstree = SysMgr.systemInfoBuffer
                SysMgr.clearInfoBuffer()

                """
                receive an ACK packet
                to prevent receiving two packets at once
                """
                connObj.recv()

                # send reply packet for command #
                connObj.send("CLEAR:%s" % pstree)
            except:
                SysMgr.printWarn(
                    "failed to terminate worker processes", reason=True
                )

        def _onJobs(connObj, value, response):
            try:
                # send message packet #
                connObj.send("MSG:list all worker processes")

                # get pstree #
                SysMgr.doPstree(
                    [str(SysMgr.pid)], False, SysMgr.infoBufferPrint
                )
                pstree = SysMgr.systemInfoBuffer.rstrip()
                SysMgr.clearInfoBuffer()

                """
                receive an ACK packet
                to prevent receiving two packets at once
                """
                connObj.recv()

                # send reply packet for command #
                connObj.send("JOBS:%s" % pstree)
            except:
                SysMgr.printWarn(
                    "failed to list worker processes", reason=True
                )

        def _onRestart(connObj, value, response):
            return True

        def _onList(connObj, value, response):
            try:
                # update service node list #
                ret = _updateNodeList(ret=True)
                connObj.send("LIST:" + ret.strip())
            except:
                pass

        def _onPing(connObj, value, response):
            try:
                connObj.send("PONG")
            except:
                pass

        def _onRun(connObj, value, response):
            def _enableSigPipe():
                signal.signal(signal.SIGPIPE, signal.SIG_DFL)

            # response from command request #
            connObj.send(response)

            # get subprocess object #
            subprocess = SysMgr.getPkg("subprocess")

            # get connection info #
            addr = "%s:%s" % (connObj.ip, connObj.port)

            # convert Guider path #
            if value.startswith("GUIDER "):
                cmd = " ".join(value.split()[1:])
                path = " ".join(SysMgr.getExeCmd(SysMgr.pid))
                value = "%s %s" % (path, cmd)

            # run command #
            try:
                # copy environment variables #
                myEnv = deepcopy(os.environ)
                myEnv["REMOTERUN"] = "True"

                # set SIGCHLD #
                signal.signal(signal.SIGCHLD, signal.SIG_DFL)

                # set print flag #
                printFlag = SysMgr.getPrintFlag()
                if printFlag:
                    procOut = subprocess.PIPE
                else:
                    procOut = open(SysMgr.nullPath, "wb")

                # create process to communicate #
                procObj = subprocess.Popen(
                    value,
                    shell=True,
                    stdout=procOut,
                    stderr=procOut,
                    env=myEnv,
                    bufsize=0,
                    preexec_fn=os.setsid,
                )

                SysMgr.printInfo("executed '%s' for %s" % (value, addr))

                # get select object #
                selectObj = SysMgr.getPkg("select")

                # set fds #
                listenFds = []
                if procObj.stdout:
                    listenFds.append(procObj.stdout)
                if procObj.stderr:
                    listenFds.append(procObj.stderr)
                if connObj.socket:
                    listenFds.append(connObj.socket)

                # get I/O buffer size #
                if "READCHUNK" in SysMgr.environList:
                    readChunkSize = UtilMgr.getEnvironNum("READCHUNK")
                else:
                    readChunkSize = None

                # run mainloop #
                while 1:
                    try:
                        # wait for event #
                        [read, write, error] = selectObj.select(
                            listenFds, [], [], 1
                        )

                        # read output from pipe #
                        for robj in read:
                            # check connection close #
                            assert robj != connObj.socket

                            # handle data arrived #
                            while 1:
                                # read output from pipe #
                                if readChunkSize:
                                    output = robj.read(readChunkSize)
                                else:
                                    output = robj.readline()

                                # check and transfer output #
                                if output == "\n":
                                    continue
                                elif output and len(output) > 0:
                                    assert connObj.write(output)
                                else:
                                    break
                    except:
                        break

                    # check process status #
                    if procObj.poll() != None:
                        break

                SysMgr.printInfo("terminated '%s' for %s" % (value, addr))
            except:
                SysMgr.printErr(
                    "failed to execute '%s' from %s" % (value, addr), True
                )
            finally:
                try:
                    # kill subprocess group #
                    SysMgr.killProcGroup(procObj)

                    time.sleep(SysMgr.waitDelay)

                    # kill subprocess group #
                    SysMgr.killProcGroup(procObj, signal.SIGKILL)

                    connObj.socket.shutdown(socket.SHUT_RDWR)
                    connObj.close()
                except:
                    pass

        def _onNotify(netObj, value, response):
            # send message packet #
            connObj.send(
                'MSG:"%s" is going to be delivered by the agent' % value
            )

            """
            receive an ACK packet
            to prevent receiving two packets at once
            """
            connObj.recv()

            # send reply packet for command #
            connObj.send("NOTIFY:%s" % value)

            # execute event handlers #
            _runEventHandlers(value)

        def _onUpstream(netObj, value, response, sync=True):
            # check agent list #
            if not agentList:
                connObj.send("NO_SERV_AGENT")
                return

            # split items #
            itemList = value.split(":")

            # pick command #
            reqCmd = itemList[0].upper()
            if reqCmd in NetworkMgr.REQUEST_LIST:
                cmd = value
            else:
                cmd = "run:" + value

            # send message packet #
            connObj.send('MSG:"%s" is going to be executed by the agent' % cmd)

            """
            receive an ACK packet
            to prevent receiving two packets at once
            """
            connObj.recv()

            # send reply packet for command #
            connObj.send("run|%s" % value)

            # execute remote commands #
            pid = 0
            for addr in list(agentList):
                # create a new worker process #
                pid = SysMgr.createProcess()
                if pid > 0:
                    continue

                try:
                    SysMgr.printInfo(
                        "execute '%s' at %s for %s:%s"
                        % (cmd, addr, connObj.ip, connObj.port)
                    )

                    # disable log #
                    SysMgr.logEnable = False

                    # execute a command from the agent #
                    rcmd = "%s|%s" % (addr, cmd)
                    SysMgr.runClientMode(rcmd, connObj)
                except SystemExit:
                    pass
                except:
                    SysMgr.logEnable = True
                    SysMgr.printErr(
                        "failed to execute '%s' at %s for %s:%s"
                        % (cmd, addr, connObj.ip, connObj.port)
                    )

                sys.exit(0)

            # wait for termination for remote commands #
            if pid > 0 and sync:
                SysMgr.waitChild()

        def _onBroadcast(connObj, value, response, sync=True):
            # check node list #
            if not nodeList:
                connObj.send("NO_SERV_NODE")
                return

            # split items #
            itemList = value.split(":")

            # check target list #
            if itemList[0].startswith("@"):
                targetList = itemList.pop(0)[1:].split("@")
                value = ":".join(itemList)
                nrTarget = len(targetList)
            else:
                targetList = []
                nrTarget = len(nodeList)

            # pick command #
            reqCmd = itemList[0].upper()
            if reqCmd in NetworkMgr.REQUEST_LIST:
                cmd = value
            else:
                cmd = "run:" + value

            # send message packet #
            connObj.send(
                'MSG:"%s" is going to be executed by %s nodes'
                % (cmd, UtilMgr.convNum(nrTarget))
            )

            """
            receive an ACK packet
            to prevent receiving two packets at once
            """
            connObj.recv()

            # send reply packet for command #
            connObj.send("run|%s" % value)

            # execute remote commands #
            pid = 0
            for addr in list(nodeList):
                if targetList and not addr.replace(":", "/") in targetList:
                    continue

                # create a new worker process #
                pid = SysMgr.createProcess()
                if pid > 0:
                    continue

                try:
                    # get host name #
                    if addr in nodeList:
                        hostinfo = "%s@" % nodeList[addr]["host"]
                    else:
                        hostinfo = ""

                    SysMgr.printInfo(
                        "execute '%s' at %s%s for %s:%s"
                        % (cmd, hostinfo, addr, connObj.ip, connObj.port)
                    )

                    # disable log #
                    SysMgr.logEnable = False

                    # execute a command from a remote node #
                    rcmd = "%s|%s" % (addr, cmd)
                    SysMgr.runClientMode(rcmd, connObj)
                except SystemExit:
                    pass
                except:
                    SysMgr.logEnable = True
                    SysMgr.printErr(
                        "failed to execute '%s' at %s for %s:%s"
                        % (cmd, addr, connObj.ip, connObj.port)
                    )

                sys.exit(0)

            # wait for termination for remote commands #
            if pid > 0 and sync:
                SysMgr.waitChild()

        def _register(connObj):
            # create a new socket for TCP #
            rip = SysMgr.remoteServObj.ip
            rport = SysMgr.remoteServObj.port
            raddr = "%s:%s" % (rip, rport)
            caddr = "%s:%s" % (connObj.ip, connObj.port)
            cliObj = None
            errMsg = None

            while 1:
                try:
                    # create a new socket for TCP #
                    cliObj = NetworkMgr.setRemoteServer(
                        raddr, tcp=True, verb=not cliObj
                    )

                    SysMgr.printWarn(
                        "try to connect to the agent (%s)" % raddr
                    )

                    # connect to the agent #
                    cliObj.connect()
                    SysMgr.printInfo("connected to the agent (%s)" % raddr)

                    # register agent info #
                    agentList["%s:%s" % (cliObj.ip, cliObj.port)] = True

                    # init error message #
                    errMsg = None

                    # get host name #
                    hostname = NetworkMgr.getHostName()

                    # register to another server #
                    ret = NetworkMgr.getCmdPipe(
                        cliObj, "new:%s/%s" % (hostname, caddr)
                    )
                    if not ret:
                        # try to connect again #
                        time.sleep(1)
                        continue

                    # monitor connection #
                    cliObj.recv()
                except SystemExit:
                    sys.exit(0)
                except:
                    # print error message #
                    curErrMsg = SysMgr.getErrMsg()
                    if errMsg != curErrMsg:
                        SysMgr.printErr(
                            "failed to keep connection with the agent (%s)"
                            % raddr,
                            True,
                        )
                        SysMgr.printInfo(
                            "start trying to connect to the agent (%s)" % raddr
                        )

                    # update latest error message #
                    errMsg = curErrMsg

                    # remove agent info #
                    try:
                        agentList.pop("%s:%s" % (cliObj.ip, cliObj.port), None)
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass

                    # close invalid socket #
                    if cliObj.connected:
                        cliObj.close()

                    cliObj.connected = False

                    # retry after 1 second #
                    time.sleep(1)

        def _loadConfig():
            initCmds = []
            eventHandlers = {}

            # get server config #
            config = SysMgr.getConfigItem("server")
            if not config:
                return initCmds

            SysMgr.printInfo(
                "loaded server config from '%s'" % SysMgr.confFileName
            )

            # print config #
            SysMgr.printWarn(UtilMgr.convDict2Str(config))

            if "INIT" in config and type(config["INIT"]) is list:
                # get command shortcut #
                if "COMMAND" in config and type(config["COMMAND"]) is dict:
                    cmds = config["COMMAND"]
                else:
                    cmds = []

                # get valid commands #
                for item in config["INIT"]:
                    if not "apply" in item or item["apply"] != "true":
                        continue
                    elif not "command" in item:
                        continue

                    # convert command shortcut to real command #
                    if UtilMgr.isString(item["command"]):
                        pcmds = item["command"].split("->")
                        clist = []

                        for pcmd in pcmds:
                            if pcmd in cmds:
                                pcmd = cmds[pcmd]
                            clist.append(pcmd)

                        item["command"] = "->".join(clist)
                    elif type(item["command"]) is list:
                        newCmdList = []
                        for command in item["command"]:
                            pcmds = command.split("->")
                            clist = []

                            for pcmd in pcmds:
                                if pcmd in cmds:
                                    pcmd = cmds[pcmd]
                                clist.append(pcmd)

                            command = "->".join(clist)
                            newCmdList.append(command)
                        item["command"] = newCmdList
                    else:
                        continue

                    # add command to list #
                    initCmds.append(item)

            if initCmds:
                SysMgr.printInfo(
                    "applied init commands from '%s'" % SysMgr.confFileName
                )

                # print thresholds #
                if SysMgr.warnEnable:
                    SysMgr.printWarn(UtilMgr.convDict2Str(initCmds))

            if "EVENT" in config and type(config["EVENT"]) is list:
                # get valid commands #
                for item in config["EVENT"]:
                    if not "apply" in item or item["apply"] != "true":
                        continue

                    # check duplicated registation #
                    name = item["name"]
                    if name in eventHandlers:
                        SysMgr.printWarn(
                            "'%s' event handler is already registered" % name,
                            True,
                        )
                        continue

                    # register handler #
                    eventHandlers[name] = item

            if eventHandlers:
                SysMgr.printInfo(
                    "applied event handlers from '%s'" % SysMgr.confFileName
                )

                # print thresholds #
                if SysMgr.warnEnable:
                    SysMgr.printWarn(UtilMgr.convDict2Str(eventHandlers))

            return initCmds, eventHandlers

        def _runEventHandlers(event):
            # check event handler #
            if event not in eventHandlers:
                SysMgr.printErr("no event handler registered for '%s'" % event)
                return

            pid = 0
            for name, value in eventHandlers.items():
                # command #
                if "command" in value:
                    for cmd in value["command"]:
                        SysMgr.printInfo(
                            "execute '%s' via %s event" % (cmd, event)
                        )

                        # create a new worker process to execute a command #
                        pid = SysMgr.createProcess(cmd)
                        if pid == 0:
                            sys.exit(0)

                # handler #
                if "handler" in value:
                    for value in value["handler"]:
                        SysMgr.printInfo(
                            "call '%s' via %s event" % (value, event)
                        )

                        # create a new worker process #
                        pid = SysMgr.createProcess()
                        if pid != 0:
                            continue

                        # get function items #
                        cmd = value.split(":")
                        path, func = cmd[:2]
                        if len(cmd) > 2:
                            argset = cmd[2:]
                        else:
                            argset = []

                        # call handler #
                        res = UtilMgr.callPyFunc(path, func, argset)

            # wait for termination for remote commands #
            if pid != 0:
                SysMgr.waitChild()

        def _runInitCmds(addr, initCmds):
            for item in initCmds:
                # check command #
                if not "command" in item:
                    continue

                # check permission #
                if "perm" in item and item["perm"] == "root":
                    SysMgr.checkRootPerm(
                        msg="execute init command\n'%s'"
                        % UtilMgr.convDict2Str(item)
                    )

                # set timer #
                if "duration" in item:
                    sec = UtilMgr.convUnit2Time(item["duration"])
                    signal.signal(signal.SIGALRM, SysMgr.onAlarmExit)
                    signal.alarm(sec)

                # execute init commands #
                for cmd in item["command"]:
                    # split command by pipe character #
                    pipeCmds = cmd.split("->")

                    # normal command #
                    if len(pipeCmds) == 1:
                        # run remote task #
                        try:
                            rcmd = "%s|%s" % (addr, cmd)
                            SysMgr.runClientMode(rcmd)
                        except SystemExit:
                            continue
                        except:
                            SysMgr.printErr(
                                "failed to execute remote command '%s'" % rcmd,
                                reason=True,
                            )
                    # piped command #
                    elif len(pipeCmds) == 2:
                        # create a pipe #
                        rd, wr = os.pipe()

                        # create a new process #
                        pid = SysMgr.createProcess()
                        # writer relaying remote task #
                        if pid > 0:
                            # set stdio #
                            os.close(rd)
                            os.dup2(wr, 1)

                            # run remote task #
                            try:
                                pcmd = pipeCmds[0]
                                rcmd = "%s|%s" % (addr, pcmd)
                                SysMgr.runClientMode(rcmd)
                            except SystemExit:
                                continue
                            except:
                                SysMgr.printErr(
                                    "failed to execute remote command '%s'"
                                    % rcmd,
                                    reason=True,
                                )
                        # reader handling data #
                        else:
                            # set stdio #
                            os.close(wr)
                            os.dup2(rd, 0)

                            # run local task #
                            pcmd = pipeCmds[1].split()
                            SysMgr.executeProcess(cmd=pcmd, closeFd=False)
                    else:
                        SysMgr.printErr(
                            (
                                "no support piped command set bigger than 2 "
                                "for '%s'"
                            )
                            % cmd
                        )

        def _handleConn(connObj, connMan, initCmds=[], eventHandlers={}):
            # read command #
            req = connObj.recvfrom()

            # unmarshalling #
            if type(req) is tuple:
                # check garbage value #
                if req[0] == "":
                    return

                try:
                    message = req[0].decode()
                except:
                    message = req[0]

                if req[1] is None:
                    ip = connObj.ip
                    port = connObj.port
                else:
                    try:
                        ip = req[1][0]
                        port = req[1][1]
                    except:
                        SysMgr.printWarn(
                            "failed to get address of client from message"
                        )
                        return False

                SysMgr.printInfo(
                    "received the request '%s' from %s:%s"
                    % (message, ip, port)
                )
            else:
                SysMgr.printErr("received wrong request '%s'" % req)
                return False

            # get request and value #
            try:
                request, value = message.split(":", 1)
            except:
                request = value = None
                request = message

            # convert request to capital #
            request = request.upper()

            # define valid request list #
            requestList = {
                "BROADCAST": _onBroadcast,
                "CLEAR": _onClear,
                "DOWNLOAD": _onDownload,
                "JOBS": _onJobs,
                "LIST": _onList,
                "NEW": _onNew,
                "NOTIFY": _onNotify,
                "PING": _onPing,
                "RESTART": _onRestart,
                "RUN": _onRun,
                "UPSTREAM": _onUpstream,
                "UPLOAD": _onUpload,
            }

            # check request type #
            if not request in requestList:
                SysMgr.printWarn(
                    "failed to recognize the request '%s'" % message, True
                )

                _sendErrMsg(connObj, "no support the request '%s'" % message)

                return False
            elif request == "NEW":
                # register a new node #
                requestList[request](connObj, value, None)
                if not initCmds:
                    return False
            elif request == "CLEAR":
                # terminate all worker processes #
                requestList[request](connObj, value, None)
                return True
            elif request == "JOBS":
                # list all worker processes #
                requestList[request](connObj, value, None)
                return True
            elif request == "BROADCAST":
                # update service node list #
                _updateNodeList()
            elif request == "RESTART":
                SysMgr.printInfo("RESTART by %s:%s" % (ip, port))

                # restart with all nodes connected #
                try:
                    _onBroadcast(connObj, request, None, sync=False)
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printWarn(
                        "failed to handle %s command for all nodes" % request,
                        always=True,
                        reason=True,
                    )

                # close sockets #
                try:
                    connMan.close()
                except:
                    pass

                try:
                    connObj.close()
                except:
                    pass

                # restart server #
                SysMgr.restart()

            cmd = None
            if request == "NEW":
                # create new worker processes #
                for item in initCmds:
                    pid = SysMgr.createProcess()
                    if pid == 0:
                        cmd = item
                        break

                # connection manager return #
                if pid > 0:
                    return False
            else:
                # create a new worker process #
                pid = SysMgr.createProcess()
                if pid > 0:
                    return True

            # close listen socket of parent #
            if connMan:
                connMan.close()

            # save timestamp #
            before = time.time()

            # request init command #
            if request == "NEW":
                # remove host name from address #
                value = value.split("/", 1)[1]

                _runInitCmds(value, [cmd])
            # handle request #
            else:
                # build response data #
                response = "%s|%s" % (request, value)

                requestList[request](connObj, value, response)

            # print elapsed time #
            elapsed = time.time() - before
            SysMgr.printInfo(
                "elapsed %.6f for '%s' from %s:%s"
                % (elapsed, message, ip, port)
            )

            sys.exit(0)

        # start server mode #
        SysMgr.printInfo("SERVER MODE")

        # set default logger #
        if not SysMgr.stdlog:
            # get current time #
            try:
                datetime = SysMgr.getPkg("datetime", False)
                now = datetime.datetime.utcfromtimestamp(time.time())
                now = now.strftime("%y%m%dT%H%M%S")
            except SystemExit:
                sys.exit(0)
            except:
                now = long(time.time())

            # set file name #
            value = os.path.join(
                SysMgr.tmpPath, "guider_server_%s_%s.log" % (SysMgr.pid, now)
            )
            SysMgr.printInfo("applied '%s' as the log file" % value)

            # set logger #
            SysMgr.stdlog = LogMgr(value)

        # load config #
        try:
            initCmds, eventHandlers = _loadConfig()
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("failed to load config", reason=True)
            initCmds = eventHandlers = []

        # import packages #
        SysMgr.getPkg("select")
        socket = SysMgr.getPkg("socket")

        # get IP and PORT #
        if SysMgr.localServObj:
            ip = SysMgr.localServObj.ip
            port = SysMgr.localServObj.port
            SysMgr.localServObj.close()
        else:
            ip = port = None

        # set local address #
        connMan = NetworkMgr.setServerNetwork(
            ip, port, force=True, blocking=True, tcp=True
        )
        if not connMan:
            return

        # register to another server as a service node #
        if SysMgr.remoteServObj:
            # create a new thread to manage socket #
            threadObj = SysMgr.getPkg("threading")
            tobj = threadObj.Thread(target=_register, args=[connMan])
            tobj.daemon = True
            tobj.start()

        SysMgr.printStat(
            "run server(%s:%s) in %s(%s)"
            % (
                SysMgr.localServObj.ip,
                SysMgr.localServObj.port,
                SysMgr.getComm(SysMgr.pid),
                SysMgr.pid,
            )
        )

        # set SA_RESTART for SIGCHLD #
        signal.siginterrupt(signal.SIGCHLD, False)

        # listen #
        try:
            connMan.listen()
            connMan.timeout()
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to listen to prepare for connection", True)
            sys.exit(-1)

        # run mainloop #
        while 1:
            # accept #
            try:
                sock, addr = connMan.accept()
            except SystemExit:
                sys.exit(0)
            except IOError as err:
                if err.errno != errno.EINTR:
                    SysMgr.printWarn(
                        "failed to accept the connection request", reason=True
                    )
                continue
            except socket.timeout:
                continue
            except:
                SysMgr.printWarn(
                    "failed to accept the connection request", reason=True
                )
                continue

            SysMgr.printInfo(
                "connected to the new client (%s:%s)" % (addr[0], addr[1])
            )

            # create a TCP socket #
            connObj = NetworkMgr(
                "server", addr[0], addr[1], tcp=True, bind=False
            )
            if not connObj or not connObj.ip:
                continue

            # apply connected socket to object #
            connObj.socket = sock

            # handle request from client #
            if _handleConn(connObj, connMan, initCmds, eventHandlers):
                connObj.close()
                SysMgr.printBgProcs()

        sys.exit(0)

    @staticmethod
    def runClientMode(cmds=None, writer=None):
        def _printMenu():
            sys.stdout.write("%s\n" % SysMgr.cliCmdStr)

        def _doPing(uinput, cmd=None, hasarg=False):
            # set default command to ping #
            if not cmd:
                cmd = "ping"

            # get args #
            args = UtilMgr.lstrip(uinput, [cmd, cmd.upper()])
            if args and not args[0].isdigit():
                args = args[1:]

            # set variable #
            if hasarg:
                items = args
                addrs = None
            else:
                addrs = args
                items = ""

            # classify IP and PORT #
            if addrs:
                service, ip, port = NetworkMgr.parseAddr(addrs)
                if service == ip == port == None:
                    SysMgr.printErr(
                        "failed to recognize command %s" % uinput, True
                    )
                    return
                else:
                    NetworkMgr.setRemoteServer(addrs, tcp=True)

            # append args to command #
            if items:
                cmd = "%s|%s" % (cmd, items)

            # request command #
            ret = NetworkMgr.requestPing(cmd=cmd)

            # PING #
            ucmd = cmd.upper()
            if ucmd.startswith("PING"):
                if ret:
                    SysMgr.printInfo("server is alive")
                else:
                    SysMgr.printInfo("server is not responding")
            # RESTART #
            elif ucmd.startswith("RESTART"):
                SysMgr.printInfo("server is restarted")

        def _printHistory(hlist):
            print("\n<History>")
            if hlist:
                for idx, cmd in enumerate(hlist):
                    print(
                        "[%0d] %s" % (idx, UtilMgr.convColor(cmd, "UNDERLINE"))
                    )
                print('input "! + index" to execute the above commands')
            else:
                print("no history")

        def _getUserInput():
            _printMenu()
            sys.stdout.write("input command for request...\n=> ")
            sys.stdout.flush()

            return sys.stdin.readline()[:-1]

        def _convUserCmd(uinput):
            uinputUpper = uinput.upper()
            if uinputUpper.startswith("D:"):
                uinput = "download" + uinput[1:]
            elif uinputUpper.startswith("U:"):
                uinput = "upload" + uinput[1:]
            elif uinputUpper.startswith("R:"):
                uinput = "run" + uinput[1:]
            elif uinputUpper.startswith("B:"):
                uinput = "broadcast" + uinput[1:]
            elif uinputUpper.startswith("S:"):
                uinput = "upstream" + uinput[1:]
            elif uinputUpper.startswith("N:"):
                uinput = "notify" + uinput[1:]
            elif uinputUpper == "H":
                uinput = "history"
            elif uinputUpper == "P":
                uinput = "ping"
            elif uinputUpper == "L":
                uinput = "list"
            elif uinputUpper == "C":
                uinput = "clear"
            elif uinputUpper == "J":
                uinput = "jobs"
            elif uinputUpper == "Q":
                uinput = "quit"

            return uinput

        def _execUserCmd(uinput, addr=None, retPipe=False):
            def _unsetAlarm():
                if SysMgr.isLinux:
                    signal.signal(signal.SIGALRM, SysMgr.defaultHandler)

            def _setAlarm():
                if SysMgr.isLinux:
                    signal.signal(signal.SIGALRM, SysMgr.onAlarmExit)
                    SysMgr.intervalEnable = 1
                    SysMgr.repeatCount = sys.maxsize

            # check short command #
            uinputUpper = uinput.upper()
            if uinputUpper.startswith("PING"):
                _doPing(uinput)
                return
            elif uinputUpper.startswith("RESTART"):
                _doPing(uinputUpper, "RESTART", hasarg=True)
                return

            # launch remote command #
            pipe = NetworkMgr.execRemoteCmd(uinput, addr)
            if not pipe:
                if addr:
                    addrstr = " at %s" % addr
                else:
                    addrstr = ", check server IP and port"

                SysMgr.printErr("failed to execute '%s'%s" % (uinput, addrstr))
                return

            # return pipe or True #
            if retPipe or pipe is True:
                return pipe

            # set alarm #
            _setAlarm()

            # block signal #
            SysMgr.blockSignal(act="block")

            # set print flag #
            printFlag = SysMgr.getPrintFlag()

            while 1:
                try:
                    SysMgr.updateTimer()

                    output = pipe.getData()
                    if not output:
                        break

                    dataType = pipe.getDataType(output)

                    if printFlag:
                        print(output[:-1])
                except SystemExit:
                    if not SysMgr.isLinux:
                        break
                except KeyboardInterrupt:
                    break
                except:
                    SysMgr.printErr(SysMgr.getErrMsg())
                    break

                if SysMgr.pendingSignal(signal.SIGINT):
                    break

            # close running remote task #
            try:
                pipe.close()
            except:
                pass

            # disable alarm handler #
            _unsetAlarm()

            # unblock signal #
            SysMgr.blockSignal(act="unblock")

        # start client mode #
        SysMgr.printInfo("CLIENT MODE")

        # load libc #
        if SysMgr.loadLibcObj():
            # disable SIGINT #
            signal.signal(signal.SIGINT, signal.SIG_IGN)

        # get argument #
        if cmds:
            cmdList = cmds.split(",")
            cmdList = UtilMgr.cleanItem(cmdList, False)
        elif SysMgr.hasMainArg():
            cmdList = SysMgr.getMainArgs(False)
        elif SysMgr.customCmd:
            cmdList = SysMgr.customCmd
        else:
            cmdList = []

        # set environment for parallel commands #
        if cmdList:
            SysMgr.setDefaultSignal()

            selectObj = SysMgr.getPkg("select")

            # print window size for commands #
            windowSize = long(SysMgr.ttyRows / len(cmdList))
            SysMgr.printInfo("set each window height to %s" % (windowSize + 2))

            # get print flag #
            printFlag = SysMgr.getPrintFlag()

            # set default writer #
            if not writer:
                writer = sys.stdout

        # save timestamp for start #
        start = time.time()

        # run parallel commands #
        cmdPipeList = {}
        for idx, uinput in enumerate(cmdList):
            fullInput = uinput

            # get address #
            if "|" in uinput:
                addr, uinput = uinput.split("|", 1)
            else:
                addr = None

            # convert command shortcut #
            uinput = _convUserCmd(uinput)

            # fit Guider's window size #
            if uinput.startswith("run:GUIDER") and not " -m" in uinput:
                uinput += " -m %s:%s" % (windowSize + 2, SysMgr.ttyCols)

            # execute an user command #
            pipe = _execUserCmd(uinput, addr, retPipe=True)
            if not pipe:
                sys.exit(0)
            elif pipe is True:
                continue

            # set timeout #
            pipe.timeout(0.1)

            # register socket to command list #
            cmdPipeList[pipe.socket] = [fullInput, pipe, [""] * SysMgr.ttyRows]

        # run mainloop for parallel commands #
        while 1:
            if not cmdPipeList:
                if cmdList:
                    SysMgr.printInfo(
                        "elapsed %.6f for '%s'"
                        % (time.time() - start, ", ".join(cmdList))
                    )
                    sys.exit(0)
                break

            try:
                # set fds #
                listenFds = [item for item in cmdPipeList]

                if len(listenFds) > 1:
                    isMulti = True
                else:
                    isMulti = False

                # update window size #
                windowSize = long(SysMgr.ttyRows / len(cmdPipeList))
                mod = SysMgr.ttyRows % windowSize

                # wait for event #
                [read, write, error] = selectObj.select(listenFds, [], [], 0.1)

                # handle output from multiple commands #
                for robj in read:
                    while 1:
                        # clear screen #
                        if len(cmdPipeList) > 1:
                            SysMgr.clearScreen()

                        # read output #
                        output = cmdPipeList[robj][1].getData(noTimeout=False)
                        if output == "\n":
                            if isMulti:
                                break
                            continue
                        elif not output:
                            cmdPipeList.pop(robj, None)
                            break

                        # handle output #
                        if len(cmdPipeList) == 1:
                            if printFlag:
                                writer.write(output)
                            if isMulti:
                                break
                            else:
                                continue

                        # update a surface #
                        fullSurface = ""
                        surface = cmdPipeList[robj][2]
                        output = [line for line in output.split("\n") if line]
                        surface = surface[len(output) :] + output
                        cmdPipeList[robj][2] = surface

                        # composite surfaces #
                        nrLine = 0
                        for idx, item in enumerate(cmdPipeList.values()):
                            surface = item[2]

                            if idx == len(cmdPipeList) - 1:
                                nrStrip = (
                                    SysMgr.ttyRows - nrLine - windowSize - 1
                                )
                                window = surface[-windowSize:nrStrip]
                            else:
                                window = surface[-windowSize:]

                            nrLine += len(window) + 1

                            if idx < len(cmdPipeList) - 1:
                                fullSurface += "\n".join(window)
                                fullSurface += "\n%s\n" % splitLine
                            else:
                                fullSurface += "\n".join(window)
                                fullSurface += "\n"

                        # update screen in 20 FPS #
                        if printFlag:
                            writer.write(fullSurface)

                        # delay for overhead #
                        time.sleep(0.05)

                        if isMulti:
                            break
            except SystemExit:
                sys.exit(0)
            except KeyboardInterrupt:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "failed to handle multiple commands", reason=True
                )

        # run mainloop for user interaction #
        hlist = []
        while 1:
            try:
                isHistory = False

                # get input #
                uinput = _getUserInput()

                # check input for history #
                if uinput.startswith("!") and len(uinput) > 1:
                    try:
                        uinput = hlist[long(uinput[1:])]
                        isHistory = True
                    except:
                        SysMgr.printErr(
                            "wrong history index for '%s'" % uinput[1:]
                        )
                        continue

                # convert command shortcut #
                uinput = _convUserCmd(uinput)
                uinputUpper = uinput.upper()

                # handle local command #
                if not uinput or uinput == "!" or uinputUpper == "HISTORY":
                    _printHistory(hlist)
                    continue
                elif uinputUpper.startswith("PING"):
                    _doPing(uinput)
                    continue
                elif uinputUpper == "QUIT":
                    break

                # backup command #
                if not isHistory and (not hlist or hlist[-1] != uinput):
                    hlist.append(uinput)

                # execute an user command #
                _execUserCmd(uinput)
            except SystemExit:
                return
            except:
                pass

    @staticmethod
    def getIdleTime():
        try:
            # read stat buf #
            cpuBuf = SysMgr.readProcStat(
                SysMgr.statFd, "stat", SysMgr, "statFd"
            )
            return long(cpuBuf[0].split()[4])
        except SystemExit:
            sys.exit(0)
        except:
            return 0

    @staticmethod
    def getNrCore():
        if SysMgr.nrCore > 0:
            return SysMgr.nrCore

        if not SysMgr.isLinux:
            try:
                # get psutil object #
                psutil = SysMgr.getPkg("psutil", False)
                nrCore = psutil.cpu_count()
                SysMgr.nrCore = nrCore
                return nrCore
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn(
                    "failed to get the number of CPU", reason=True
                )
                return 0

        # read stat buf #
        cpuBuf = SysMgr.readProcStat(SysMgr.statFd, "stat", SysMgr, "statFd")

        nrCore = 0
        if cpuBuf:
            for line in cpuBuf:
                statList = line.split()
                cpuId = statList[0]
                if cpuId != "cpu" and cpuId.startswith("cpu"):
                    nrCore += 1

            # set the number of core #
            SysMgr.nrCore = nrCore

        return nrCore

    @staticmethod
    def doDrawReq():
        def _drawRes(stats):
            # pylint: disable=undefined-variable
            def _drawMeta(labelList=None):
                # pylint: disable=undefined-variable
                # draw label #
                TaskAnalyzer.drawLabel(labelList, draw=True, anchor=(1.12, 1))

                # update yticks #
                TaskAnalyzer.drawYticks(ax, ymax=None, adjust=False)

                # draw time unit #
                try:
                    ytickLabel = ax.get_yticks().tolist()
                    ytickLabel = list(map(long, ytickLabel))
                    ytickLabel = [val for val in ytickLabel]
                    ytickLabel[0] = "ms"

                    # apply formatter #
                    ax.set_yticks(ax.get_yticks().tolist())
                    ax.set_yticklabels(ytickLabel)
                except:
                    pass

                # draw grid #
                xticks(fontsize=self.xfsize)
                grid(which="both", linestyle=":", linewidth=0.2)
                tick_params(axis="x", direction="in")
                tick_params(axis="y", direction="in")

            # draw base #
            figObj = TaskAnalyzer.drawFigure()

            # draw title #
            ax = subplot2grid((6, 1), (0, 0), rowspan=3, colspan=1)
            ax.xaxis.set_major_locator(MaxNLocator(integer=True))
            suptitle("Guider Response Graph", fontsize=8)

            # define integrated request list for processes #
            totalStats = {}
            maxLabelLen = 80

            # draw line plots for per-process requests #
            labelList = []
            for req, stat in stats.items():
                timeline = stat["reqtime"]
                response = stat["restime"]

                realreq = req[req.find(")_") + 2 :]
                totalStats.setdefault(realreq, [])
                totalStats[realreq] += response

                # draw total GPU graph #
                plot(
                    timeline,
                    response,
                    "-",
                    linewidth=1,
                    marker="d",
                    markersize=1,
                    solid_capstyle="round",
                )

                labelList.append(req[:maxLabelLen])

            # set xticks #
            try:
                xtickLabel = ax.get_xticks().tolist()

                try:
                    datetime = SysMgr.getPkg("datetime")

                    # convert time unit #
                    for idx, item in enumerate(xtickLabel):
                        ms = item % 1000
                        value = datetime.datetime.utcfromtimestamp(item / 1000)
                        xtickLabel[idx] = value.strftime("%H:%M:%S")
                        xtickLabel[idx] = "%s.%0.3d" % (xtickLabel[idx], ms)
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printWarn(
                        "failed to convert time unit in xticks", reason=True
                    )

                xtickLabel[-1] = "Time"
                ax.set_xticks(ax.get_xticks())
                ax.set_xticklabels(xtickLabel)
            except SystemExit:
                sys.exit(0)
            except:
                pass

            _drawMeta(labelList)

            # draw bar plots for requests #
            ax = subplot2grid((6, 1), (3, 0), rowspan=3, colspan=1)
            ax.xaxis.set_major_locator(MaxNLocator(integer=True))

            start = 0
            width = 0.1
            for req, value in totalStats.items():
                totval = sum(value)
                avgval = totval / len(value)
                minval = min(value)
                maxval = max(value)
                data = [minval, avgval, maxval]

                # draw bar #
                brange = []
                for idx in xrange(-1, 2):
                    brange.append(start + idx / 10)
                ax.bar(
                    brange,
                    data,
                    width=width,
                    edgecolor="white",
                    label=req[:maxLabelLen],
                )

                # draw stat text on the bar #
                for idx, value in enumerate(data):
                    text(
                        start + (idx - 1) / 10,
                        value,
                        UtilMgr.convNum(value),
                        color="black",
                        fontweight="bold",
                        fontsize=self.lfsize,
                    )

                # draw name text over the bar #
                text(
                    start,
                    maxval / 2,
                    req[:maxLabelLen],
                    color="black",
                    fontsize=self.lfsize,
                    rotation=35,
                )

                start += 1

            # set ticks #
            try:
                xtickLabel = ax.get_xticks().tolist()
                xtickLabel = list(map(long, xtickLabel))
                xtickLabel = list(xrange(-1, len(totalStats) + 1))
                ax.set_xticks(xtickLabel)
                xtickLabel[0] = ""
                xtickLabel[-1] = "Req"
                for idx in xrange(1, len(totalStats) + 1):
                    xtickLabel[idx] = "Min/Avg/Max"
                ax.set_xticklabels(xtickLabel)
            except:
                pass

            _drawMeta(None)

            # save to file #
            TaskAnalyzer.saveImage(SysMgr.inputFile, "graph")

        def _getDrawStat(path):
            try:
                fd = open(path, "r")
                data = fd.readlines()
                fd.close()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("failed to read '%s'" % path, reason=True)
                sys.exit(-1)

            startPos = -1
            task = None
            for idx, line in enumerate(data):
                if line.startswith("[Response Time]"):
                    for item in line.split("["):
                        if item.startswith("Task:"):
                            task = item[5:].strip().rstrip("]")
                    startPos = idx + 4
                    break

            # check start pos #
            if startPos == -1:
                SysMgr.printErr("failed to recognize '%s'" % path)
                sys.exit(-1)

            edata = data[startPos:]

            # parse response time for requests #
            resTable = {}
            for line in edata:
                if not line.strip():
                    break
                elif line.startswith(oneLine):
                    continue

                req, times = line.split("|", 1)

                # check filter #
                if SysMgr.filterGroup:
                    if not UtilMgr.isValidStr(req):
                        continue

                # add timestamps in ms #
                reqtimeList = []
                restimeList = []
                timeList = times.split(",")
                for item in timeList:
                    reqtime, restime = item.split("/")
                    reqtimeList.append(float(reqtime) * 1000)
                    restimeList.append(float(restime) * 1000)

                # initialize lists #
                reqid = "%s_%s" % (task, req)
                resTable.setdefault(reqid, {})
                resTable[reqid].setdefault("reqtime", [])
                resTable[reqid].setdefault("restime", [])

                resTable[reqid]["reqtime"] += reqtimeList
                resTable[reqid]["restime"] += restimeList

            return resTable

        # initialize environment for drawing #
        TaskAnalyzer.initDrawEnv()

        # get argument #
        if SysMgr.hasMainArg():
            inputParam = SysMgr.getMainArg().split(",")
            inputParam = UtilMgr.getFileList(inputParam)
        elif SysMgr.inputParam:
            inputParam = SysMgr.inputParam.split(",")
            inputParam = UtilMgr.getFileList(inputParam)
        else:
            inputParam = [SysMgr.outFilePath]

        # check input path #
        if not inputParam:
            SysMgr.printErr("no input for path")
            sys.exit(-1)

        # get response time from file #
        stats = {}
        for path in inputParam:
            try:
                if not os.path.exists(path):
                    raise Exception("not exist")

                SysMgr.printStat(r"start loading '%s'..." % path)
                stat = _getDrawStat(path)
                if not stat:
                    raise Exception("no data")
                stats.update(stat)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "failed to get stats from '%s'" % path, reason=True
                )
                sys.exit(-1)

        SysMgr.printStat(r"start drawing graphs...")

        # draw response time #
        _drawRes(stats)

    @staticmethod
    def doConvert():
        # remove option args #
        SysMgr.removeOptionArgs()

        # get argument #
        if SysMgr.hasMainArg():
            value = SysMgr.getMainArg()
        else:
            SysMgr.printErr(
                "no path to convert file, input the path of a text file"
            )
            sys.exit(-1)

        # check file #
        if not os.path.isfile(value):
            SysMgr.printErr("wrong path '%s' for converting" % value)
            sys.exit(-1)

        # set output file name #
        SysMgr.imagePath = os.path.splitext(value)[0]

        # open text file #
        try:
            with open(value, "r") as fd:
                textBuf = fd.read()
        except:
            SysMgr.printErr("failed to read data from %s" % value)
            sys.exit(-1)

        # draw image #
        SysMgr.drawText(textBuf)

    @staticmethod
    def doSetCpu():
        freqPath = "/sys/devices/system/cpu"

        SysMgr.checkRootPerm()

        # check CPU driver #
        if not os.path.isdir(freqPath):
            SysMgr.printErr("failed to find CPU node for governor")
            sys.exit(-1)

        # get argument #
        if SysMgr.hasMainArg():
            filterGroup = SysMgr.getMainArgs()
        elif SysMgr.filterGroup:
            filterGroup = SysMgr.filterGroup
        else:
            SysMgr.printErr("no input for core info")
            sys.exit(-1)

        # parse values #
        targetlist = []
        for val in list(filterGroup):
            vals = val.split(":")

            # check error #
            if (
                (len(vals) < 2 or len(vals) > 3)
                or (vals[0] and not vals[0].isdigit())
                or (vals[1] and not vals[1].isdigit())
            ):
                SysMgr.printErr(
                    (
                        "wrong value to set CPU clock, "
                        "input in the format CORE:CLOCK(HZ){:GOVERNOR}"
                    )
                )
                sys.exit(-1)

            targetlist.append(vals)

        # get available CPU list #
        cpulist = {}
        for f in sorted(os.listdir(freqPath)):
            if not f.startswith("cpu"):
                continue

            cpu = f.split("cpu")[1]
            if not cpu.isdigit():
                continue

            # set path #
            commonpath = "%s/%s/cpufreq" % (freqPath, f)
            affectpath = "%s/affected_cpus" % commonpath
            govpath = "%s/scaling_available_governors" % commonpath
            curgovpath = "%s/scaling_governor" % commonpath
            availfreqpath = "%s/scaling_available_frequencies" % commonpath
            curfreqpath = "%s/scaling_cur_freq" % commonpath
            minfreqpath = "%s/scaling_min_freq" % commonpath
            maxfreqpath = "%s/scaling_max_freq" % commonpath

            cpulist[cpu] = {}

            # affected_cpus #
            try:
                with open(affectpath, "r") as fd:
                    cpulist[cpu]["affect"] = fd.readlines()[0].split()
            except SystemExit:
                sys.exit(0)
            except:
                pass

            # available_governors #
            try:
                with open(govpath, "r") as fd:
                    cpulist[cpu]["governors"] = fd.readlines()[0].split()
            except SystemExit:
                sys.exit(0)
            except:
                pass

            # available_freq #
            try:
                with open(availfreqpath, "r") as fd:
                    cpulist[cpu]["avail"] = list(
                        map(long, fd.readlines()[0].split())
                    )
                    cpulist[cpu]["avail"].sort()
                    cpulist[cpu]["avail"] = list(
                        map(str, cpulist[cpu]["avail"])
                    )
            except SystemExit:
                sys.exit(0)
            except:
                pass

            # freq #
            try:
                with open(minfreqpath, "r") as fd:
                    cpulist[cpu]["min"] = fd.readlines()[0]
                with open(maxfreqpath, "r") as fd:
                    cpulist[cpu]["max"] = fd.readlines()[0]
            except SystemExit:
                sys.exit(0)
            except:
                cpulist.pop(cpu, None)

        # set CPU clock #
        for vals in targetlist:
            if len(vals) == 2:
                core, clock = vals
                gov = None
            elif len(vals) == 3:
                core, clock, gov = vals

            # check values #
            if not core and not clock and not gov:
                SysMgr.printErr("no value for CPU")
                continue

            if not core:
                cpuRange = list(cpulist)
            else:
                cpuRange = [core]

            # check support #
            if not core:
                pass
            elif not core in cpulist:
                SysMgr.printErr(
                    (
                        "failed to set CPU(%s) clock because "
                        "it doesn't support governor"
                    )
                    % core
                )
                sys.exit(-1)
            # check available clock #
            elif (
                "avail" in cpulist[core]
                and clock
                and long(clock) > 0
                and not clock in cpulist[core]["avail"]
            ) or (gov and not gov in cpulist[core]["governors"]):

                try:
                    avail = " ".join(cpulist[core]["avail"])
                except:
                    avail = "?"

                governors = " ".join(cpulist[core]["governors"])

                SysMgr.printErr(
                    (
                        "failed to set CPU(%s) clock because it"
                        " only supports \n\t-clock: [%s]\n\t-governor: [%s]"
                    )
                    % (core, avail, governors)
                )
                sys.exit(-1)

            for core in cpuRange:
                # set path #
                commonpath = "%s/cpu%s/cpufreq" % (freqPath, core)
                curgovpath = "%s/scaling_governor" % commonpath
                minfreqpath = "%s/scaling_min_freq" % commonpath
                maxfreqpath = "%s/scaling_max_freq" % commonpath

                minres = maxres = govres = False

                # set clock range #
                try:
                    if clock and long(clock) > 0:
                        with open(minfreqpath, "w") as fd:
                            fd.write(clock)
                        with open(maxfreqpath, "w") as fd:
                            fd.write(clock)
                    if gov:
                        with open(curgovpath, "w") as fd:
                            fd.write(gov)
                except SystemExit:
                    sys.exit(0)
                except:
                    if not minres:
                        res = "min clock"
                    elif not maxres:
                        res = "max clock"
                    elif not govres:
                        res = "governor"

                    SysMgr.printErr(
                        "failed to set %s of CPU(%s)" % (res, core), True
                    )
                    sys.exit(-1)

                # cur_governor #
                try:
                    with open(curgovpath, "r") as fd:
                        curgovernor = fd.readlines()[0].split()[0]
                except SystemExit:
                    sys.exit(0)
                except:
                    curgovernor = "?"

                # get affected CPU list #
                if (
                    "affect" in cpulist[core]
                    and len(cpulist[core]["affect"]) > 1
                ):
                    affectstring = "and it also affects CPU(%s)" % "-".join(
                        cpulist[core]["affect"]
                    )
                else:
                    affectstring = ""

                if clock:
                    clockstr = "%shz " % UtilMgr.convNum(clock)
                else:
                    clockstr = ""

                SysMgr.printInfo(
                    "set CPU(%s) to %s[%s] successfully %s"
                    % (core, clockstr, curgovernor, affectstring)
                )

    @staticmethod
    def doSetSched():
        isProcess = False
        SysMgr.warnEnable = True

        # get argument #
        if SysMgr.hasMainArg(dash=True):
            value = SysMgr.getMainArgs()
        elif SysMgr.filterGroup:
            value = SysMgr.filterGroup
        else:
            SysMgr.printErr(
                (
                    "wrong value to set priority, "
                    "input in the format POLICY:PRIORITY|TIME:TID|COMM"
                )
            )
            sys.exit(-1)

        value = ",".join(value)

        while 1:
            # change priority #
            SysMgr.applyPriority(value)

            if not SysMgr.intervalEnable:
                break

            # wait for next tick #
            time.sleep(SysMgr.intervalEnable)

    @staticmethod
    def doPrintKconf():
        SysMgr.printLogo(big=True, onlyFile=True)

        # get path argument #
        if SysMgr.inputParam:
            inputParam = SysMgr.inputParam.split(",")
            inputParam = UtilMgr.getFileList(inputParam)
        elif os.path.exists("/proc/config.gz"):
            inputParam = "/proc/config.gz"
        else:
            inputParam = "/boot/config-%s" % SysMgr.getKernelVersion(name=True)

        # check config file #
        if not os.path.exists(inputParam):
            SysMgr.printErr("no kernel config file (%s)" % inputParam)

        # get filter argument #
        if SysMgr.hasMainArg():
            filterGroup = SysMgr.getMainArgs()
        elif SysMgr.filterGroup:
            filterGroup = SysMgr.filterGroup
        else:
            filterGroup = ""

        # get configs #
        try:
            if inputParam.endswith("gz"):
                configs = UtilMgr.ungzip(inputParam)
                configs = configs.decode().split("\n")
            else:
                configs = open(inputParam, "r").readlines()
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenErr(inputParam)
            return

        for config in configs:
            if filterGroup and not UtilMgr.isValidStr(
                config, filterGroup, ignCap=True
            ):
                continue
            SysMgr.printPipe(config)

    @staticmethod
    def doPrintVmalloc(topMode=False):
        if not topMode:
            SysMgr.pipeEnable = True
            SysMgr.printLogo(big=True, onlyFile=True)

        SysMgr.checkRootPerm()

        # get argument #
        if SysMgr.hasMainArg():
            target = SysMgr.getMainArgs()
        elif SysMgr.filterGroup:
            target = SysMgr.filterGroup
        else:
            target = []

        # read vmalloc info #
        instance = TaskAnalyzer(onlyInstance=True)
        instance.saveVmallocInfo()

        # set title and uptime #
        if topMode:
            title = "Top Vmalloc Info"
            uptime = "[Time: %.6f] " % SysMgr.updateUptime()
        else:
            title = "Vmalloc Info"
            uptime = ""

        # get total size #
        totalSize = sum([x["size"] for x in instance.vmallocData.values()])

        # print title #
        SysMgr.addPrint(
            "[%s] %s[NrItems: %s] [Total: %s] \n%s\n"
            % (
                title,
                uptime,
                UtilMgr.convNum(len(instance.vmallocData)),
                UtilMgr.convSize2Unit(totalSize),
                twoLine,
            ),
            newline=2,
        )
        SysMgr.addPrint(
            "{0:>7} {1:>1}\n{2:1}\n".format("SIZE", "NAME", twoLine), newline=2
        )

        # print vmalloc info #
        try:
            nrCnt = 0
            for name, items in sorted(
                instance.vmallocData.items(),
                key=lambda x: x[1]["size"],
                reverse=True,
            ):

                # check name #
                if target and not UtilMgr.isValidStr(name, target, inc=True):
                    continue

                SysMgr.addPrint(
                    "{0:>7} {1:>1}\n".format(
                        UtilMgr.convSize2Unit(items["size"]), name
                    ),
                    force=True,
                )
                nrCnt += 1

                # check terminal rows #
                if topMode and SysMgr.checkCutCond():
                    nrCnt = -1
                    break

            if nrCnt == 0:
                SysMgr.addPrint("\tNone\n")
            if nrCnt >= 0:
                SysMgr.addPrint("%s\n" % oneLine, force=True)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to print vmalloc info", True)
            sys.exit(-1)

        if topMode:
            SysMgr.printTopStats()
        else:
            SysMgr.doPrint()

    @staticmethod
    def doPrintSlab(topMode=False):
        if not topMode:
            SysMgr.pipeEnable = True
            SysMgr.printLogo(big=True, onlyFile=True)

        SysMgr.checkRootPerm()

        # get argument #
        if SysMgr.hasMainArg():
            target = SysMgr.getMainArgs()
        elif SysMgr.filterGroup:
            target = SysMgr.filterGroup
        else:
            target = []

        # read slab info #
        instance = TaskAnalyzer(onlyInstance=True)
        instance.saveSlabInfo()

        # set sort value #
        if SysMgr.sort:
            sortval = SysMgr.sort

            # check sort item #
            if not sortval in ("size", "active", "actsize", "total"):
                SysMgr.printErr("failed to sort by '%s'" % sortval)
                sys.exit(-1)
        else:
            sortval = "totsize"

        # set title and uptime #
        if topMode:
            title = "Top Slab Info"
            uptime = "[Time: %.6f] " % SysMgr.updateUptime()
        else:
            title = "Slab Info"
            uptime = ""

        # get total size #
        totalSize = sum([x["totsize"] for x in instance.slabData.values()])

        # print title #
        SysMgr.addPrint(
            "[%s] %s[NrItems: %s] [Total: %s]\n%s\n"
            % (
                title,
                uptime,
                UtilMgr.convNum(len(instance.slabData)),
                UtilMgr.convSize2Unit(totalSize),
                twoLine,
            ),
            newline=2,
        )
        SysMgr.addPrint(
            "{0:>11} {1:>11} {2:>4} {3:>7} {4:>12} {5:>12} {6:1}\n".format(
                "OBJS",
                "ACTIVE",
                "USE",
                "OBJSIZE",
                "ACTSIZE",
                "TOTSIZE",
                "NAME",
            )
        )
        SysMgr.addPrint("%s\n" % twoLine)

        conv = UtilMgr.convNum

        # print slab info #
        try:
            nrCnt = 0
            for name, items in sorted(
                instance.slabData.items(),
                key=lambda x: x[1][sortval],
                reverse=True,
            ):

                # check name #
                if target and not UtilMgr.isValidStr(name, target, inc=True):
                    continue

                total = items["total"]
                active = items["active"]
                if total > 0:
                    actper = long(active / float(total) * 100)
                else:
                    actper = 0
                size = items["size"] / float(1024)
                actsize = conv(long(items["actsize"] / 1024))
                totsize = conv(long(items["totsize"] / 1024))
                SysMgr.addPrint(
                    (
                        "{0:>11} {1:>11} {2:3}% {3:6.2f}K "
                        "{4:>11}K {5:>11}K {6:1}\n"
                    ).format(
                        conv(total),
                        conv(active),
                        actper,
                        size,
                        actsize,
                        totsize,
                        name,
                    ),
                    force=True,
                )
                nrCnt += 1

                # check terminal rows #
                if topMode and SysMgr.checkCutCond():
                    nrCnt = -1
                    break

            if nrCnt == 0:
                SysMgr.addPrint("\tNone\n")
            if nrCnt >= 0:
                SysMgr.addPrint("%s\n" % oneLine, force=True)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to print slab info", True)
            sys.exit(-1)

        if topMode:
            SysMgr.printTopStats()
        else:
            SysMgr.doPrint()

    @staticmethod
    def doPrintEnv():
        SysMgr.printLogo(big=True, onlyFile=True)

        SysMgr.checkRootPerm()

        # get argument #
        if SysMgr.hasMainArg():
            filterGroup = SysMgr.getMainArgs()
        elif SysMgr.filterGroup:
            filterGroup = SysMgr.filterGroup
        else:
            filterGroup = [str(SysMgr.pid)]

        pids = SysMgr.convTaskList(filterGroup, exceptMe=True)
        if not pids:
            SysMgr.printErr(
                "failed to find the process with PID %s"
                % ", ".join(filterGroup)
            )
            sys.exit(-1)

        # set line length #
        lenLine = long(len(oneLine) / 2)

        # check filter #
        if SysMgr.inputParam:
            filters = SysMgr.inputParam.split(",")
            filters = UtilMgr.cleanItem(filters)
        else:
            filters = []

        for pid in pids:
            comm = SysMgr.getComm(pid, True)

            if SysMgr.jsonEnable:
                envs = SysMgr.getEnv(pid, retdict=True)
                if not envs:
                    continue

                envs["PID"] = pid
                envs["COMM"] = comm
                envs = UtilMgr.convDict2Str(envs, pretty=False)
                SysMgr.printPipe(envs)
                continue

            envs = SysMgr.getEnv(pid)
            if not envs:
                continue

            # get cmdline #
            cmdline = SysMgr.getCmdline(pid)

            SysMgr.printPipe(
                "\n[Env Info] [Proc: %s(%s)] [Cmd: %s]\n%s\n"
                % (comm, pid, cmdline, oneLine[:lenLine])
            )

            # filter variables #
            if filters:
                filteredList = []
                for env in envs:
                    if UtilMgr.isValidStr(env, key=filters):
                        filteredList.append(env)
                envs = filteredList

            # print variables #
            for env in envs:
                SysMgr.printPipe(env)

            if not envs:
                SysMgr.printPipe("\tNone\n%s" % oneLine[:lenLine])
            else:
                SysMgr.printPipe(oneLine[:lenLine])

        SysMgr.printPipe("\n")

    @staticmethod
    def initNetlink():
        if not SysMgr.isLinux or SysMgr.netlinkObj:
            return

        array = SysMgr.getPkg("array", False)
        if not array:
            return

        # create netlink socket #
        sockObj = SysMgr.netlinkObj = NetworkMgr(
            "server", ip=0, port=0, anyPort=True, netlink=True, blocking=False
        )

        NLM_F_REQUEST = 1

        CTRL_CMD_UNSPEC = 0
        CTRL_CMD_NEWFAMILY = 1
        CTRL_CMD_DELFAMILY = 2
        CTRL_CMD_GETFAMILY = 3
        CTRL_CMD_NEWOPS = 4
        CTRL_CMD_DELOPS = 5
        CTRL_CMD_GETOPS = 6

        CTRL_ATTR_UNSPEC = 0
        CTRL_ATTR_FAMILY_ID = 1
        CTRL_ATTR_FAMILY_NAME = 2
        CTRL_ATTR_VERSION = 3
        CTRL_ATTR_HDRSIZE = 4
        CTRL_ATTR_MAXATTR = 5
        CTRL_ATTR_OPS = 6

        geAttrStruct = [
            9,  # 0 CTRL_ATTR_UNSPEC
            """=H""",  # 1 U16(skb, CTRL_ATTR_FAMILY_ID
            0,  # 2 STRING(skb, CTRL_ATTR_FAMILY_NAME
            """=I""",  # 3 U32(skb, CTRL_ATTR_VERSION
            """=I""",  # 4 U32(skb, CTRL_ATTR_HDRSIZE
            """=I""",  # 5 U32(skb, CTRL_ATTR_MAXATTR
            """=I""",  # 6 U32(skb, CTRL_ATTR_OP_ID
            """=I""",  # 7 U32(skb, CTRL_ATTR_OP_FLAGS
            """=I""",  # 8 U32(skb, CTRL_ATTR_MCAST_GRP_ID
            9,  # 9 STRING(skb, CTRL_ATTR_MCAST_GRP_NAME
        ]

        cmd = "TASKSTATS\0"
        msgLen = len(cmd) + 4

        # build request packet #
        msg = array.array(str("B"))

        # check version #
        if sys.version_info < (3, 0, 0):
            conv = msg.fromstring
        else:
            conv = msg.frombytes

        conv(struct.pack("BBxx", CTRL_CMD_GETFAMILY, 0))
        conv(struct.pack("HH", msgLen, CTRL_ATTR_FAMILY_NAME))
        conv(cmd.encode())
        conv(b"\0" * ((4 - (len(cmd) % 4)) & 0x3))

        nlmsghdr = array.array(
            str("B"),
            struct.pack(
                str("=IHHII"),
                len(msg) + 16,
                ConfigMgr.NETLINK_TYPE["NETLINK_GENERIC"],
                NLM_F_REQUEST,
                0,
                0,
            ),
        )
        nlmsghdr.extend(msg)

        # send GETFAMILY command #
        sockObj.send(nlmsghdr)

        # recv result #
        data = sockObj.recv()
        if not data:
            return

        (size, type, flags, seq, pid) = struct.unpack(str("=IHHII"), data[:16])
        data = data[16:size]

        cmd, version = struct.unpack(str("=BBxx"), data[:4])
        data = data[4:]

        while len(data) > 0:
            length, typ = struct.unpack(str("=HH"), data[:4])
            length = length & 0x7FFF

            if geAttrStruct[typ] == 0:
                SysMgr.geAttr[typ] = data[4 : length - 1]
            elif geAttrStruct[typ] == 9:
                pass
            elif typ > 5:
                pass
            else:
                SysMgr.geAttr[typ] = struct.unpack(
                    geAttrStruct[typ], data[4:length]
                )[0]

            data = data[((((length + 3))) & ~0x3) :]

    @staticmethod
    def getTaskstats(target):
        if SysMgr.isAndroid:
            return None

        sockObj = SysMgr.netlinkObj
        geAttr = SysMgr.geAttr

        if not sockObj:
            SysMgr.printErr("not initialized netlink socket yet")
            return None

        NLMSG_MIN_TYPE = 0x10
        GENL_ID_CTRL = NLMSG_MIN_TYPE
        ACK_REQUEST = 4 | 1

        TASKSTATS_CMD_ATTR_PID = 1
        TASKSTATS_CMD_ATTR_TGID = 2
        TASKSTATS_CMD_GET = 1  # user -> kernel request/get-response
        TASKSTATS_CMD_NEW = 2  # kernel -> user event

        TASKSTATS_TYPE_PID = 1  # Process id
        TASKSTATS_TYPE_TGID = 2  # Thread group id
        TASKSTATS_TYPE_STATS = 3  # taskstats structure
        TASKSTATS_TYPE_AGGR_PID = 4  # contains pid + stats
        TASKSTATS_TYPE_AGGR_TGID = 5  # contains tgid + stats

        NLMSG_NOOP = 0x1
        NLMSG_ERROR = 0x2
        NLMSG_DONE = 0x3
        NLMSG_OVERRUN = 0x4

        CTRL_ATTR_UNSPEC = 0
        CTRL_ATTR_FAMILY_ID = 1
        CTRL_ATTR_FAMILY_NAME = 2
        CTRL_ATTR_VERSION = 3
        CTRL_ATTR_HDRSIZE = 4
        CTRL_ATTR_MAXATTR = 5
        CTRL_ATTR_OPS = 6

        TASKSTATS_STRUCT = "HIBBQQQQQQQQ32sIxxxIIIIIQQQQQQQQQQQQQQQQQQQQQQQ"
        TASKSTATS_FIELD = [
            "version",
            "ac_exitcode",
            "ac_flag",
            "ac_nice",
            "cpu_count",
            "cpu_delay_total",
            "blkio_count",
            "blkio_delay_total",
            "swapin_count",
            "swapin_delay_total",
            "cpu_run_real_total",
            "cpu_run_virtual_total",
            "ac_comm",
            "ac_sched",
            "ac_uid",
            "ac_gid",
            "ac_pid",
            "ac_ppid",
            "ac_btime",
            "ac_etime",
            "ac_utime",
            "ac_stime",
            "ac_minflt",
            "ac_majflt",
            "coremem",
            "virtmem",
            "hiwater_rss",
            "hiwater_vm",
            "read_char",
            "write_char",
            "read_syscalls",
            "write_syscalls",
            "read_bytes",
            "write_bytes",
            "cancelled_write_bytes",
            "nvcsw",
            "nivcsw",
            "utimescaled",
            "stimescaled",
            "cpu_scaled_run_real_total",
            "freepages_count",
            "freepages_delay_total",
        ]

        array = SysMgr.getPkg("array", False)
        if not array:
            return None

        # request #
        msg = array.array(str("B"))

        # check version #
        if sys.version_info < (3, 0, 0):
            conv = msg.fromstring
        else:
            conv = msg.frombytes

        conv(struct.pack("BBxx", TASKSTATS_CMD_GET, 0))

        cmd = struct.pack("=I", long(target))
        msgLen = len(cmd) + 4

        conv(struct.pack("HH", msgLen, TASKSTATS_CMD_ATTR_PID))
        conv(cmd)
        conv(b"\0" * ((4 - (len(cmd) % 4)) & 0x3))

        pid = sockObj.socket.getsockname()[0]
        nlmsghdr = array.array(
            str("B"),
            struct.pack(
                str("=IHHII"),
                len(msg) + 16,
                geAttr[CTRL_ATTR_FAMILY_ID],
                ACK_REQUEST,
                1,
                pid,
            ),
        )
        nlmsghdr.extend(msg)

        sockObj.send(nlmsghdr)

        cnt = 0
        while 1:
            data = sockObj.recv()
            if type(data) is bytes and len(data) >= 328:
                break

            cnt += 1
            if cnt > 3:
                return None

        (size, ftype, flags, seq, pid) = struct.unpack(
            str("=IHHII"), data[:16]
        )
        data = data[16:size]

        cmd, version = struct.unpack(str("=BBxx"), data[:4])
        data = data[4:]

        attrs = dict(
            zip(TASKSTATS_FIELD, struct.unpack(TASKSTATS_STRUCT, data[16:344]))
        )
        attrs["ac_comm"] = attrs["ac_comm"].decode().rstrip("\0")

        return attrs

    @staticmethod
    def doPrintSvc():
        def _getAttr(fpath):
            try:
                fd = open(fpath, "r")
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenErr(fpath)
                return

            lines = fd.readlines()

            attrList = {}
            for line in lines:
                try:
                    if (
                        line == "\n"
                        or line.startswith("#")
                        or line.startswith("[")
                    ):
                        continue

                    name, value = line[:-1].split("=", 1)
                    attrList[name.strip()] = value.strip()
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printWarn(
                        "failed to parse line '%s'" % line[:-1], reason=True
                    )

            return attrList

        SysMgr.printLogo(big=True, onlyFile=True)

        # set dir path #
        if SysMgr.inputParam:
            systemdPathList = SysMgr.inputParam.split(",")
            for d in systemdPathList:
                if not os.path.isdir(d.strip()):
                    SysMgr.printErr("%s is not an accessible directory" % d)
                    sys.exit(-1)
        else:
            systemdPathList = ["/etc/systemd/system", "/lib/systemd/system"]

        cv = UtilMgr.convNum

        busServiceList = {}
        filteredList = {}

        SysMgr.cmdlineEnable = True
        obj = TaskAnalyzer(onlyInstance=True)
        obj.saveSystemStat()

        # parse service files #
        for spath in systemdPathList:
            for items in os.walk(spath):
                for node in items[2]:
                    if not node.endswith(".service"):
                        continue
                    elif node in busServiceList:
                        continue
                    elif not UtilMgr.isValidStr(node, ignCap=True):
                        continue

                    fpath = os.path.join(items[0], node)
                    if os.path.islink(fpath):
                        continue

                    busServiceList[node] = _getAttr(fpath)
                    busServiceList[node]["path"] = fpath

        # parse filter #
        attrList = []
        valList = []
        for item in SysMgr.customCmd:
            args = item.split(":", 1)
            if len(args) == 1:
                attrList.append(args[0])
            else:
                valList.append(args[1])

        # print service files #
        if busServiceList:
            SysMgr.printPipe(
                "[Systemd Target Service] (NrItems: %s)\n%s"
                % (cv(len(busServiceList)), twoLine)
            )
            nrItems = 0
            for node, value in sorted(
                busServiceList.items(), key=lambda e: e[0]
            ):
                cnt = 0
                for attr, val in sorted(value.items()):
                    if not UtilMgr.isValidStr(attr, attrList, ignCap=True):
                        continue
                    elif not UtilMgr.isValidStr(val, valList, ignCap=True):
                        continue

                    SysMgr.addPrint(
                        "{0:32} {1:1} = {2:1}\n".format(" ", attr, val),
                        isList=True,
                    )
                    cnt += 1

                if cnt > 0:
                    SysMgr.printPipe("[ %s ]" % node)
                    SysMgr.doPrint(clear=True, isList=True)
                    nrItems += 1
                else:
                    SysMgr.clearPrint()
                    filteredList[node] = value

            if nrItems == 0:
                SysMgr.printPipe("\tNone")
            SysMgr.printPipe("%s\n" % oneLine)

        # print filtered list #
        if filteredList:
            SysMgr.printPipe(
                "\n[Systemd Exceptional Service] (NrItems: %s)\n%s"
                % (cv(len(filteredList)), twoLine)
            )
            for node, value in sorted(filteredList.items()):
                SysMgr.printPipe("[ %s ]" % node)
                for attr, val in sorted(value.items()):
                    SysMgr.printPipe(
                        "{0:32} {1:1} = {2:1}".format(" ", attr, val)
                    )
                SysMgr.printPipe()
            SysMgr.printPipe("%s\n" % oneLine)

        sys.exit(0)

    @staticmethod
    def doPrintNs():
        SysMgr.printLogo(big=True, onlyFile=True)

        SysMgr.checkRootPerm()

        SysMgr.nsEnable = True
        cv = UtilMgr.convNum

        obj = TaskAnalyzer(onlyInstance=True)
        obj.saveSystemStat()

        for ns, val in sorted(obj.nsData.items(), key=lambda e: e[0]):
            SysMgr.printPipe(
                "\n[%s] (Total: %s)\n%s" % (ns, cv(len(val)), twoLine)
            )

            cnt = 1
            for key, tids in sorted(val.items(), key=lambda e: e[0]):
                tid = sorted(list(tids), key=lambda e: long(e))[0]
                comm = obj.procData[tid]["stat"][obj.commIdx].strip("()")
                subStr = "{ %s(%s)" % (comm, tid)
                if len(tids) == 1:
                    subStr += " }"
                else:
                    subStr += ", ... }"

                nsStr = "(%3s) %s [Total: %s] %s" % (
                    cnt,
                    key,
                    len(tids),
                    subStr,
                )
                SysMgr.printPipe(nsStr)
                cnt += 1
                indentStr = " " * long(len(nsStr) / 2)

                if not SysMgr.showAll:
                    continue

                for tid in sorted(tids, key=lambda e: long(e)):
                    comm = obj.procData[tid]["stat"][obj.commIdx].strip("()")
                    cmdline = SysMgr.getCmdline(tid)
                    if cmdline:
                        cmdline = "<%s>" % cmdline
                    SysMgr.printPipe(
                        "%s - %s(%s) %s" % (indentStr, comm, tid, cmdline)
                    )

            SysMgr.printPipe("%s\n" % oneLine)

        sys.exit(0)

    @staticmethod
    def doPrintInfo():
        SysMgr.printLogo(big=True, onlyFile=True)

        # save system info #
        SysMgr.saveSysStats()

        if SysMgr.jsonEnable:
            # convert dict data to JSON string #
            jsonStr = UtilMgr.convDict2Str(
                SysMgr.jsonData, pretty=not SysMgr.streamEnable
            )
            if not jsonStr:
                SysMgr.printWarn(
                    "failed to convert report data to JSON format"
                )
            else:
                SysMgr.printPipe(jsonStr)
        else:
            SysMgr.printInfoBuffer()

        sys.exit(0)

    @staticmethod
    def doWatch():
        SysMgr.printLogo(big=True, onlyFile=True)

        SysMgr.setStream()

        # check target path #
        if SysMgr.hasMainArg():
            opList = SysMgr.getMainArgs(False)
        elif SysMgr.filterGroup:
            opList = SysMgr.filterGroup
        else:
            opList = ["."]

        targetList = []
        targetInfo = {}

        # parse items #
        for item in opList:
            args = item.split(":")

            # convert path #
            path = os.path.realpath(os.path.expanduser(args[0]))
            targetList.append(path)

            if len(args) > 1:
                events = args[1].strip().split("|")
                if events == [""]:
                    events = []
            else:
                events = []

            if len(args) > 2:
                fname = args[2].strip()
            else:
                fname = None

            if len(args) > 3:
                cmd = args[3].strip().split("|")
                if cmd == [""]:
                    cmd = []
            else:
                cmd = []

            targetInfo[path] = {"event": events, "cmd": cmd, "fname": fname}

        SysMgr.printInfo("start watching [%s]" % ", ".join(targetList))

        # start watching #
        while 1:
            try:
                ret = SysMgr.inotify(targetList, wait=True, verb=True)
                if not ret:
                    break

                current = SysMgr.getUptime()

                for item in ret:
                    path, events, fname = item

                    # check event condition #
                    if targetInfo[path]["event"]:
                        cond = set(targetInfo[path]["event"])
                        new = set(events)
                        if cond - new == cond:
                            continue

                    # check file condition #
                    if (
                        targetInfo[path]["fname"]
                        and targetInfo[path]["fname"] != fname
                    ):
                        continue

                    # add file name #
                    if fname:
                        fpath = os.path.join(path, fname)
                    else:
                        fpath = path

                    SysMgr.printPipe(
                        "[%.6f] %s@%s" % (current, "|".join(events), fpath)
                    )

                    # execute command #
                    for cmd in targetInfo[path]["cmd"]:
                        if cmd.upper() == "EXIT":
                            sys.exit(0)
                        else:
                            if cmd.endswith("&"):
                                cmd = cmd[:-1]
                                wait = False
                            else:
                                wait = True

                            SysMgr.createProcess(cmd)
                            if wait:
                                os.wait()

            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("failed to watch", reason=True)
                sys.exit(-1)

    @staticmethod
    def getTargetFileList():
        # get target file list #
        if "TARGETFILE" in SysMgr.environList:
            targetFileList = SysMgr.environList["TARGETFILE"]
        else:
            targetFileList = []

        # get except file list #
        if "EXCEPTFILE" in SysMgr.environList:
            exceptFileList = SysMgr.environList["EXCEPTFILE"]
        else:
            exceptFileList = []

        return targetFileList, exceptFileList

    @staticmethod
    def isExceptFile(mfile, targetFileList, exceptFileList):
        if targetFileList and not UtilMgr.isValidStr(mfile, targetFileList):
            ElfAnalyzer.failedFiles[mfile] = True
            return True
        elif exceptFileList and UtilMgr.isValidStr(mfile, exceptFileList):
            ElfAnalyzer.failedFiles[mfile] = True
            return True

        return False

    @staticmethod
    def doTrace(mode, tid=None):
        def _doCommonJobs(pids, procList):
            # check STOP condition #
            if "STOPTARGET" in SysMgr.environList:
                needStop = True
            else:
                needStop = False

            # get file list #
            targetFileList, exceptFileList = SysMgr.getTargetFileList()

            # get pid list #
            for tid in pids:
                try:
                    pid = SysMgr.getTgid(tid)
                    if not pid:
                        continue

                    # stop target #
                    try:
                        if needStop:
                            os.kill(long(pid), signal.SIGSTOP)
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass

                    procList.setdefault(pid, [])
                    procList[pid].append(tid)
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

            pidList = list(map(long, procList))

            # merge map files #
            mapList = []
            getProcMapInfo = FileAnalyzer.getProcMapInfo
            for pid in pidList:
                mapList += getProcMapInfo(pid, onlyExec=True)
            mapList = list(set(mapList))

            # load symbol caches at once #
            printLog = True
            if not "LAZYCACHE" in SysMgr.environList:
                for item in mapList:
                    # skip invalid file #
                    if not FileAnalyzer.isValidFile(item, special=True):
                        continue
                    # check file filter #
                    elif SysMgr.isExceptFile(
                        item, targetFileList, exceptFileList
                    ):
                        continue

                    try:
                        eobj = ElfAnalyzer.getObject(item, log=printLog)
                        if len(pidList) == 1 and eobj:
                            eobj.mergeSymTable()
                            if printLog:
                                printLog = False
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass

            # continue target #
            try:
                if needStop:
                    for pid in pidList:
                        os.kill(pid, signal.SIGCONT)
            except SystemExit:
                sys.exit(0)
            except:
                pass

            # check mode #
            if not mode in ("breakcall", "pytrace"):
                return

            # save original data to be injected for multi-threaded process #
            for pid in pidList:
                # stop a process #
                try:
                    os.kill(pid, signal.SIGSTOP)
                except SystemExit:
                    sys.exit(0)
                except:
                    continue

                # initialize lists #
                bpList.setdefault(pid, {})
                exceptBpList.setdefault(pid, {})
                targetBpList.setdefault(pid, {})
                targetBpFileList.setdefault(pid, {})
                exceptBpFileList.setdefault(pid, {})

                # create object #
                procObj = Debugger(pid=pid, mode="break")
                if not procObj:
                    os.kill(pid, signal.SIGCONT)
                    continue
                elif (
                    mode in ("pycall", "pytrace") and not procObj.checkPyVer()
                ):
                    os.kill(pid, signal.SIGCONT)
                    continue

                # register signal sender for resume #
                SysMgr.addExitFunc(
                    SysMgr.sendSignalProcs,
                    [signal.SIGCONT, [pid], False, False],
                )

                # load common ELF cache files #
                procObj.loadSymbols()
                procObj.updateBpList()

                # save per-process breakpoint info #
                bpList[pid] = UtilMgr.deepcopy(procObj.bpList)
                exceptBpList[pid] = UtilMgr.deepcopy(procObj.exceptBpList)
                targetBpList[pid] = UtilMgr.deepcopy(procObj.targetBpList)
                targetBpFileList[pid] = UtilMgr.deepcopy(
                    procObj.targetBpFileList
                )
                exceptBpFileList[pid] = UtilMgr.deepcopy(
                    procObj.exceptBpFileList
                )

                # create a lock for the multi-threaded process #
                if SysMgr.getTids(pid, sibling=True):
                    lockList[pid] = Debugger.getGlobalLock(
                        pid, len(bpList[pid])
                    )

                # detach task #
                procObj.detach()
                del procObj

                # remove signal sender #
                SysMgr.removeExitFunc(
                    SysMgr.sendSignalProcs,
                    [signal.SIGCONT, [pid], False, False],
                )

        # no use pager #
        if not SysMgr.isTopMode() and not SysMgr.outPath:
            SysMgr.setStream()

        # define variables #
        wait = None
        multi = False
        execCmd = None
        lockObj = None
        procList = {}
        allpids = []
        bpList = {}
        lockList = {}
        exceptBpList = {}
        targetBpList = {}
        targetBpFileList = {}
        exceptBpFileList = {}

        # get argument #
        if tid:
            inputParam = None
        elif SysMgr.hasMainArg():
            inputParam = SysMgr.getMainArg()
        elif SysMgr.inputParam:
            inputParam = SysMgr.inputParam
        else:
            inputParam = None

        # check input #
        if not SysMgr.filterGroup and not inputParam:
            SysMgr.printErr("no input value for target")
            sys.exit(-1)

        # check condition #
        if mode == "pytrace":
            SysMgr.pyFuncFilter = SysMgr.customCmd
            if "GETRET" in SysMgr.environList:
                SysMgr.customCmd = ["%s|getret" % SysMgr.pyCallFunc]
            else:
                SysMgr.customCmd = [SysMgr.pyCallFunc]
        elif mode == "remote" or mode == "hook":
            if not SysMgr.customCmd:
                SysMgr.printErr("failed to get remote command")
                sys.exit(-1)
            elif inputParam:
                SysMgr.printErr("executing a program is not supported")
                sys.exit(-1)

        # set priority #
        if SysMgr.prio is None:
            SysMgr.setPriority(SysMgr.pid, "C", -20)

        # write user command #
        if not SysMgr.isTopMode():
            SysMgr.runProfCmd("BEFORE")

        # create event memory #
        Debugger.globalEvent = SysMgr.createShm()

        # check symbol requirement #
        needSymbol = SysMgr.funcDepth > 0 or mode in (
            "usercall",
            "sample",
            "breakcall",
            "hook",
            "pytrace",
            "bind",
        )

        # set dwarf flag #
        SysMgr.setDwarfFlag()

        # preload ELF caches #
        if "ELFFILE" in SysMgr.environList:
            elfPath = SysMgr.environList["ELFFILE"][0]

            SysMgr.printStat("start preloading ElF files from '%s'" % elfPath)

            # load ELF files #
            Debugger.loadElfList(elfPath)

            # move loaded objects to preload list #
            ElfAnalyzer.preloadedFiles = ElfAnalyzer.cachedFiles
            ElfAnalyzer.cachedFiles = {}

        # get pids #
        if tid:
            allpids = pids = [tid]
        elif not inputParam:
            if mode in ("hook", "bind"):
                isThread = False
            else:
                isThread = True

            # convert comm to pid #
            pids = SysMgr.convTaskList(
                SysMgr.filterGroup,
                isThread=isThread,
                sibling=SysMgr.groupProcEnable,
            )

            # get pids of process groups #
            if mode in ("breakcall", "pytrace"):
                allpids = SysMgr.convTaskList(
                    SysMgr.filterGroup, isThread=True, sibling=True
                )
            else:
                allpids = pids

        # check command #
        if inputParam:
            pid = None
            execCmd = UtilMgr.parseCommand(inputParam)
        # check permission #
        elif not SysMgr.checkRootPerm(msg="trace %s" % mode):
            # exit #
            pass
        # check pid #
        elif not pids:
            if SysMgr.filterGroup:
                flist = ", ".join(SysMgr.filterGroup)
                SysMgr.printErr("no thread related to '%s'" % flist)
            elif not inputParam:
                SysMgr.printErr("no input for TID or command")
            else:
                SysMgr.printErr("no input for TID")

            SysMgr.outPath = SysMgr.printFd = None

            sys.exit(-1)
        # check targets #
        elif len(allpids) > 1 or mode in ("breakcall", "pytrace"):
            parent = SysMgr.pid

            # set multi-task attributes #
            if len(pids) > 1:
                multi = True
                if not SysMgr.outPath:
                    SysMgr.setStream()

                SysMgr.printWarn(
                    "multiple tasks [ %s ] are targeted"
                    % SysMgr.getCommList(pids),
                    True,
                )

            # load symbol caches in advance #
            if needSymbol:
                _doCommonJobs(pids, procList)

            # create new worker processes #
            try:
                isFinished = True
                for tid in allpids:
                    ret = SysMgr.createProcess(chPgid=True, chMid=True)
                    if ret != 0:
                        continue

                    if not tid in pids:
                        SysMgr.printEnable = False

                        # mute tasks except for targets #
                        if (
                            not SysMgr.warnEnable
                            and SysMgr.getTgid(tid) != tid
                        ):
                            SysMgr.logEnable = False

                    pid = long(tid)
                    break
            except:
                isFinished = False

            # wait for children tracers as their parent #
            if SysMgr.pid == parent:
                # disable printing to file #
                SysMgr.outPath = SysMgr.printFd = None

                if isFinished:
                    SysMgr.termFlag = False
                    while 1:
                        SysMgr.waitEvent(ignChldSig=False, block=False)
                        if SysMgr.condExit:
                            break

                        # check children #
                        SysMgr.updateChildList()
                        if SysMgr.isNoChild():
                            break

                # broadcast term signal to children and wait for them #
                signal.signal(signal.SIGCHLD, signal.SIG_IGN)
                children = TaskAnalyzer.getDescendantList(SysMgr.pid)
                SysMgr.killChildren(
                    sig=signal.SIGINT, children=children, wait=True, group=True
                )

                # continue processes #
                SysMgr.sendSignalProcs(
                    signal.SIGCONT, list(procList), verb=False
                )

                # remove temporary files #
                if mode in ("breakcall", "pytrace"):
                    # remove all lock files #
                    for lockPath in list(lockList.values()):
                        # remove lock file #
                        try:
                            os.remove(lockPath.name)
                        except:
                            pass

                sys.exit(0)
        else:
            # load symbol caches in advance #
            if needSymbol:
                _doCommonJobs(pids, procList)

            pid = long(pids[0])

        # recover SIGCHLD #
        signal.signal(signal.SIGCHLD, signal.SIG_DFL)

        # start tracing #
        try:
            if mode == "kernelcall":
                dobj = Debugger(pid=pid, execCmd=execCmd, attach=False)
                dobj.trace(mode="kernel", wait=wait, multi=multi)
            elif mode == "usercall":
                # tracing #
                if SysMgr.isTraceMode():
                    dobj = Debugger(pid=pid, execCmd=execCmd, attach=False)
                    dobj.trace(mode="inst", wait=wait, multi=multi)
                # monitoring #
                else:
                    dobj = Debugger(pid=pid, execCmd=execCmd, attach=True)
                    dobj.trace(mode="sample", wait=wait, multi=multi)
            elif mode == "pycall":
                dobj = Debugger(pid=pid, execCmd=execCmd, attach=True)
                dobj.trace(mode="pycall", wait=wait, multi=multi)
            elif mode in ("breakcall", "pytrace"):
                if pid:
                    try:
                        ppid = long(SysMgr.getTgid(pid))
                    except SystemExit:
                        sys.exit(0)
                    except:
                        ppid = None

                    # set per-process convert breakpoint list #
                    if ppid in bpList:
                        bpList = bpList[ppid]
                    if ppid in exceptBpList:
                        exceptBpList = exceptBpList[ppid]
                    if ppid in targetBpList:
                        targetBpList = targetBpList[ppid]
                    if ppid in targetBpFileList:
                        targetBpFileList = targetBpFileList[ppid]
                    if ppid in exceptBpFileList:
                        exceptBpFileList = exceptBpFileList[ppid]
                    if ppid in lockList:
                        lockObj = lockList[ppid]
                else:
                    ppid = SysMgr.pid

                # set real mode #
                if mode == "breakcall":
                    rmode = "break"
                else:
                    rmode = "pybreak"

                Debugger(pid=pid, execCmd=execCmd).trace(
                    mode=rmode,
                    wait=wait,
                    multi=multi,
                    bpList=bpList,
                    exceptBpList=exceptBpList,
                    lock=lockObj,
                    targetBpList=targetBpList,
                    targetBpFileList=targetBpFileList,
                    exceptBpFileList=exceptBpFileList,
                )
            elif mode == "hook":
                Debugger.hookFunc(pid, SysMgr.customCmd)
            elif mode == "bind":
                Debugger.hookFunc(pid, SysMgr.customCmd, mode="print")
            else:
                # syscall / signal / remote #
                dobj = Debugger(
                    pid=pid, execCmd=execCmd, attach=False, mode=mode
                )
                dobj.trace(mode=mode, wait=wait, multi=multi)
        except SystemExit:
            pass
        except:
            SysMgr.printErr("stopped to trace %s" % mode, True)

        sys.exit(0)

    @staticmethod
    def doAddr2sym():
        SysMgr.printLogo(big=True, onlyFile=True)

        # check input #
        if SysMgr.hasMainArg():
            inputArg = SysMgr.getMainArg()
        elif SysMgr.inputParam:
            inputArg = str(SysMgr.inputParam)
        else:
            SysMgr.printErr("no input for path")
            sys.exit(-1)

        # check symbol #
        if not SysMgr.filterGroup:
            SysMgr.printErr("no input for offset")
            sys.exit(-1)
        else:
            addrList = []
            for idx, addr in enumerate(SysMgr.filterGroup):
                if not UtilMgr.isNumber(addr):
                    SysMgr.printErr(
                        "failed to recognize '%s' as a number" % addr
                    )
                    sys.exit(-1)

                try:
                    addrList.append(long(addr, 16))
                except:
                    addrList.append(long(addr))

        def _printRes(procInfo, resInfo, maxSymLen):
            if procInfo:
                procInfo = " [Task: %s]" % procInfo

            # make space between symbol and path #
            maxSymLen += 4

            SysMgr.printPipe("\n[Address Info]%s\n%s" % (procInfo, twoLine))
            SysMgr.printPipe(
                "{0:<18} {1:<18} {2:<{maxSymLen}} {3:<1}\n{4:1}".format(
                    menu1st,
                    menu2nd,
                    "Symbol",
                    "File",
                    twoLine,
                    maxSymLen=maxSymLen,
                )
            )

            # print symbols from offset list #
            for addr, val in resInfo.items():
                SysMgr.printPipe(
                    "{0:<18} {1:18} {2:<{maxSymLen}} {3:<1}".format(
                        hex(addr).rstrip("L"),
                        val[2],
                        val[0],
                        val[1],
                        maxSymLen=maxSymLen,
                    )
                )

            if not resInfo:
                SysMgr.printPipe("\tNone")

            SysMgr.printPipe(oneLine + "\n")

        # init variables #
        resInfo = {}
        menu1st = "Offset"
        menu2nd = "Address"
        maxSymLen = 5
        procInfo = ""

        # get pid list #
        pids = SysMgr.getTids(inputArg)
        taskList = []
        for tid in pids:
            taskList.append(SysMgr.getTgid(tid))
        pids = list(set(taskList))

        # files #
        if not pids:
            # get file list #
            fileList = UtilMgr.getFileList(
                UtilMgr.cleanItem(inputArg.split(","), False), exceptDir=True
            )

            # check file #
            if not fileList:
                SysMgr.printErr(
                    "failed to recognize '%s' as a file or a process"
                    % inputArg
                )
                sys.exit(-1)

            menu1st = "Address"
            menu2nd = "Offset"

            for filePath in fileList:
                # create an ELF object #
                try:
                    binObj = ElfAnalyzer.getObject(filePath)
                    if not binObj:
                        err = SysMgr.getErrMsg()
                        raise Exception(err)
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(
                        "failed to load '%s' as an ELF object" % filePath, True
                    )
                    continue

                for addr in addrList:
                    try:
                        sym, size = binObj.getSymbolByOffset(
                            addr, onlyFunc=False
                        )
                        resInfo[addr] = [sym, filePath, "N/A"]
                        if maxSymLen < len(sym) < SysMgr.ttyCols / 2:
                            maxSymLen = len(sym)
                    except SystemExit:
                        sys.exit(0)
                    except:
                        resInfo[addr] = ["??", filePath, "N/A"]

            # print result #
            _printRes(procInfo, resInfo, maxSymLen)
        else:
            for pid in pids:
                # init variables #
                resInfo = {}
                maxSymLen = 5
                comm = SysMgr.getComm(pid)
                procInfo = "%s(%s)" % (comm, pid)

                try:
                    dobj = Debugger(pid=pid, attach=False)
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr("failed to analyze %s" % procInfo, True)
                    continue

                for addr in addrList:
                    ret = dobj.getSymbolInfo(
                        addr, onlyFunc=False, onlyExec=False
                    )
                    if not ret:
                        SysMgr.printErr(
                            "failed to analyze %s" % procInfo, True
                        )
                        continue
                    elif type(ret) is list:
                        resInfo[addr] = [ret[0], ret[1], ret[2]]
                        if maxSymLen < len(ret[0]) < SysMgr.ttyCols / 2:
                            maxSymLen = len(ret[0])
                    else:
                        resInfo[addr] = ["??", "??", "N/A"]

                # print result #
                _printRes(procInfo, resInfo, maxSymLen)

    @staticmethod
    def printDirs(path=".", maxLevel=-1, retVal=False):
        def _getDirsJson(result, parentPath, level, maxLevel):
            # get subdir #
            try:
                fileList = os.listdir(parentPath)
                parentAbsPath = "%s" % (os.path.realpath(parentPath))
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn(
                    "failed to access %s" % parentPath,
                    always=True,
                    reason=True,
                )
                return (0, 0, 0)

            # check return condition #
            if not fileList or (maxLevel != -1 and maxLevel <= level):
                return (0, 0, 0)

            # print progress #
            if not retVal:
                UtilMgr.printProgress()

            totalSize = 0
            totalFile = 0
            totalDir = 0

            # set block size #
            topDir = parentPath.lstrip("/").split("/", 1)[0]
            if topDir in ("proc", "sys", "dev"):
                blockSize = 0
            else:
                blockSize = SysMgr.PAGESIZE

            # check including link option #
            if "INCLINK" in SysMgr.environList:
                incLink = True
            else:
                incLink = False

            for idx, subPath in enumerate(fileList):

                fullPath = os.path.join(parentPath, subPath)

                subAbsPath = os.path.realpath(fullPath)

                if os.path.isdir(fullPath):
                    totalDir += 1
                    totalSize += blockSize

                    # skip link #
                    if not incLink and os.path.islink(fullPath):
                        continue

                    if SysMgr.showAll:
                        info = dict(subDirs={}, subFiles={})
                    else:
                        info = dict(subDirs={})

                    result[parentAbsPath]["subDirs"][subAbsPath] = info

                    totalInfo = _getDirsJson(
                        result[parentAbsPath]["subDirs"],
                        fullPath,
                        level + 1,
                        maxLevel,
                    )

                    if blockSize:
                        totalSize += totalInfo[0]
                    totalDir += totalInfo[1]
                    totalFile += totalInfo[2]

                elif os.path.isfile(fullPath):
                    # apply filter #
                    if SysMgr.filterGroup:
                        if not UtilMgr.isValidStr(subPath):
                            continue

                    totalFile += 1

                    # get size #
                    if not blockSize:
                        size = 0
                    elif not incLink and os.path.islink(fullPath):
                        size = 0
                    else:
                        size = os.stat(fullPath).st_size

                    if size < blockSize:
                        totalSize += blockSize
                    else:
                        totalSize += size

                    if not SysMgr.showAll:
                        continue

                    # check size #
                    if not _isValidSize(condop, condval, size):
                        continue

                    if "subFiles" not in result[parentAbsPath]:
                        result[parentAbsPath]["subFiles"] = {}

                    result[parentAbsPath]["subFiles"][subAbsPath] = dict(
                        size=UtilMgr.convSize2Unit(size), type="file"
                    )

            result[parentAbsPath]["size"] = UtilMgr.convSize2Unit(totalSize)
            result[parentAbsPath]["nrDir"] = UtilMgr.convNum(totalDir)
            result[parentAbsPath]["nrFile"] = UtilMgr.convNum(totalFile)

            return (totalSize, totalDir, totalFile)

        def _executeCmd(path):
            for cmd in SysMgr.customCmd:
                command = cmd.replace("TARGET", path)
                SysMgr.printInfo("execute '%s'" % command)
                pid = SysMgr.createProcess(command)
                if pid > 0:
                    os.waitpid(pid, 0)
                elif pid == 0:
                    sys.exit(0)

        def _isValidSize(condop, condval, size):
            if not condop:
                return True

            if condop == "BT":
                if condval <= size:
                    return True
                else:
                    return False
            elif condop == "LT":
                if condval >= size:
                    return True
                else:
                    return False
            else:
                return True

        def _getDirs(parentPath, fileList, prefix, result, level, maxLevel):
            totalSize = 0
            totalFile = 0
            totalDir = 0

            # check return condition #
            if not fileList or (maxLevel != -1 and maxLevel <= level):
                return (0, 0, 0)

            # print progress #
            UtilMgr.printProgress()

            convSize = UtilMgr.convSize2Unit
            convColor = UtilMgr.convColor
            BIGSIZE = 1 << 30

            # set block size #
            topDir = parentPath.lstrip("/").split("/", 1)[0]
            if topDir in ("proc", "sys", "dev"):
                blockSize = 0
            else:
                blockSize = SysMgr.PAGESIZE

            # check including link option #
            if "INCLINK" in SysMgr.environList:
                incLink = True
            else:
                incLink = False

            # sort #
            if "SORT" in SysMgr.environList:
                # sort by size #
                if "SIZE" in SysMgr.environList["SORT"]:
                    fileList.sort(
                        key=lambda name: os.path.getsize(
                            "%s/%s" % (parentPath, name)
                        )
                        if os.path.exists("%s/%s" % (parentPath, name))
                        else 0,
                        reverse=True,
                    )
                # sort by type #
                elif "TYPE" in SysMgr.environList["SORT"]:
                    fileList.sort(
                        key=lambda f: os.path.isfile(
                            os.path.join(parentPath, f)
                        )
                    )
                # sort by name #
                else:
                    fileList.sort()
            # sort by name #
            else:
                fileList.sort()

            for idx, subPath in enumerate(fileList):
                idc = "|-"

                fullPath = os.path.join(parentPath, subPath)

                # check dir #
                if os.path.isdir(fullPath):
                    totalDir += 1
                    totalSize += blockSize
                    isTarget = False

                    # apply filter #
                    if SysMgr.filterGroup:
                        if UtilMgr.isValidStr(subPath):
                            isTarget = True
                            SysMgr.printPipe(
                                "[%s]" % convColor(fullPath, "GREEN")
                            )
                    else:
                        isTarget = True
                        string = "%s%s[%s]" % (
                            prefix,
                            idc,
                            convColor(subPath, "GREEN"),
                        )
                        result.append(string)

                    # apply command #
                    if isTarget and SysMgr.customCmd:
                        _executeCmd(fullPath)

                    # update prefix #
                    tmpPrefix = prefix + "|  "

                    # check link #
                    if not incLink and os.path.islink(fullPath):
                        pass
                    else:
                        # get subdir #
                        try:
                            subdirs = os.listdir(fullPath)
                        except SystemExit:
                            sys.exit(0)
                        except:
                            SysMgr.printWarn(
                                "failed to access %s" % fullPath,
                                always=True,
                                reason=True,
                            )
                            continue

                        # traverse subdirs #
                        rlist = _getDirs(
                            fullPath,
                            subdirs,
                            tmpPrefix,
                            result,
                            level + 1,
                            maxLevel,
                        )

                        # add to stat #
                        if blockSize:
                            totalSize += rlist[0]
                        totalFile += rlist[2]
                        if isTarget:
                            totalDir += rlist[1]
                # check file #
                elif os.path.isfile(fullPath):
                    size = ""

                    # apply filter #
                    if SysMgr.filterGroup:
                        # name #
                        if not UtilMgr.isValidStr(subPath):
                            continue

                        # get size #
                        try:
                            if blockSize:
                                size = os.stat(fullPath).st_size
                                totalSize += size
                            else:
                                size = 0
                        except SystemExit:
                            sys.exit(0)
                        except:
                            SysMgr.printWarn(
                                "failed to get size for '%s'" % fullPath,
                                reason=True,
                            )
                            continue

                        # size #
                        if not _isValidSize(condop, condval, size):
                            continue

                        # convert size to string #
                        try:
                            if size >= BIGSIZE or condval:
                                color = "RED"
                            else:
                                color = "CYAN"
                            sizeStr = convSize(size)
                            sizeStr = " <%s>" % convColor(sizeStr, color)
                        except SystemExit:
                            sys.exit(0)
                        except:
                            sizeStr = ""

                        string = fullPath + sizeStr
                        SysMgr.printPipe(string)

                        # apply command #
                        if SysMgr.customCmd:
                            _executeCmd(fullPath)

                    totalFile += 1

                    # get size #
                    try:
                        if not blockSize:
                            size = 0
                        elif not incLink and os.path.islink(fullPath):
                            size = 0
                        elif not size:
                            size = os.stat(fullPath).st_size
                            if size < blockSize:
                                totalSize += blockSize
                            else:
                                totalSize += size
                    except SystemExit:
                        sys.exit(0)
                    except:
                        SysMgr.printWarn(
                            "failed to get size for '%s'" % fullPath,
                            reason=True,
                        )
                        continue

                    # check skip condition #
                    if not SysMgr.showAll or SysMgr.filterGroup:
                        continue

                    # check size #
                    if not _isValidSize(condop, condval, size):
                        continue

                    # apply command #
                    if SysMgr.customCmd:
                        _executeCmd(fullPath)

                    # convert size to string #
                    try:
                        if size >= BIGSIZE or condval:
                            color = "RED"
                        elif size > blockSize:
                            color = "CYAN"
                        else:
                            color = None

                        sizeStr = convSize(size)

                        nrLink = os.stat(fullPath).st_nlink
                        if nrLink > 1:
                            linkStr = ", LINK: %s" % nrLink
                        elif os.path.islink(fullPath):
                            try:
                                linkStr = ", LINK: %s" % os.readlink(fullPath)
                            except SystemExit:
                                sys.exit(0)
                            except:
                                linkStr = ""
                        else:
                            linkStr = ""

                        sizeStr = " <SIZE: %s%s>" % (
                            convColor(sizeStr, color),
                            linkStr,
                        )
                    except SystemExit:
                        sys.exit(0)
                    except:
                        sizeStr = ""

                    string = "%s%s%s%s" % (prefix, idc, subPath, sizeStr)
                    result.append(string)

            # check size #
            if not _isValidSize(condop, condval, totalSize):
                return (totalSize, totalDir, totalFile)

            # convert total size #
            if totalSize:
                if totalSize >= BIGSIZE or condval:
                    color = "RED"
                else:
                    color = "CYAN"
                tsize = "SIZE: %s, " % convColor(convSize(totalSize), color)
            else:
                tsize = ""

            summary = " <%sFILE: %s, DIR: %s>" % (
                tsize,
                UtilMgr.convNum(totalFile),
                UtilMgr.convNum(totalDir),
            )

            # add summary by reverse traverse #
            if level == 0:
                result[0] += summary
            else:
                tprefix = "%s-[%s]" % (
                    prefix[:-2],
                    os.path.basename(parentPath),
                )
                for i, val in enumerate(reversed(result)):
                    if not UtilMgr.removeColor(val).startswith(tprefix):
                        continue
                    result[-(i) - 1] += summary
                    break

            return (totalSize, totalDir, totalFile)

        # check filter option #
        if SysMgr.findOption("g"):
            SysMgr.setStream()
            if not SysMgr.filterGroup:
                SysMgr.filterGroup = ["*"]

        # parse filter for file size #
        condop = None
        condval = None
        if "SIZECOND" in SysMgr.environList:
            sizeFilter = SysMgr.environList["SIZECOND"][0].split(":")

            # init variables #
            error = False

            # parse condition values #
            if len(sizeFilter) != 2:
                error = True
            elif sizeFilter[0].strip().upper() == "BT":
                condop = "BT"
                try:
                    condval = UtilMgr.convUnit2Size(sizeFilter[1].strip())
                except SystemExit:
                    sys.exit(0)
                except:
                    condval = None
                    error = True
            elif sizeFilter[0].strip().upper() == "LT":
                condop = "LT"
                try:
                    condval = UtilMgr.convUnit2Size(sizeFilter[1].strip())
                except SystemExit:
                    sys.exit(0)
                except:
                    error = True
            else:
                error = True

            # handle error #
            if error:
                SysMgr.printErr("wrong input value for SIZECOND", True)
                sys.exit(-1)
        else:
            sizeFilter = None

        # print start directory #
        abspath = os.path.realpath(path)

        if not retVal:
            SysMgr.printStat(r"start traversing dirs from '%s'..." % abspath)

        # print start path #
        if SysMgr.jsonEnable or retVal:
            result = {}
            if SysMgr.showAll:
                result[abspath] = dict(subDirs={}, subFiles={})
            else:
                result[abspath] = dict(subDirs={})

            _getDirsJson(result, path, 0, -1)

            if retVal:
                return result

            output = UtilMgr.convDict2Str(
                result, pretty=not SysMgr.streamEnable
            )
        else:
            try:
                initDir = os.listdir(path)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("failed to access %s" % path, reason=True)
                sys.exit(-1)

            result = ["[%s]" % abspath]

            if SysMgr.filterGroup:
                SysMgr.printPipe()

            _getDirs(abspath, initDir, "  ", result, 0, maxLevel)

            output = "\n%s\n" % "\n".join(result)

        # print results #
        UtilMgr.deleteProgress()
        SysMgr.printPipe(output)

        return output

    @staticmethod
    def setLowPriority(force=False, cpuVal=15, verb=False):
        # set CPU priority #
        if force or SysMgr.prio is None:
            SysMgr.setPriority(SysMgr.pid, "C", cpuVal, verb=verb)

        # set I/O priority #
        if force or SysMgr.ioprio is None:
            SysMgr.setIoPriority(ioclass="IOPRIO_CLASS_IDLE", verb=verb)

    @staticmethod
    def getProcAddrBySymbol(pid, symbolList, fileFilter=None):
        resInfo = {}

        # get file list on memory map #
        fileList = FileAnalyzer.getProcMapInfo(pid, onlyExec=False)
        if not fileList:
            comm = SysMgr.getComm(pid)
            procInfo = "%s(%s)" % (comm, pid)
            SysMgr.printErr("failed to get memory map for %s" % procInfo)
            return resInfo

        # apply file filter #
        if fileFilter:
            newFileList = {}
            if type(fileFilter) is str:
                fileFilter = [fileFilter]
            for path, value in sorted(
                fileList.items(), key=lambda e: e[1]["vstart"]
            ):
                for item in fileFilter:
                    if path.startswith(item):
                        newFileList[path] = value
            if not newFileList:
                comm = SysMgr.getComm(pid)
                procInfo = "%s(%s)" % (comm, pid)
                SysMgr.printErr(
                    "failed to get [ %s ] from memory map for %s"
                    % (", ".join(fileFilter), procInfo)
                )
                sys.exit(-1)
            fileList = newFileList

        # scan files #
        magicStr = SysMgr.magicStr
        for filePath, attr in sorted(
            fileList.items(), key=lambda e: e[1]["vstart"]
        ):
            # skip invalid file #
            if not FileAnalyzer.isValidFile(filePath, special=True):
                continue

            for sym in symbolList:
                # create an ELF object #
                try:
                    if magicStr in filePath:
                        origFilePath = filePath[: filePath.rfind(magicStr)]
                    else:
                        origFilePath = filePath

                    res = ElfAnalyzer.getSymOffset(sym, origFilePath)
                    if not res:
                        continue

                    origStartAddr = fileList[origFilePath]["vstart"]

                    for item in res:
                        fname = item[2]
                        fobj = ElfAnalyzer.cachedFiles[fname]
                        foffset = long(item[0])
                        startAddr = attr["vstart"]
                        totalDiff = 0

                        # get real offset for memory hole #
                        if (
                            origFilePath != filePath
                            and attr["offset"] <= foffset
                        ):
                            (
                                filePath,
                                startAddr,
                                totalDiff,
                            ) = Debugger.getRealOffsetInfo(fileList, filePath)

                        # check relocatable type #
                        if fobj.loadAddr == 0:
                            addr = hex(startAddr + foffset - totalDiff)
                        elif origStartAddr > fobj.loadAddr:
                            addr = hex(startAddr + foffset - totalDiff)
                        else:
                            addr = hex(foffset)

                        resInfo["%s|%s" % (item[1], origFilePath)] = (
                            hex(item[0]),
                            origFilePath,
                            addr,
                            item[1],
                        )
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printWarn(
                        "failed to save offset info", True, reason=True
                    )

        return resInfo

    @staticmethod
    def setDwarfFlag():
        def _printDwarfStatus(stat):
            statStr = "enabled" if stat else "disabled"
            SysMgr.printWarn("%s DWARF parser" % statStr, True)

        # check DWARF requirement #
        if SysMgr.dwarfEnable:
            _printDwarfStatus(True)
            return

        # enable DWARF by default for ARM #
        if SysMgr.arch == "aarch64" or SysMgr.arch == "arm":
            SysMgr.dwarfEnable = False
        else:
            SysMgr.dwarfEnable = True

        # check disable option #
        disableList = SysMgr.getOption("d")
        if disableList and "D" in disableList:
            SysMgr.dwarfEnable = False
            _printDwarfStatus(False)
            return

        # init and check libcorkscrew #
        SysMgr.initLibcorkscrew()
        if SysMgr.libcorkscrewObj and SysMgr.libcorkscrewObj != -1:
            SysMgr.dwarfEnable = False
            _printDwarfStatus(False)
            return

        _printDwarfStatus(SysMgr.dwarfEnable)

    @staticmethod
    def doPrintFile():
        SysMgr.printLogo(big=True, onlyFile=True)

        # check input #
        if SysMgr.hasMainArg():
            inputArg = SysMgr.getMainArgs()
        elif SysMgr.inputParam:
            inputArg = str(SysMgr.inputParam).split(",")
            inputArg = UtilMgr.cleanItem(inputArg, True)
        else:
            SysMgr.printErr("no input for PATH")
            sys.exit(-1)

        # convert input files #
        inputArg = UtilMgr.getFileList(inputArg, sort=True, exceptDir=True)

        # check tail flag #
        if "TAIL" in SysMgr.environList:
            tail = True
            nrLast = UtilMgr.getEnvironNum("TAIL", False, 100, False)
            SysMgr.streamEnable = True
        else:
            tail = False
            nrLast = 0

        if "SIZE" in SysMgr.environList:
            try:
                reqSize = UtilMgr.convUnit2Size(SysMgr.environList["SIZE"][0])
            except:
                sys.exit(0)
        else:
            reqSize = None

        prevStr = ""

        # print files #
        for path in inputArg:
            SysMgr.printStat(r"start printing '%s'..." % path)

            # open the target file #
            try:
                # check gzip magic number #
                if UtilMgr.isGzipFile(path):
                    fd = SysMgr.getPkg("gzip", False).open(path, "r")
                else:
                    fd = open(path, "r")
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenErr(path)
                continue

            newPos = pos = 0

            # set pos to EOF #
            if tail:
                try:
                    size = os.stat(path).st_size
                    pos = fd.seek(0, 2)
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

                # set path #
                pathList = [path, os.path.dirname(os.path.realpath(path))]

                # set flags #
                flags = [
                    "IN_ATTRIB",
                    "IN_MOVED_TO",
                    "IN_CREATE",
                    "IN_DELETE",
                    "IN_DELETE_SELF",
                    "IN_MODIFY",
                    "IN_MOVE_SELF",
                ]

            while 1:
                if tail:
                    # watch the file #
                    SysMgr.inotify(pathList, flags)
                    try:
                        # reopen the file #
                        fd.close()
                        fd = open(path, "r")
                        newSize = os.stat(path).st_size

                        # check file size #
                        if newPos == 0 or size > newSize:
                            newPos = newSize - nrLast
                            if newPos < 0:
                                newPos = 0

                        # update size #
                        size = newSize
                        fd.seek(newPos, 0)
                    except SystemExit:
                        sys.exit(0)
                    except:
                        newPos = 0
                        continue

                # read data #
                try:
                    if reqSize:
                        data = fd.read(reqSize)
                    else:
                        data = fd.read()
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(
                        "failed to read data from '%s'" % fd.name, True
                    )
                    continue

                # decompress data #
                try:
                    data = data.decode()
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

                # handle redundant data #
                if tail:
                    origPrevStr = prevStr
                    prevStr = data
                    if origPrevStr:
                        # get common part #
                        common = UtilMgr.getCommonPart([origPrevStr, data])
                        if common:
                            data = data.replace(common, "")
                            origPrevStr = common

                # update pos #
                pos = fd.tell()

                # handle event #
                if not data:
                    if tail:
                        continue
                    else:
                        break

                # print data #
                for line in data.split("\n"):
                    # apply filter #
                    if SysMgr.filterGroup and not UtilMgr.isValidStr(line):
                        continue

                    # print line #
                    if line:
                        SysMgr.printPipe(line)
                    else:
                        SysMgr.printPipe("\n")

                if tail:
                    SysMgr.printPipe("--- END [%s] ---" % UtilMgr.getUTCTime())
                else:
                    break

    @staticmethod
    def doPrintExt():
        SysMgr.printLogo(big=True, onlyFile=True)

        # check input #
        if SysMgr.hasMainArg():
            inputArg = SysMgr.getMainArgs()
        elif SysMgr.inputParam:
            inputArg = str(SysMgr.inputParam).split(",")
            inputArg = UtilMgr.cleanItem(inputArg, True)
        else:
            SysMgr.printErr("no input for PATH")
            sys.exit(-1)

        for path in inputArg:
            SysMgr.printStat(
                r"start traversing ext4 filesystem from '%s'..." % path
            )

            # make an ext4 object #
            try:
                eobj = Ext4Analyzer(path)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "failed to create ext4 object for %s" % path, True
                )
                continue

            # traverse all inodes #
            try:
                inodeList = eobj.getInodeList(
                    filters=SysMgr.filterGroup, verb=SysMgr.warnEnable
                )
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("failed to traverse %s" % path, True)
                continue

            # print menu #
            SysMgr.printPipe("\n[Ext4 Info] [Path: %s]\n%s" % (path, twoLine))
            SysMgr.printPipe(
                "{0:>12} {1:>6} {2:>1}\n{3:1}".format(
                    "INODE", "TYPE", "PATH", twoLine
                )
            )

            # print items #
            for inode, values in sorted(inodeList.items()):
                fpath = os.path.join(values["path"], values["name"])
                SysMgr.printPipe(
                    "{0:>12} {1:>6} {2:>1}".format(
                        inode, values["type"], fpath
                    )
                )
            SysMgr.printPipe(oneLine)

    @staticmethod
    def doMkCache():
        SysMgr.printLogo(big=True, onlyFile=True)

        # change priority #
        SysMgr.setLowPriority(force=False, cpuVal=10, verb=True)

        # set dwarf flag #
        SysMgr.setDwarfFlag()

        # check input #
        if SysMgr.hasMainArg():
            inputArg = SysMgr.getMainArgs()
        elif SysMgr.inputParam:
            inputArg = str(SysMgr.inputParam).split(",")
            inputArg = UtilMgr.cleanItem(inputArg, True)
        else:
            SysMgr.printErr("no input for PATH or COMM or PID")
            sys.exit(-1)

        # get pid list #
        pids = []
        for item in inputArg:
            pids = SysMgr.getTids(item)
            taskList = []
            for tid in pids:
                taskList.append(SysMgr.getTgid(tid))
            pids += list(set(taskList))
        pids = list(set(pids))

        # single file #
        if not pids:
            for item in inputArg:
                # check file #
                if not os.path.isfile(item):
                    SysMgr.printErr(
                        "failed to recognize '%s' as file or process" % item
                    )
                    sys.exit(-1)

                # load symbol caches #
                ElfAnalyzer.getObject(item)
        else:
            procList = {}

            # get pid list #
            for tid in pids:
                try:
                    pid = SysMgr.getTgid(tid)
                    if not pid:
                        continue

                    procList.setdefault(pid, [])
                    procList[pid].append(tid)
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

            pidList = list(map(long, procList))

            # merge map files #
            mapList = []
            getProcMapInfo = FileAnalyzer.getProcMapInfo
            for pid in pidList:
                mapList += getProcMapInfo(pid, onlyExec=True)
            mapList = list(set(mapList))

            # load symbol caches at once #
            printLog = True
            for item in mapList:
                try:
                    SysMgr.printInfo("load %s... " % item)

                    # create a new worker #
                    pid = SysMgr.createProcess(mute=True)
                    if pid != 0:
                        continue

                    # create a file cache #
                    ElfAnalyzer.getObject(item)

                    # terminate a worker #
                    sys.exit(0)
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

            SysMgr.printInfo("start waiting for workers... ", suffix=False)

            # wait for children #
            SysMgr.waitChild()

            SysMgr.printInfo("[Done]", prefix=False, title=False)

    @staticmethod
    def doSym2addr():
        SysMgr.printLogo(big=True, onlyFile=True)

        # check input #
        if SysMgr.hasMainArg():
            inputArg = SysMgr.getMainArg()
        elif SysMgr.inputParam:
            inputArg = str(SysMgr.inputParam)
        else:
            SysMgr.printErr("no input for PATH or COMM or PID")
            sys.exit(-1)

        # check symbol #
        if not SysMgr.filterGroup:
            SysMgr.printInfo("print all symbols")
            SysMgr.filterGroup.append("**")
        else:
            SysMgr.printInfo(
                "print all symbols including [ %s ]"
                % ",".join(SysMgr.filterGroup)
            )

        def _printRes(procInfo, resInfo, maxSymLen):
            if procInfo:
                procInfo = " [Task: %s]" % procInfo

            # make space between symbol and path #
            maxSymLen += 4

            SysMgr.printPipe("\n[Symbol Info]%s\n%s" % (procInfo, twoLine))
            SysMgr.printPipe(
                "{0:<{maxSymLen}} {1:<18} {2:<18} {3:1}\n{4:1}".format(
                    "Symbol",
                    "Offset",
                    "Address",
                    "PATH",
                    twoLine,
                    maxSymLen=maxSymLen,
                )
            )

            # print symbols from offset list #
            for sym, val in sorted(resInfo.items()):
                symbol = sym.split("|")[0]
                offset, filePath, addr, origsym = val

                if offset is None:
                    offset = "N/A"

                if addr is None:
                    addr = "N/A"

                SysMgr.printPipe(
                    "{0:<{maxSymLen}} {1:<18} {2:<18} {3:1}".format(
                        symbol,
                        offset.rstrip("L"),
                        addr.rstrip("L"),
                        filePath,
                        maxSymLen=maxSymLen,
                    )
                )

            if not resInfo:
                SysMgr.printPipe("\tNone")

            SysMgr.printPipe(oneLine + "\n")

        # init variables #
        resInfo = {}
        maxSymLen = 5

        # get pid list #
        pids = SysMgr.getTids(inputArg)
        taskList = []
        for tid in pids:
            taskList.append(SysMgr.getTgid(tid))
        pids = list(set(taskList))
        procInfo = ""

        # files #
        if not pids:
            # get file list #
            fileList = UtilMgr.getFileList(
                UtilMgr.cleanItem(inputArg.split(","), False), exceptDir=True
            )

            # check file #
            if not fileList:
                SysMgr.printErr(
                    "failed to recognize '%s' as a file or a process"
                    % inputArg
                )
                sys.exit(-1)

            for filePath in fileList:
                for sym in SysMgr.filterGroup:
                    # create an ELF object #
                    try:
                        offset = ElfAnalyzer.getSymOffset(sym, filePath)
                        if not offset:
                            continue

                        for item in offset:
                            resInfo["%s|%s" % (item[1], filePath)] = (
                                hex(item[0]),
                                filePath,
                                None,
                                item[1],
                            )

                            if maxSymLen < len(item[1]) < SysMgr.ttyCols / 2:
                                maxSymLen = len(item[1])
                    except SystemExit:
                        sys.exit(0)
                    except:
                        SysMgr.printErr("failed to get '%s' info" % sym, True)
                        sys.exit(-1)

            # print result #
            _printRes(procInfo, resInfo, maxSymLen)
        else:
            for pid in pids:
                # init variables #
                resInfo = {}
                maxSymLen = 5
                comm = SysMgr.getComm(pid)
                procInfo = "%s(%s)" % (comm, pid)
                symbolList = SysMgr.filterGroup

                # get symbol offset #
                resInfo = SysMgr.getProcAddrBySymbol(pid, symbolList)
                for key, item in resInfo.items():
                    if maxSymLen < len(item[3]) < SysMgr.ttyCols / 2:
                        maxSymLen = len(item[3])

                # print result #
                _printRes(procInfo, resInfo, maxSymLen)

    @staticmethod
    def initTaskMon(pid, update=True):
        if not SysMgr.isLinux:
            return None

        tobj = TaskAnalyzer(None, onlyInstance=True)
        path = "%s/%s" % (SysMgr.procPath, pid)
        tobj.saveProcData(path, pid)

        SysMgr.updateUptime()
        if update:
            tobj.saveProcInstance()

        return tobj

    @staticmethod
    def getTaskMon(tobj, pid, res):
        nowData = tobj.procData[pid]["stat"]
        prevData = tobj.prevProcData[pid]["stat"]

        if res == "ttime":
            utick = nowData[tobj.utimeIdx] - prevData[tobj.utimeIdx]
            stick = nowData[tobj.stimeIdx] - prevData[tobj.stimeIdx]
            return utick + stick
        else:
            return None

    @staticmethod
    def updateTaskMon(tobj, pid):
        if not SysMgr.isLinux:
            raise Exception("N/A")

        path = "%s/%s" % (SysMgr.procPath, SysMgr.pid)
        SysMgr.updateUptime()
        tobj.saveProcData(path, pid)
        tobj.setProcUsage()

    @staticmethod
    def doLeaktrace():
        def _sendSignal(sig, comm, pid, purpose):
            # save idle page status #
            if LeakAnalyzer.markedIdlePages:
                SysMgr.printStat(r"start checking all idle pages...")
                LeakAnalyzer.idlePageList = PageAnalyzer.getPageInfo(
                    [pid],
                    "anon",
                    checkIdle=True,
                    retList=True,
                    verb=False,
                    progress=True,
                )

            # send signal #
            try:
                os.kill(long(pid), sig)
                SysMgr.printStat(
                    "sent %s to %s(%s) to %s memory profiling"
                    % (ConfigMgr.SIG_LIST[sig], comm, pid, purpose)
                )
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "failed to send %s to %s memory profiling"
                    % (ConfigMgr.SIG_LIST[sig], purpose),
                    reason=True,
                )
                sys.exit(-1)

        def _waitAndKill(tobj, pid, comm, cond, sig, purpose, hookCmd=None):
            conv = UtilMgr.convSize2Unit

            # define indexes #
            utimeIdx = ConfigMgr.STAT_ATTR.index("UTIME")
            stimeIdx = ConfigMgr.STAT_ATTR.index("STIME")
            rssIdx = ConfigMgr.STAT_ATTR.index("RSS")
            vssIdx = ConfigMgr.STAT_ATTR.index("VSIZE")
            path = "%s/%s" % (SysMgr.procPath, pid)

            # check destination value #
            if cond == sys.maxsize or cond == SysMgr.maxSize:
                conds = ""
            else:
                conds = "/%s" % conv(cond, unit="M")

            # reset and save proc instance #
            tobj.saveProcInstance()

            # wait for RSS #
            prevCpu = None
            prevRss = None
            while 1:
                ret = tobj.saveProcData(path, pid)
                if not ret:
                    if not SysMgr.isAlive(pid):
                        SysMgr.printErr("%s(%s) is terminated" % (comm, pid))
                    else:
                        SysMgr.printErr(
                            "failed to get RSS of %s(%s)" % (comm, pid)
                        )
                    return -1

                # get time #
                SysMgr.updateUptime()
                diff = "[%s]" % UtilMgr.convTime(SysMgr.uptime)

                # get CPU usage #
                procData = tobj.procData[pid]["stat"]
                utime = long(procData[utimeIdx])
                stime = long(procData[stimeIdx])
                ttime = utime + stime
                if prevCpu != None:
                    cpu = ttime - prevCpu
                    cpustr = "%.1f" % (cpu / SysMgr.uptimeDiff)
                else:
                    prevCpu = ttime
                    time.sleep(1)
                    continue

                # get memory usage #
                procData = tobj.procData[pid]["stat"]
                vss = conv(long(procData[vssIdx]), unit="M")
                rss = long(procData[rssIdx]) << 12
                rssUnit = conv(rss, unit="M")
                tobj.saveProcSmapsData(
                    tobj.procData[pid]["taskPath"], pid, mini=True
                )
                memBuf, nrss, pss, uss = tobj.getMemDetails(
                    pid, tobj.procData[pid]["maps"]
                )
                pss = long(pss) << 10
                pssUnit = conv(pss, unit="M")
                uss = long(uss) << 10
                ussUnit = conv(uss, unit="M")

                # reset and save proc instance #
                tobj.saveProcInstance()

                # print memory usage #
                if prevCpu != cpu or prevRss != rssUnit:
                    SysMgr.printInfo(
                        (
                            "%s %s(%s)'s CPU(%s%%), VSS(%s), RSS(%s%s), "
                            "PSS(%s), USS(%s) for %s"
                        )
                        % (
                            diff,
                            comm,
                            pid,
                            cpustr,
                            vss,
                            rssUnit,
                            conds,
                            pssUnit,
                            ussUnit,
                            purpose,
                        ),
                        prefix=False,
                    )
                prevRss = rssUnit
                prevCpu = ttime

                if cond <= rss:
                    break
                else:
                    time.sleep(1)

            # set hook #
            if hookCmd:
                hcmd = ["hook", "-g%s" % pid, "-c%s" % ",".join(hookCmd), "-I"]
                SysMgr.launchGuider(
                    hcmd, pipe=False, stderr=True, log=True, wait=True
                )

            # check signal #
            if (
                not sig
                or not type(sig) in (int, long)
                or sig < 0
                or sig >= len(ConfigMgr.SIG_LIST)
            ):
                SysMgr.printErr("wrong signal %s" % sig)
                return -1

            # send signal #
            try:
                _sendSignal(sig, comm, pid, purpose)
            except:
                return -1

            return 0

        def _getOutputPath(multiple, pid):
            fname = None
            dirname = None

            # get dir name #
            if SysMgr.inputParam:
                dirname = os.path.realpath(SysMgr.inputParam)
                if not os.path.isdir(dirname):
                    fname = dirname
            elif os.path.exists(SysMgr.tmpPath):
                dirname = SysMgr.tmpPath
            elif SysMgr.isWritable("."):
                dirname = os.path.realpath(".")
            else:
                SysMgr.printErr("no input for temporary file path")
                sys.exit(-1)

            # set file name #
            if not fname:
                if multiple:
                    fname = "%s/leaks_%s.out" % (dirname, pid)
                else:
                    fname = "%s/leaks.out" % dirname

            return fname

        # check package #
        SysMgr.getPkg("ctypes")

        # check output path #
        if not SysMgr.outPath:
            SysMgr.outPath = "/tmp/guider.out"

        # check target info #
        if SysMgr.hasMainArg():
            inputCmd = SysMgr.getMainArg().split()
            targetList = []
        else:
            inputCmd = []
            targetList = SysMgr.filterGroup
            if not targetList:
                SysMgr.printErr("no input for PID or COMM")
                sys.exit(-1)

        # get signals #
        startSig = stopSig = None
        if SysMgr.killFilter:
            sigList = SysMgr.killFilter

            if len(sigList) >= 2:
                # start #
                sigval = sigList[0][0].strip()
                startSig = SysMgr.getSigNum(sigval)
                if not startSig:
                    SysMgr.printErr("wrong signal %s for start" % sigval)
                    sys.exit(-1)
                LeakAnalyzer.startSig = startSig

                stopIdx = 1
            else:
                stopIdx = 0

            # stop #
            sigval = sigList[stopIdx][0].strip()
            stopSig = SysMgr.getSigNum(sigval)
            if not stopSig:
                SysMgr.printErr("wrong signal %s for stop" % sigval)
                sys.exit(-1)
            LeakAnalyzer.stopSig = stopSig

        # check WAITSIGNAL flag #
        if "WAITSIGNAL" in SysMgr.environList:
            waitSignal = True
        else:
            waitSignal = False

        # check size filter #
        if "SIZEFILTER" in SysMgr.environList:
            try:
                filters = SysMgr.environList["SIZEFILTER"][0]
                LeakAnalyzer.filterCode = filters[0]
                LeakAnalyzer.filterValue = UtilMgr.convUnit2Size(filters[1:])
                SysMgr.printInfo("applied the size filter '%s'" % filters)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("failed to apply filter '%s'" % filters, True)
                sys.exit(-1)

        # get PID #
        pid = None
        comm = None
        isMulti = False
        startTime = endTime = 0
        if inputCmd:
            # set mute flag #
            if "MUTE" in SysMgr.environList:
                mute = True
            else:
                mute = False

            # set environment variable #
            SysMgr.environList.setdefault("ENV", [])

            # set PRELOAD path #
            libPath = SysMgr.getOption("T")
            if libPath:
                # handle special characters in path #
                newPath = UtilMgr.convPath(libPath)
                if not newPath:
                    SysMgr.printErr("wrong path '%s'" % libPath)
                    sys.exit(-1)
                elif len(newPath) > 1:
                    SysMgr.printErr(
                        "found multiple libraries [ %s ]" % ", ".join(newPath)
                    )
                    sys.exit(-1)
                else:
                    # convert to absolute path #
                    libPath = os.path.realpath(newPath[0])

                    # override LD_PRELOAD value #
                    if "LD_PRELOAD" in os.environ:
                        libPath += ":%s" % os.environ["LD_PRELOAD"]

                    # add PRELOAD path #
                    SysMgr.environList["ENV"].append("LD_PRELOAD=%s" % libPath)
            else:
                SysMgr.printErr("no path for libleaktracer.so")
                sys.exit(-1)

            # set output path #
            fname = _getOutputPath(isMulti, pid)

            # add start variable #
            if startSig or len(SysMgr.customCmd) > 1 or waitSignal:
                SysMgr.environList["ENV"].append(
                    "LEAKTRACER_ONSIG_STARTALLTHREAD=%s"
                    % LeakAnalyzer.startSig,
                )
            else:
                SysMgr.environList["ENV"].append(
                    "LEAKTRACER_ONSTART_STARTALLTHREAD=1"
                )

            # add report variable #
            SysMgr.environList["ENV"].extend(
                [
                    "LEAKTRACER_ONSIG_REPORT=%s" % LeakAnalyzer.stopSig,
                    "LEAKTRACER_ONSIG_REPORTFILENAME=%s" % fname,
                    "LEAKTRACER_ONEXIT_REPORT=1",
                    "LEAKTRACER_ONEXIT_REPORTFILENAME=%s" % fname,
                ]
            )

            # create the target process #
            pid = SysMgr.createProcess(inputCmd, mute=mute, chPgid=True)
            if pid < 0:
                sys.exit(-1)
            elif pid == 0:
                sys.exit(0)

            pids = [str(pid)]

            # wait for initialization of the target #
            # TODO: sync with the child to get memory map before termination #
            time.sleep(1)
        else:
            pids = SysMgr.convTaskList(targetList, exceptMe=True)

        # check PID #
        if not pids:
            SysMgr.printErr("no '%s' process" % ", ".join(targetList))
            sys.exit(-1)
        elif len(pids) > 1:
            SysMgr.printWarn(
                "multiple tasks [ %s ] are targeted"
                % SysMgr.getCommList(pids),
                True,
            )

            isMulti = True

            for item in pids:
                ret = SysMgr.createProcess()
                if not ret:
                    pid = item
                    break

            # parent process #
            if not pid:
                SysMgr.setIgnoreSignal()
                SysMgr.waitChild()
                SysMgr.setNormalSignal()
                sys.exit(0)
        else:
            pid = pids[0]

        # get comm and check alive #
        comm = SysMgr.getComm(pid)
        if not comm and not SysMgr.isAlive(pid):
            SysMgr.printErr("the task with PID %s is terminated" % pid)
            sys.exit(0)

        # get environment variables of the target #
        envList = SysMgr.getEnv(pid, retdict=True)

        # check permission #
        SysMgr.checkRootPerm()

        # define remote command list #
        remoteCmd = []
        hookCmd = []
        hookList = [
            "calloc",
            "malloc",
            "realloc",
            "free",
            "operator new(unsigned long)",
            "operator new(unsigned long\, std::align_val_t)",
            "operator new(unsigned long\, std::align_val_t\, std::nothrow_t const&)",
            "operator new(unsigned long\, std::nothrow_t const&)",
            "operator new[](unsigned long)",
            "operator new[](unsigned long\, std::align_val_t)",
            "operator new[](unsigned long\, std::align_val_t\, std::nothrow_t const&)",
            "operator new[](unsigned long\, std::nothrow_t const&)",
            "operator delete(void*)",
            "operator delete(void*\, std::align_val_t)",
            "operator delete(void*\, std::align_val_t\, std::nothrow_t const&)",
            "operator delete(void*\, std::nothrow_t const&)",
            "operator delete(void*\, unsigned long)",
            "operator delete(void*\, unsigned long\, std::align_val_t)",
            "operator delete[](void*)",
            "operator delete[](void*\, std::align_val_t)",
            "operator delete[](void*\, std::align_val_t\, std::nothrow_t const&)",
            "operator delete[](void*\, std::nothrow_t const&)",
            "operator delete[](void*\, unsigned long)",
            "operator delete[](void*\, unsigned long\, std::align_val_t)",
        ]

        # check PRELOAD result #
        libPath = None
        ret = FileAnalyzer.getMapFilePath(pid, "libleaktracer")
        if ret:
            preloaded = True
            SysMgr.printStat(
                "%s is already preloaded to %s(%s)" % (ret, comm, pid)
            )
        else:
            preloaded = False
            libPath = SysMgr.getOption("T")
            if libPath:
                # handle special characters in path #
                newPath = UtilMgr.convPath(libPath)
                if not newPath:
                    SysMgr.printErr("wrong path '%s'" % libPath)
                    sys.exit(-1)
                elif len(newPath) > 1:
                    SysMgr.printErr(
                        "found multiple libraries [ %s ]" % ", ".join(newPath)
                    )
                    sys.exit(-1)

                # convert to absolute path #
                libPath = os.path.realpath(newPath[0])

                remoteCmd.append("load:%s" % libPath)

                for item in hookList:
                    hookCmd.append("%s#%s#%s" % (item, libPath, item))

                SysMgr.printStat(
                    "%s is going to be injected automatically" % libPath
                )
            elif (
                not "LD_PRELOAD" in envList
                or not "libleaktracer" in envList["LD_PRELOAD"]
            ):
                SysMgr.printErr(
                    "failed to find libleaktracer.so on memory map "
                    "because the library is not preloaded"
                )
                sys.exit(-1)
            else:
                SysMgr.printErr(
                    "failed to find libleaktracer.so on memory map "
                    "because the library is not preloaded\n"
                    "\tIf the target process is on secure-execution mode,"
                    "\tlibleaktracer.so should be in standard search "
                    "directories specified in /etc/ld.so.conf,n"
                    "\tAnd all slashes in it's preload path will be ignored."
                )
                sys.exit(-1)

        # create a task object #
        SysMgr.ussEnable = True
        tobj = SysMgr.initTaskMon(pid, update=False)
        path = "%s/%s" % (SysMgr.procPath, pid)

        # execute watcher tasks #
        monTasks = []
        if "MEMPROF" in SysMgr.environList:
            interval = UtilMgr.getEnvironNum("MEMPROF", False, 1, False, True)
            output = os.path.join(
                os.path.dirname(SysMgr.outPath), "guider_mem_%s.out" % comm
            )
            mcmd = [
                "mtop",
                "-g%s" % pid,
                "-i%s" % interval,
                "-o%s" % output,
                "-qfastinit",
            ]
            ret = SysMgr.launchGuider(mcmd, mute=mute, pipe=False, stderr=True)
            if ret > 0:
                monTasks.append(ret)
                output = "%s_%s.out" % (UtilMgr.rstrip(output, ".out"), ret)
                SysMgr.printInfo(
                    "start saving the monitoring results of %s(%s) to %s"
                    % (comm, pid, output)
                )

        # set input file path #
        autostart = False
        if "LEAKTRACER_ONSTART_STARTALLTHREAD" in envList:
            autostart = True
            fname = envList["LEAKTRACER_ONSIG_REPORTFILENAME"]
            startTime = SysMgr.uptime - tobj.procData[pid]["runtime"]
        elif "LEAKTRACER_ONSIG_REPORTFILENAME" in envList:
            fname = envList["LEAKTRACER_ONSIG_REPORTFILENAME"]
        else:
            fname = _getOutputPath(isMulti, pid)

            # set output file path #
            if fname:
                remoteCmd.insert(
                    0, "setenv:LEAKTRACER_ONSIG_REPORTFILENAME#%s" % fname
                )

        # make full path #
        if not fname.startswith("/"):
            pwd = SysMgr.getPwd(pid)
            if pwd:
                fname = os.path.join(pwd, fname)

        # backup previous output file already exists #
        SysMgr.backupFile(fname)

        # check signal on platform #
        try:
            signal.signal(LeakAnalyzer.startSig, signal.SIG_IGN)
        except:
            LeakAnalyzer.startSig = 10
        try:
            signal.signal(LeakAnalyzer.stopSig, signal.SIG_IGN)
        except:
            LeakAnalyzer.stopSig = 12

        # set stop signal #
        if "LEAKTRACER_ONSIG_REPORT" in envList:
            stopSig = long(envList["LEAKTRACER_ONSIG_REPORT"])

        # set start signal and add an environment variable #
        if not autostart:
            startSig = LeakAnalyzer.startSig
            if not preloaded:
                remoteCmd.insert(
                    0, 'setenv:LEAKTRACER_ONSIG_STARTALLTHREAD#"%s"' % startSig
                )

        # add an environment variable for stop signal #
        if not stopSig:
            stopSig = LeakAnalyzer.stopSig
            if not preloaded:
                remoteCmd.insert(
                    0, 'setenv:LEAKTRACER_ONSIG_REPORT#"%s"' % stopSig
                )

        # register signal handler to mark all pages as idle #
        def _markIdlePages(signum, frame):
            SysMgr.printStat(r"start marking all pages as idle...")
            PageAnalyzer.getPageInfo(
                [pid], "anon", markIdle=True, verb=False, progress=True
            )
            LeakAnalyzer.markedIdlePages = True

        signal.signal(signal.SIGQUIT, _markIdlePages)

        # add an init call for tracing #
        if remoteCmd and not libPath:
            remoteCmd.append(
                "usercall:leaktracer::MemoryTrace::init_full_from_once()"
            )

        # check signal handler #
        failCnt = 0
        while 1:
            # set environment command #
            if remoteCmd:
                rcmd = [
                    "remote",
                    "-g%s" % pid,
                    "-c%s" % ",".join(remoteCmd),
                    "-I",
                ]
                SysMgr.launchGuider(
                    rcmd, pipe=False, stderr=True, log=True, wait=True
                )

            try:
                # check library #
                ret = FileAnalyzer.getMapFilePath(pid, "libleaktracer")
                if not ret:
                    SysMgr.printErr(
                        "failed to find '%s' on memory map" % libPath
                    )
                    if failCnt > 3:
                        sys.exit(-1)
                    else:
                        failCnt += 1
                        continue

                # get signal handler info #
                if "status" in tobj.procData[pid]:
                    tobj.procData[pid]["status"] = {}
                tobj.saveProcStatusData(path, pid)

                # check start signal #
                sigList = tobj.procData[pid]["status"]["SigCgt"]
                if startSig and not UtilMgr.isBitEnabled(startSig, sigList):
                    SysMgr.printWarn(
                        "failed to find %s(%s) handler for start"
                        % (ConfigMgr.SIG_LIST[startSig], startSig),
                        True,
                    )

                # check stop signal #
                if stopSig and not UtilMgr.isBitEnabled(stopSig, sigList):
                    SysMgr.printWarn(
                        "failed to find %s(%s) handler for stop"
                        % (ConfigMgr.SIG_LIST[stopSig], stopSig),
                        True,
                    )

                break
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("failed to check signal", reason=True)

        # set hook command #
        if hookCmd:
            hcmd = ["hook", "-g%s" % pid, "-c%s" % ",".join(hookCmd), "-I"]

        # wait for START signal #
        if not autostart and startSig and waitSignal:
            try:
                SysMgr.printStat(
                    r"start waiting for input... [ START(Ctrl+c) ]"
                )

                ret = _waitAndKill(
                    tobj, pid, comm, sys.maxsize, startSig, "start"
                )
            except:
                ret = 0

            # check exit condition #
            if ret < 0:
                sys.exit(-1)
            else:
                SysMgr.setSimpleSignal()

        # init condition variables #
        convUnit = UtilMgr.convUnit2Size
        cmd = SysMgr.customCmd
        startSize = endSize = 0

        # START #
        if cmd:

            def _getThreshold(value, rss):
                if value.startswith("+"):
                    return convUnit(value[1:]) + rss
                else:
                    return convUnit(value)

            # get RSS #
            try:
                mlist = SysMgr.getMemStat(pid)
                rssIdx = ConfigMgr.STATM_TYPE.index("RSS")
                rss = long(mlist[rssIdx]) << 12
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn(
                    "failed to get RSS info for %s(%s)" % (comm, pid),
                    True,
                    True,
                )
                rss = 0

            # get threshold size #
            if len(cmd) >= 2:
                startSize = _getThreshold(cmd[0], rss)
                endSize = _getThreshold(cmd[1], rss)
            else:
                endSize = _getThreshold(cmd[0], rss)

            # hook #
            if not startSize and hookCmd:
                startSize = 1
                SysMgr.launchGuider(
                    hcmd, pipe=False, stderr=True, log=True, wait=True
                )

            # wait for start threshold #
            if startSize > 0:
                ret = _waitAndKill(
                    tobj, pid, comm, startSize, startSig, "start", hookCmd
                )
                if ret < 0:
                    sys.exit(-1)
            # send signal for start #
            elif not autostart:
                _sendSignal(LeakAnalyzer.startSig, comm, pid, "start")
        elif startSig:
            # hook #
            if hookCmd:
                SysMgr.launchGuider(
                    hcmd, pipe=False, stderr=True, log=True, wait=True
                )

            # send signal for start #
            _sendSignal(startSig, comm, pid, "start")

        # update start time #
        if not startTime:
            SysMgr.updateUptime()
            startTime = SysMgr.uptime

        # set termination timer #
        signal.signal(signal.SIGALRM, SysMgr.onAlarm)
        signal.alarm(SysMgr.intervalEnable)

        # STOP #
        try:
            # set unlimited end size #
            if not endSize:
                endSize = sys.maxsize

            # wait for stop threshold or signal #
            try:
                SysMgr.printStat(
                    r"start monitoring... [ STOP(Ctrl+c), MARK(Ctrl+\) ]"
                )

                ret = _waitAndKill(tobj, pid, comm, endSize, stopSig, "stop")
            # stop profiling #
            except:
                ret = 0

                # send stop signal to target #
                _sendSignal(stopSig, comm, pid, "stop")

            # check exit condition #
            if ret < 0:
                sys.exit(-1)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to send %s to stop memory profiling"
                % ConfigMgr.SIG_LIST[stopSig],
                reason=True,
            )
            sys.exit(-1)

        # calculate runtime and profile time #
        try:
            SysMgr.updateTaskMon(tobj, pid)
            endTime = SysMgr.uptime
            runtime = UtilMgr.convTime(tobj.procData[pid]["runtime"])
            profileTime = UtilMgr.convTime(endTime - startTime)
        except SystemExit:
            sys.exit(0)
        except:
            runtime = "?"
            profileTime = "?"

        # terminate worker processes #
        if monTasks:
            SysMgr.killChildren(
                sig=signal.SIGINT, children=monTasks, clear=False
            )

        SysMgr.printStat("wait for %s" % fname)

        # wait for the output file to be closed #
        while 1:
            if not SysMgr.isAlive(pid):
                SysMgr.printErr("%s(%s) is terminated" % (comm, pid))
                sys.exit(0)

            tobj.saveFileStat([[pid], []])
            if not fname in tobj.fileData:
                break

            time.sleep(1)
            tobj.reinitStats()

        # set signal handler #
        SysMgr.setNormalSignal()

        # wait for the output file is written #
        while not os.path.exists(fname) or os.stat(fname).st_size == 0:
            time.sleep(1)
            if not SysMgr.isAlive(pid):
                SysMgr.printErr("%s(%s) is terminated" % (comm, pid))
                sys.exit(0)

        try:
            # analyze leakage #
            lt = LeakAnalyzer(fname, pid)

            # print logo #
            SysMgr.printLogo(big=True)

            # print resource info to temporary buffer #
            SysMgr().printResourceInfo()

            # print system information #
            SysMgr.printInfoBuffer()

            # print leakage #
            lt.printLeakage(runtime, profileTime, startTime)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to analyze memory leakage for %s(%s)" % (comm, pid),
                True,
            )

    @staticmethod
    def doNetTest():
        workload = []
        msg = "*" * 4096
        msg = msg.encode()

        def _iotask(val):
            prot = val[0].lower()
            if prot == "tcp":
                tcp = True
                SysMgr.printErr("TCP protocol is not supported yet")
                sys.exit(-1)
            elif prot == "udp":
                tcp = False
            else:
                SysMgr.printErr("%s protocol is not supported" % prot)
                sys.exit(-1)

            gObj = SysMgr.localServObj
            networkObject = NetworkMgr(
                "client", ip=gObj.ip, port=gObj.port, tcp=tcp
            )

            while 1:
                networkObject.sendto(msg, val[1], val[2])

            sys.exit(0)

        # set network config #
        value = SysMgr.getOption("x")
        if not value:
            NetworkMgr.setServerNetwork(None, None)
        else:
            service, ip, port = NetworkMgr.parseAddr(value)
            NetworkMgr.setServerNetwork(ip, port)

        # get tasks #
        try:
            prot = "udp"
            ip = "0.0.0.0"
            port = 55555

            if SysMgr.hasMainArg():
                jobs = SysMgr.getMainArg()
            elif SysMgr.inputParam:
                jobs = SysMgr.inputParam
            else:
                jobs = None

            if jobs:
                for item in jobs.split(","):
                    task = item.split(":")
                    if len(task) == 1:
                        prot = task[0]
                    elif len(task) == 2:
                        prot = task[0]
                        port = long(task[1])
                    elif len(task) == 3:
                        prot = task[0]
                        ip = task[1]
                        port = long(task[2])
                    else:
                        raise Exception("too many arguments")

                    workload.append([prot, ip, port])
            else:
                workload.append([prot, ip, port])
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                (
                    "wrong value for NETWORK load because %s, "
                    "input number in the format PROTOCOL{:IP:PORT}"
                )
                % SysMgr.getErrMsg()
            )
            sys.exit(-1)

        # run tasks #
        ioTasks = {}
        for idx, item in enumerate(workload):
            try:
                pid = SysMgr.createProcess()
                if pid == 0:
                    _iotask(workload[idx])
                else:
                    ioTasks[pid] = workload[idx]
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("failed to create process", True)
                sys.exit(-1)

        # set alarm #
        signal.signal(signal.SIGALRM, SysMgr.onAlarm)
        signal.alarm(SysMgr.intervalEnable)

        # wait for childrenren #
        while 1:
            if not ioTasks:
                break
            SysMgr.waitEvent(ignChldSig=False, exit=True)
            SysMgr.updateChildList()
            if SysMgr.isNoChild():
                break

    @staticmethod
    def statvfs(path):
        # load libc #
        if not SysMgr.loadLibcObj():
            return None

        if hasattr(SysMgr.libcObj, "statvfs"):
            func = SysMgr.libcObj.statvfs
        elif hasattr(SysMgr.libcObj, "statfs"):
            func = SysMgr.libcObj.statfs
        else:
            return None

        if SysMgr.statvfsObj:
            ret = func(path.encode(), byref(SysMgr.statvfsObj))
            if ret == 0:
                return SysMgr.statvfsObj
            else:
                return None

        # define statvfs object #
        class struct_statvfs(Structure):
            _fields_ = (
                ("f_bsize", c_ulong),  # filesystem block size
                ("f_frsize", c_ulong),  # fragment size
                ("f_blocks", c_ulong),  # size of fs in f_frsize units
                ("f_bfree", c_ulong),  # free blocks
                ("f_bavail", c_ulong),  # free blocks for unprivileged users
                ("f_files", c_ulong),  # inodes
                ("f_ffree", c_ulong),  # free inodes
                ("f_favail", c_ulong),  # free inodes for unprivileged users
                ("f_fsid", c_ulong),  # filesystem ID
                ("f_flag", c_ulong),  # mount flags
                ("f_namemax", c_ulong),  # maximum filename length
                ("f_type", c_ulong),  # maximum filename length
                ("reserved", c_char * 32),  # reserved
            )

        # define statfs object #
        class struct_statfs(Structure):
            _fields_ = (
                ("f_type", c_ulong),
                ("f_bsize", c_ulong),
                ("f_blocks", c_ulong),
                ("f_bfree", c_ulong),
                ("f_bavail", c_ulong),
                ("f_files", c_ulong),
                ("f_ffree", c_ulong),
                ("f_fsid", c_ulong),
                ("f_namelen", c_ulong),
                ("reserved", c_ulong * 12),
            )

        if hasattr(SysMgr.libcObj, "statvfs"):
            SysMgr.statvfsObj = struct_statvfs()
        elif hasattr(SysMgr.libcObj, "statfs"):
            SysMgr.statvfsObj = struct_statfs()

        ret = func(path.encode(), byref(SysMgr.statvfsObj))
        if ret == 0:
            return SysMgr.statvfsObj
        else:
            return None

    @staticmethod
    def doFlush():
        # check root permission #
        SysMgr.checkRootPerm()

        # get command #
        if SysMgr.hasMainArg():
            cmd = SysMgr.getMainArg()
        elif SysMgr.filterGroup:
            cmd = SysMgr.filterGroup
        else:
            cmd = None

        if SysMgr.findOption("i"):
            interval = SysMgr.intervalEnable
        else:
            interval = None

        while 1:
            # flush caches #
            if not cmd:
                SysMgr.dropCaches("3", verb=True)
            elif cmd in ("1", "2", "3"):
                SysMgr.dropCaches(cmd, verb=True)
            else:
                SysMgr.printInfo(
                    "flush file caches for '%s'... " % os.path.realpath(cmd),
                )
                SysMgr.invalidateFile(cmd)

            if interval is None:
                break
            else:
                time.sleep(interval)

    @staticmethod
    def dropCaches(val, verb=False):
        try:
            dropCachePath = "%s/sys/vm/drop_caches" % SysMgr.procPath
            with open(dropCachePath, "w") as fd:
                if verb:
                    SysMgr.printInfo(
                        "start flushing system caches(%s)... " % val,
                        suffix=False,
                    )
                ret = fd.write(val)
                if verb:
                    SysMgr.printInfo("[Done]", prefix=False, title=False)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("failed to flush system cache", reason=True)

    @staticmethod
    def doIoTest():
        # snapshot system info including mount #
        SysMgr()

        workload = []
        writeData = b"0" * 4096

        def _flushCache(verb=False):
            ret = SysMgr.checkRootPerm(verb=False)
            SysMgr.dropCaches("3", verb)

        def _iotask(num, load):
            def _readChunk(fobj, chunk=4096, sync=False):
                while 1:
                    ret = os.read(fobj, chunk)
                    yield ret

            def _writeChunk(fobj, chunk=4096, sync=False):
                while 1:
                    ret = os.write(fobj, writeData[:chunk])
                    if sync:
                        os.fsync(fobj)
                    yield ret

            # set default signal handlers #
            SysMgr.setDefaultSignal()

            # get jobs #
            op = load["op"]
            path = load["path"]
            size = load["size"]

            # set handler #
            if op == "read":
                opFunc = _readChunk
                flag = os.O_RDONLY
            elif op == "write":
                opFunc = _writeChunk
                flag = os.O_WRONLY | os.O_CREAT | os.O_TRUNC
            else:
                SysMgr.printErr("failed to recognize operation %s" % op)
                sys.exit(-1)

            # set operation #
            if op == "write":
                # set direction #
                direct = "to"

                # convert path list #
                pathList = path.split(",")
                pathList = UtilMgr.cleanItem(pathList)
            elif op == "read":
                # set direction #
                direct = "from"

                # convert path list #
                pathList = UtilMgr.convPath(path, separator=",")
                if not pathList:
                    SysMgr.printErr("failed to recognize '%s'" % path)
                    sys.exit(-1)

            for path in pathList:
                # check I/O type #
                if os.path.isfile(path) or SysMgr.isBlkDev(path):
                    target = "file"
                elif os.path.isdir(path):
                    if op == "write":
                        path = os.path.join(path, "WRTEST")
                    else:
                        target = "dir"
                elif op == "write" and SysMgr.isWritable(path):
                    target = "file"
                else:
                    SysMgr.printErr("failed to access '%s'" % path)
                    return

                # set repeat count #
                repeat = SysMgr.repeatInterval
                if repeat == 0:
                    repeat = 1

                # make file size string #
                fsize = ""
                if target == "file":
                    # get output size #
                    fsize = UtilMgr.getFileSizeStr(path)

                # declare shortcut function #
                conv = UtilMgr.convNum

                # make load string #
                if size > 0:
                    loadStr = "only %s " % UtilMgr.convSize2Unit(size)
                else:
                    loadStr = ""

                # flush page caches #
                if "CHUNK" in SysMgr.environList:
                    try:
                        chunkVar = SysMgr.environList["CHUNK"][0]
                        chunk = UtilMgr.convUnit2Size(chunkVar)
                    except:
                        SysMgr.printErr(
                            "failed to convert I/O chunk '%s'" % chunkVar, True
                        )
                        sys.exit(-1)
                else:
                    chunk = 4096

                SysMgr.printInfo(
                    "%s %s%s '%s%s' %s times\n"
                    % (op, loadStr, direct, path, fsize, conv(repeat))
                )

                # set sync flag #
                if "SYNC" in SysMgr.environList:
                    sync = True
                else:
                    sync = False

                # run loop #
                for seq in xrange(repeat):
                    sys.stdout.write(
                        "(%s) %s %s '%s'... "
                        % (
                            conv(seq),
                            op,
                            target,
                            UtilMgr.convColor(path, "CYAN"),
                        )
                    )
                    sys.stdout.flush()

                    # flush page caches #
                    if "DROPCACHE" in SysMgr.environList:
                        _flushCache()

                    # save timestamp #
                    start = time.time()

                    # FILE #
                    if target == "file":
                        try:
                            done = 0
                            fd = os.open(path, flag)
                            for piece in opFunc(fd, chunk, sync):
                                # update progress #
                                if isinstance(piece, (int, long)):
                                    done += piece
                                else:
                                    done += len(piece)

                                # check stop condition #
                                if not piece:
                                    break
                                elif size > 0 and done >= size:
                                    break
                            os.close(fd)
                        except SystemExit:
                            sys.exit(0)
                        except:
                            SysMgr.printWarn(
                                "failed to access %s for %s" % (path, op),
                                True,
                                True,
                            )
                            break
                    elif target != "dir":
                        continue

                    # DIR #
                    for r, d, f in os.walk(path):
                        for item in f:
                            try:
                                fpath = os.path.join(r, item)
                                if not os.path.isfile(fpath):
                                    continue

                                fd = os.open(fpath, flag)
                                for piece in opFunc(fd, chunk, sync):
                                    if not piece:
                                        break
                                os.close(fd)
                            except SystemExit:
                                sys.exit(0)
                            except:
                                SysMgr.printWarn(
                                    "failed to access %s for %s" % (fpath, op),
                                    True,
                                    True,
                                )

                    elapsed = "%.6f" % (time.time() - start)
                    sys.stdout.write(
                        "[%s]\n" % UtilMgr.convColor(elapsed, "GREEN")
                    )

        # get tasks #
        try:
            # get option #
            if SysMgr.hasMainArg():
                opList = SysMgr.getMainArgs(False)
            elif SysMgr.filterGroup:
                opList = SysMgr.filterGroup
            else:
                opList = None

            # parse option #
            if opList:
                for item in opList:
                    size = 0

                    item = item.split(":")

                    if len(item) == 1:
                        op = "read"
                        path = item[0]
                    elif len(item) == 3:
                        op, path, size = item
                        try:
                            size = UtilMgr.convUnit2Size(size)
                        except SystemExit:
                            sys.exit(0)
                        except:
                            sys.exit(0)
                    else:
                        op, path = item

                    workload.append({"op": op, "path": path, "size": size})
            # read all mount directories #
            elif SysMgr.showAll:
                for path, value in SysMgr.sysInstance.mountInfo.items():
                    if not path.startswith("/dev/") or "loop" in path:
                        continue

                    if hasattr(os, "statvfs"):
                        stat = os.statvfs(value["path"])
                    else:
                        stat = SysMgr.statvfs(value["path"])

                    size = stat.f_bsize * stat.f_blocks

                    workload.append({"op": "read", "path": path, "size": size})
            # read current directory #
            else:
                # get device ID #
                fstat = os.lstat(".")
                major = str(os.major(fstat.st_dev))
                minor = str(os.minor(fstat.st_dev))

                # get mount point #
                mountPoint = None
                for path, value in SysMgr.sysInstance.mountInfo.items():
                    if value["major"] == major and value["minor"] == minor:
                        mountPoint = value["path"]
                        break

                # just use PWD #
                if not mountPoint:
                    mountPoint = "."

                if not os.path.exists(mountPoint):
                    SysMgr.printErr("failed to access to %s" % mountPoint)
                    sys.exit(-1)

                workload.append({"op": "read", "path": mountPoint, "size": 0})

        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                (
                    "wrong value for I/O load because %s, "
                    "input number in the format OP:PATH"
                )
                % SysMgr.getErrMsg()
            )
            sys.exit(-1)

        # flush page caches #
        if "DROPCACHE" in SysMgr.environList:
            _flushCache(verb=True)

        # run tasks #
        ioTasks = {}
        for _ in xrange(1):
            for idx in xrange(len(workload)):
                try:
                    pid = SysMgr.createProcess()
                    if pid == 0:
                        _iotask(idx, workload[idx])
                        sys.exit(0)
                    else:
                        ioTasks[pid] = workload[idx]
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr("failed to create process", True)
                    sys.exit(-1)

        # set alarm #
        try:
            signal.signal(signal.SIGALRM, SysMgr.onAlarm)
            signal.alarm(SysMgr.intervalEnable)
        except:
            SysMgr.printErr(
                "failed to set alarm to %s" % SysMgr.intervalEnable, True
            )
            sys.exit(-1)

        # wait for childrenren #
        while 1:
            if not ioTasks:
                break
            SysMgr.waitEvent(ignChldSig=False, exit=True)
            SysMgr.updateChildList()
            if SysMgr.isNoChild():
                break

    @staticmethod
    def getPciList(cache=True):
        if cache and SysMgr.pciList:
            return SysMgr.pciList

        try:
            with open("/usr/share/misc/pci.ids") as reader:
                SysMgr.pciList = reader.read().strip().split("\n")
        except:
            try:
                with open("/usr/share/hwdata/pci.ids") as reader:
                    SysMgr.pciList = reader.read().strip().split("\n")
            except:
                SysMgr.pciList = []

        return SysMgr.pciList

    @staticmethod
    def getGpuList():
        gpuNameList = []
        gpuVendorList = []
        gpuDeviceList = []

        # get PCI list #
        pciList = SysMgr.getPciList()
        if not pciList:
            return gpuNameList

        pciList = "\n".join(pciList)

        # get driver list #
        try:
            gpuList = [
                name
                for name in os.listdir("/dev/dri/")
                if name.rstrip("0123456789") == "card"
            ]
        except SystemExit:
            sys.exit(0)
        except:
            return gpuNameList

        for gpu in gpuList:
            try:
                vendor = device = "UNKNOWN"
                commonPath = "/sys/class/drm/" + gpu + "/device/"
                with open(commonPath + "vendor") as reader:
                    vendor = reader.read().split("x")[1].strip()
                with open(commonPath + "device") as reader:
                    device = reader.read().split("x")[1].strip()
            except SystemExit:
                sys.exit(0)
            except:
                pass

            vendorStr = "\n" + vendor + "  "
            deviceStr = "\n\t" + device + "  "

            if vendorStr in pciList:
                rest = pciList.split(vendorStr, 1)[1]
                vendorName = rest.split("\n", 1)[0].strip()
            else:
                vendorName = "UNKNOWN"

            if deviceStr in rest and vendorName != "UNKNOWN":
                rest = rest.split(deviceStr, 1)[1]
                deviceName = rest.split("\n", 1)[0].strip()
            else:
                deviceName = "UNKNOWN"

            gpuNameList.append("%s - %s" % (vendorName, deviceName))
            gpuVendorList.append(vendor)
            gpuDeviceList.append(device)

        return gpuNameList

    @staticmethod
    def getGpuInfo():
        return SysMgr.getGpuInfo_NVIDIA()

    @staticmethod
    def getGpuInfo_NVIDIA():
        def _ConvertSMVer2Cores(major, minor):
            # Returns the number of CUDA cores per multiprocessor for a given
            # Compute Capability version. There is no way to retrieve that via
            # the API, so it needs to be hard-coded. See _ConvertSMVer2Cores
            # in helper_cuda.h in NVIDIA's CUDA Samples.
            return {
                # Tesla
                (1, 0): 8,  # SM 1.0
                (1, 1): 8,  # SM 1.1
                (1, 2): 8,  # SM 1.2
                (1, 3): 8,  # SM 1.3
                # Fermi
                (2, 0): 32,  # SM 2.0: GF100 class
                (2, 1): 48,  # SM 2.1: GF10x class
                # Kepler
                (3, 0): 192,  # SM 3.0: GK10x class
                (3, 2): 192,  # SM 3.2: GK10x class
                (3, 5): 192,  # SM 3.5: GK11x class
                (3, 7): 192,  # SM 3.7: GK21x class
                # Maxwell
                (5, 0): 128,  # SM 5.0: GM10x class
                (5, 2): 128,  # SM 5.2: GM20x class
                (5, 3): 128,  # SM 5.3: GM20x class
                # Pascal
                (6, 0): 64,  # SM 6.0: GP100 class
                (6, 1): 128,  # SM 6.1: GP10x class
                (6, 2): 128,  # SM 6.2: GP10x class
                # Volta
                (7, 0): 64,  # SM 7.0: GV100 class
                (7, 2): 64,  # SM 7.2: GV11b class
                # Turing
                (7, 5): 64,  # SM 7.5: TU10x class
            }.get(
                (major, minor), 64
            )  # unknown architecture

        CUDA_SUCCESS = 0
        CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT = 16
        CU_DEVICE_ATTRIBUTE_MAX_THREADS_PER_MULTIPROCESSOR = 39
        CU_DEVICE_ATTRIBUTE_CLOCK_RATE = 13
        CU_DEVICE_ATTRIBUTE_MEMORY_CLOCK_RATE = 36

        if not SysMgr.importPkgItems("ctypes", False):
            return None

        nGpus = c_int()
        name = b" " * 100
        cc_major = c_int()
        cc_minor = c_int()
        cores = c_int()
        threads_per_core = c_int()
        clockrate = c_int()
        freeMem = c_size_t()
        totalMem = c_size_t()

        result = c_int()
        device = c_int()
        context = c_void_p()

        try:
            cuda = SysMgr.loadLib("libcuda.so")
        except:
            return None

        result = cuda.cuInit(0)
        if result != CUDA_SUCCESS:
            return None

        result = cuda.cuDeviceGetCount(byref(nGpus))
        if result != CUDA_SUCCESS:
            return None

        gpuInfo = {}

        for i in xrange(nGpus.value):
            result = cuda.cuDeviceGet(byref(device), i)
            if result != CUDA_SUCCESS:
                return None

            gpuInfo[i] = {}

            if (
                cuda.cuDeviceGetName(c_char_p(name), len(name), device)
                == CUDA_SUCCESS
            ):
                gpuInfo[i]["name"] = name.split(b"\0", 1)[0].decode()

            if (
                cuda.cuDeviceComputeCapability(
                    byref(cc_major), byref(cc_minor), device
                )
                == CUDA_SUCCESS
            ):
                gpuInfo[i]["capa"] = "%d.%d" % (cc_major.value, cc_minor.value)

            if (
                cuda.cuDeviceGetAttribute(
                    byref(cores),
                    CU_DEVICE_ATTRIBUTE_MULTIPROCESSOR_COUNT,
                    device,
                )
                == CUDA_SUCCESS
            ):
                gpuInfo[i]["processor"] = cores.value
                gpuInfo[i]["core"] = cores.value * _ConvertSMVer2Cores(
                    cc_major.value, cc_minor.value
                )

                if (
                    cuda.cuDeviceGetAttribute(
                        byref(threads_per_core),
                        CU_DEVICE_ATTRIBUTE_MAX_THREADS_PER_MULTIPROCESSOR,
                        device,
                    )
                    == CUDA_SUCCESS
                ):
                    gpuInfo[i]["threads"] = (
                        cores.value * threads_per_core.value
                    )

            if (
                cuda.cuDeviceGetAttribute(
                    byref(clockrate), CU_DEVICE_ATTRIBUTE_CLOCK_RATE, device
                )
                == CUDA_SUCCESS
            ):
                gpuInfo[i]["gpuClock(MHz)"] = clockrate.value / 1000.0

            if (
                cuda.cuDeviceGetAttribute(
                    byref(clockrate),
                    CU_DEVICE_ATTRIBUTE_MEMORY_CLOCK_RATE,
                    device,
                )
                == CUDA_SUCCESS
            ):
                gpuInfo[i]["memClock(MHz)"] = clockrate.value / 1000.0

            result = cuda.cuCtxCreate(byref(context), 0, device)
            if result == CUDA_SUCCESS:
                result = cuda.cuMemGetInfo(byref(freeMem), byref(totalMem))
                if result == CUDA_SUCCESS:
                    gpuInfo[i]["totalMem(MB)"] = totalMem.value / 1024**2
                    gpuInfo[i]["freeMem(MB)"] = freeMem.value / 1024**2

                cuda.cuCtxDetach(context)

        return gpuInfo

    @staticmethod
    def doRequest(reqstr=None):
        def _convStr2Data(string, enc=False):
            # define keys #
            skey = "@@@BIN:"
            ekey = "@@@"

            # get pos #
            start = string.find(skey)
            if start < 0:
                return string
            secStart = start + len(skey)
            end = string[secStart:].find(ekey)
            if end < 0:
                return string

            # get real size #
            size = string[secStart : secStart + end]
            rsize = UtilMgr.convUnit2Size(size)

            # allocate byte array #
            data = bytes(rsize)

            return data

        def _convPath2Data(path, enc=False):
            if not path or not isinstance(path, str):
                return path

            # define keys #
            skey = "@@@FILE:"
            ekey = "@@@"

            # get pos #
            start = path.find(skey)
            if start < 0:
                return _convStr2Data(path, enc=enc)
            secStart = start + len(skey)
            end = path[secStart:].find(ekey)
            if end < 0:
                return _convStr2Data(path, enc=enc)

            # get real path #
            rpath = path[secStart : secStart + end]

            # read data #
            with open(rpath, "rb") as fd:
                data = fd.read()

                # encode to base64 #
                if enc:
                    data = UtilMgr.encodeBase64(data)
                else:
                    data = data

                data = (
                    path[:start].encode()
                    + data
                    + path[secStart + end + len(ekey) :].encode()
                )

            return data

        def _convPath2DataJson(obj, enc=False):
            if isinstance(obj, list):
                for idx, item in enumerate(obj):
                    if isinstance(item, list):
                        obj[idx] = _convPath2DataJson(item, enc)
                    elif isinstance(item, dict):
                        obj[idx] = _convPath2DataJson(item, enc)
                    else:
                        obj[idx] = _convPath2Data(item, enc)
            elif isinstance(obj, dict):
                for idx, item in obj.items():
                    if isinstance(item, list):
                        obj[idx] = _convPath2DataJson(item, enc)
                    elif isinstance(item, dict):
                        obj[idx] = _convPath2DataJson(item, enc)
                    else:
                        obj[idx] = _convPath2Data(item, enc)
            else:
                return _convPath2Data(obj, enc)

            return obj

        def _request(
            req, cache, stats, idx, lastReqTime, verb=False, mute=False
        ):
            cmd = None
            arg = None
            json = None

            # get data from cache #
            try:
                (
                    cmd,
                    method,
                    content,
                    arg,
                    timeout,
                    auth,
                    verify,
                    cookies,
                    headers,
                    reqstr,
                    files,
                    json,
                ) = cache[req]
            # parse request #
            except:
                timeout = None
                auth = None
                verify = False
                cookies = None
                headers = None

                # alias #
                if req.startswith("ALIAS:"):
                    alias, remain = req.split("#", 1)
                    alias = alias.split(":", 1)[1]
                    stats["name"].setdefault(req, alias)
                else:
                    remain = req

                # create a session to improve performance by session reuse #
                try:
                    if not "KEEPALIVE" in SysMgr.environList:
                        raise Exception()
                    obj = requests.Session()
                except SystemExit:
                    sys.exit(0)
                except:
                    obj = requests

                # GET #
                if remain.startswith("GET#"):
                    method = "GET"
                    cmd = obj.get
                    remain = remain[len(method) + 1 :]
                # POST #
                elif remain.startswith("POST#"):
                    method = "POST"
                    cmd = obj.post
                    remain = remain[len(method) + 1 :]
                # default #
                else:
                    method = "GET"
                    cmd = obj.get

                # check method #
                if not cmd:
                    return

                files = []

                # parse options #
                # refer to https://requests.readthedocs.io #
                while 1:
                    if remain.startswith("DATA:") or remain.startswith(
                        "JSONDATA:"
                    ):
                        orig = remain
                        data, remain = remain.split("#", 1)
                        data = data.split(":", 1)[1]

                        # convert string to dictionary #
                        if orig.startswith("JSONDATA:"):
                            json = UtilMgr.convStr2Dict(data, verb=True)
                        else:
                            arg = data
                    elif remain.startswith("DATAFILE:") or remain.startswith(
                        "JSONFILE:"
                    ):
                        try:
                            orig = remain
                            data, remain = remain.split("#", 1)

                            # read data from file #
                            path = "??"
                            path = data.split(":", 1)[1]
                            with open(path, "rb") as fd:
                                data = fd.read()
                                try:
                                    data = data.decode()
                                except:
                                    pass

                            # convert string to dictionary #
                            if orig.startswith("JSONFILE:"):
                                json = UtilMgr.convStr2Dict(data, verb=True)
                            else:
                                arg = data
                        except SystemExit:
                            sys.exit(0)
                        except:
                            SysMgr.printErr(
                                "failed to get data from '%s'" % path,
                                reason=True,
                            )
                            sys.exit(-1)
                    elif remain.startswith("FILE:"):
                        try:
                            orig = remain
                            data, remain = remain.split("#", 1)
                            path = "??"

                            # define name and path #
                            fileInfo = data.split(":")[1:]
                            if len(fileInfo) == 1:
                                name = path = fileInfo[0]
                                addinfo = [name]
                            else:
                                name = fileInfo[0]
                                path = fileInfo[1]
                                addinfo = []

                            # add a file descriptor #
                            fileInfo.insert(len(fileInfo), open(path, "rb"))

                            # complete tuple data #
                            fileArgs = tuple(addinfo + fileInfo[1:])

                            files.append((name, fileArgs))
                        except SystemExit:
                            sys.exit(0)
                        except:
                            SysMgr.printErr(
                                "failed to get data from '%s'" % path,
                                reason=True,
                            )
                            sys.exit(-1)
                    elif remain.startswith("TIMEOUT:"):
                        timestr, remain = remain.split("#", 1)
                        timeout = timestr.split(":", 1)[1].strip()
                        if not timeout.isdigit():
                            SysMgr.printErr(
                                "failed to get timeout(sec) in %s" % timestr
                            )
                            sys.exit(-1)
                        timeout = long(timeout)
                    elif remain.startswith("AUTH:"):
                        authstr, remain = remain.split("#", 1)
                        auth = authstr.split(":", 1)[1].strip()
                        auth = tuple(
                            [item.strip() for item in auth.split(",")]
                        )
                    elif remain.startswith("VERIFY:"):
                        verifystr, remain = remain.split("#", 1)
                        verify = verifystr.split(":", 1)[1].strip().upper()
                        if verify == "TRUE":
                            verify = True
                        elif verify == "FALSE":
                            verify = False
                        else:
                            SysMgr.printErr(
                                "failed to get verify(TRUE/FALSE) value"
                            )
                            sys.exit(-1)
                    elif remain.startswith("COOKIES:"):
                        cookiestr, remain = remain.split("#", 1)
                        cookiestr = cookiestr.split(":", 1)[1].strip()
                        cookielist = cookiestr.split(",")
                        cookies = {}
                        for item in cookielist:
                            data = item.split(":", 1)
                            cookies.setdefault(
                                data[0].strip(), data[1].strip()
                            )
                    elif remain.startswith("HEADERS:"):
                        headerstr, remain = remain.split("#", 1)
                        headerstr = headerstr.split(":", 1)[1].strip()
                        headerlist = headerstr.split(",")
                        headers = {}
                        for item in headerlist:
                            data = item.split(":", 1)
                            headers.setdefault(
                                data[0].strip(), data[1].strip()
                            )
                    else:
                        break

                # check protocol #
                content = remain
                if not content.startswith("http"):
                    SysMgr.printErr(
                        'no protocol such like "http" in %s' % content
                    )

                # convert request #
                reqstr = "%s %s" % (method, content)
                if req in stats["name"]:
                    reqstr = "(%s) %s" % (stats["name"][req], reqstr)
                if arg:
                    reqstr += " DATA:%s" % repr(arg)
                if json:
                    reqstr += " JSON:%s" % repr(json)
                if timeout:
                    reqstr += " TIMEOUT:%s" % timeout
                if auth:
                    reqstr += " AUTH:%s" % str(auth)
                if verify:
                    reqstr += " VERIFY:%s" % verify
                if cookies:
                    reqstr += " COOKIES:%s" % repr(cookies)
                if headers:
                    reqstr += " HEADERS:%s" % repr(headers)
                reqstr = UtilMgr.convColor(reqstr, "UNDERLINE")

                # convert path to data #
                if json:
                    _convPath2DataJson(json, enc=True)
                if arg:
                    arg = _convPath2Data(arg, enc=True)

                # cache data #
                cache[req] = (
                    cmd,
                    method,
                    content,
                    arg,
                    timeout,
                    auth,
                    verify,
                    cookies,
                    headers,
                    reqstr,
                    files,
                    json,
                )

            # convert sequence #
            idx = UtilMgr.convNum(idx)

            # print request #
            if not mute:
                SysMgr.printPipe(
                    "\n%s(%s) <%s> [%.6f] -> %s"
                    % (SysMgr.comm, SysMgr.pid, idx, time.time(), reqstr)
                )

            before = time.time()
            lastReqTime[0] = before

            # request #
            if json:
                res = cmd(
                    content,
                    json=json,
                    timeout=timeout,
                    auth=auth,
                    verify=verify,
                    cookies=cookies,
                    headers=headers,
                    files=files,
                )
            elif arg:
                res = cmd(
                    content,
                    arg,
                    timeout=timeout,
                    auth=auth,
                    verify=verify,
                    cookies=cookies,
                    headers=headers,
                    files=files,
                )
            else:
                res = cmd(
                    content,
                    timeout=timeout,
                    auth=auth,
                    verify=verify,
                    cookies=cookies,
                    headers=headers,
                    files=files,
                )

            # update time #
            after = time.time()
            elapsed = after - before

            # print request #
            if verb:
                data = res.request.headers
                data["Body"] = res.request.body
                data = str(data).replace("\\n", "\n")
                data = str(data).replace("\\r", "")
                SysMgr.printWarn(data, True)

            # save statistics #
            stats["perReqTime"].setdefault(req, [])
            stats["perReqTime"][req].append(elapsed)
            stats["perReqTimeAll"][req].append([before, elapsed])

            # check mute option #
            if mute:
                # raise Exception for error #
                if not res.ok:
                    raise Exception(res.reason)
                return

            # convert result #
            if res.ok:
                success = UtilMgr.convColor("OK", "GREEN")
            else:
                success = UtilMgr.convColor(res.reason, "RED")

            # convert code #
            code = UtilMgr.convColor(res.status_code, "SPECIAL")

            # convert text #
            if SysMgr.showAll:
                text = ": %s" % res.text
            else:
                text = ""

            # round elapsd time #
            elapsed = "%.6f" % elapsed

            # print response #
            SysMgr.printPipe(
                "%s(%s) <%s> [%.6f] <- [%s/%s] %s%s"
                % (
                    SysMgr.comm,
                    SysMgr.pid,
                    idx,
                    after,
                    code,
                    UtilMgr.convColor(elapsed, "CYAN"),
                    success,
                    text,
                )
            )

            # raise Exception for error #
            if not res.ok:
                raise Exception(res.reason)

        def _task(reqs, repeat, delay, cache):
            # initialize statistics #
            stats = {
                "perReqTime": {},
                "perReqTimeAll": {},
                "perReqErr": {},
                "perCycleTime": [],
                "name": {},
            }

            convNum = UtilMgr.convNum

            # set mute flag #
            if "MUTE" in SysMgr.environList:
                mute = True
            else:
                mute = False

            # set verb flag #
            if "PRINTREQ" in SysMgr.environList:
                verb = True
            else:
                verb = False

            # save task stat #
            tobj = SysMgr.initTaskMon(SysMgr.pid)

            start = time.time()

            try:
                lastReqTime = [0]
                idx = 1
                for idx in xrange(repeat):
                    before = time.time()

                    for req in reqs:
                        try:
                            stats["perReqTimeAll"].setdefault(req, [])
                            stats["perReqErr"].setdefault(req, 0)

                            # do request #
                            _request(
                                req, cache, stats, idx, lastReqTime, verb, mute
                            )

                            # make a delay #
                            if delay > 0:
                                time.sleep(delay)

                            # print progress #
                            if mute:
                                UtilMgr.printProgress(idx, repeat)
                        except SystemExit:
                            sys.exit(0)
                        except:
                            stats["perReqTimeAll"][req].append(
                                [lastReqTime[0], 0]
                            )
                            stats["perReqErr"][req] += 1
                            SysMgr.printErr(
                                "failed to request '%s'" % req, reason=True
                            )

                            # reset signal and exit flag #
                            SysMgr.setSimpleSignal()

                    elapsed = time.time() - before
                    stats["perCycleTime"].append(elapsed)
            except:
                pass

            totalElapsed = time.time() - start

            # get CPU usage #
            try:
                SysMgr.updateTaskMon(tobj, SysMgr.pid)
                tcpu = SysMgr.getTaskMon(tobj, SysMgr.pid, "ttime")
                acpu = tcpu / totalElapsed
                if tcpu <= totalElapsed * 100:
                    tcpu = convNum(tcpu)
                    acpu = convNum(acpu)
                else:
                    tcpu = acpu = 0
            except SystemExit:
                sys.exit(0)
            except:
                tcpu = "?"
                acpu = "?"

            # make repeat string #
            if repeat == sys.maxsize or repeat == SysMgr.maxSize:
                repeatStr = "INFINITE"
            else:
                repeatStr = convNum(len(reqs) * repeat)

            # list per-request response time #
            if SysMgr.outPath:
                SysMgr.printPipe(
                    (
                        "\n[Response Time] [Task: %s(%s)] [Elapsed: %.6f] "
                        "[NrReq: %s] [ReqCnt: %s/%s] [Delay: %s] "
                        "[TotalCPU: %s%%] [AvgCPU: %s%%]\n%s"
                    )
                    % (
                        SysMgr.comm,
                        SysMgr.pid,
                        totalElapsed,
                        convNum(len(reqs)),
                        convNum(idx + 1),
                        repeatStr,
                        delay,
                        tcpu,
                        acpu,
                        twoLine,
                    )
                )

                SysMgr.printPipe(
                    "{0:^50} | {1:^80}\n{2:1}".format(
                        "Request", "Response Times", oneLine
                    )
                )

                for ridx, value in stats["perReqTimeAll"].items():
                    interval = ", ".join(
                        list(map(lambda x: "%s/%s" % (x[0], x[1]), value))
                    )

                    SysMgr.printPipe(
                        "{0:>20} | {1:1}\n{2:1}".format(
                            ridx, interval, oneLine
                        )
                    )

            # summarize per-request response time #
            SysMgr.printPipe(
                (
                    "\n[Response Summary] [Task: %s(%s)] [Elapsed: %.6f] "
                    "[NrReq: %s] [ReqCnt: %s/%s] [Delay: %s] "
                    "[TotalCPU: %s%%] [AvgCPU: %s%%]\n%s"
                )
                % (
                    SysMgr.comm,
                    SysMgr.pid,
                    totalElapsed,
                    convNum(len(reqs)),
                    convNum(idx + 1),
                    repeatStr,
                    delay,
                    tcpu,
                    acpu,
                    twoLine,
                )
            )

            SysMgr.printPipe(
                (
                    "{0:^7} | {1:^7} | {2:^7} | {3:^10} | {4:^10} | "
                    "{5:^10} | {6:^7} | {7:1} \n{8:1}"
                ).format(
                    "Cnt",
                    "Elapsed",
                    "Avg",
                    "Min",
                    "Max",
                    "Std",
                    "Err",
                    "Request",
                    oneLine,
                )
            )

            for idx, value in stats["perReqTime"].items():
                cnt = len(value)
                totval = sum(value)
                avgval = totval / len(value)
                minval = min(value)
                maxval = max(value)
                stdval = UtilMgr.getStdev(value)

                # get error #
                if idx in stats["perReqErr"]:
                    errcnt = stats["perReqErr"][idx]
                    cnt += errcnt
                    err = convNum(errcnt)
                    if errcnt > 0:
                        err = UtilMgr.convColor(err, "RED", 7)
                else:
                    err = 0

                # get count #
                cnt = convNum(cnt)

                # apply alias #
                if idx in stats["name"]:
                    name = "(%s)%s" % (
                        stats["name"][idx],
                        idx.split("#", 1)[1],
                    )
                else:
                    name = idx

                SysMgr.printPipe(
                    (
                        "{0:>7} | {1:>7.3f} | {2:>7.3f} | {3:>10.6f} | "
                        "{4:>10.6f} | {5:>10.6f} | {6:>7} | {7:1}"
                    ).format(
                        cnt, totval, avgval, minval, maxval, stdval, err, name
                    )
                )

            # print only errors #
            for idx, value in stats["perReqErr"].items():
                if not idx in stats["perReqTime"]:
                    err = UtilMgr.convColor(value, "RED", 7)
                    SysMgr.printPipe(
                        (
                            "{0:>7} | {1:>7.3f} | {2:>7.3f} | {3:>10.6f} | "
                            "{4:>10.6f} | {5:>10.6f} | {6:>7} | {7:1}"
                        ).format(value, 0, 0, 0, 0, 0, err, idx)
                    )

            SysMgr.printPipe(oneLine)

        def _runCLIMode():
            def __printMenu():
                sys.stdout.write(
                    "\n<Command List>\n"
                    "- HISTORY\n"
                    "- PING\n"
                    "- REPEAT\n"
                    "- QUIT\n"
                    "\n"
                )

            def __printHistory(hlist):
                print("\n<History>")
                if hlist:
                    for idx, cmd in enumerate(hlist):
                        print(cmd)
                        print(
                            "[%0d] %s"
                            % (idx, UtilMgr.convColor(cmd, "UNDERLINE"))
                        )
                    print('input "! + index" to execute the above commands')
                else:
                    print("no history")

            def __getUserInput():
                __printMenu()
                sys.stdout.write("input command for request...\n=> ")
                sys.stdout.flush()

                return sys.stdin.readline()[:-1]

            def __doPing(uinput):
                pass

            def __convUserCmd(uinput):
                uinputUpper = uinput.upper()
                if uinputUpper == "H":
                    uinput = "history"
                elif uinputUpper == "P":
                    uinput = "ping"
                elif uinputUpper == "Q":
                    uinput = "quit"
                elif uinputUpper.startswith("R:"):
                    uinput = "repeat" + uinput[1:]

                return uinput

            def __setRepeat(uinput):
                try:
                    cmd = "repeat:"
                    count = UtilMgr.lstrip(uinput, [cmd, cmd.upper()])

                    # set repeat count #
                    SysMgr.repeatCount = long(count)
                    if SysMgr.repeatCount == 0:
                        SysMgr.repeatCount = sys.maxsize

                    SysMgr.printInfo(
                        "set repeat count to %s"
                        % UtilMgr.convNum(SysMgr.repeatCount)
                    )
                except:
                    SysMgr.printErr("failed to set repeat count to '%s'", True)

            # run mainloop for user interaction #
            hlist = []
            while 1:
                try:
                    isHistory = False

                    # get input #
                    uinput = __getUserInput()

                    # check input for history #
                    if uinput.startswith("!") and len(uinput) > 1:
                        try:
                            uinput = hlist[long(uinput[1:])]
                            isHistory = True
                        except:
                            SysMgr.printErr(
                                "wrong history index for '%s'" % uinput[1:]
                            )
                            continue

                    # convert command shortcut #
                    uinput = __convUserCmd(uinput)
                    uinputUpper = uinput.upper()

                    # handle local command #
                    if not uinput or uinput == "!" or uinputUpper == "HISTORY":
                        __printHistory(hlist)
                        continue
                    elif uinputUpper.startswith("PING"):
                        __doPing(uinput)
                        continue
                    elif uinputUpper == "QUIT":
                        break
                    elif uinputUpper.startswith("REPEAT"):
                        __setRepeat(uinput)
                        continue

                    # backup command #
                    if not isHistory and (not hlist or hlist[-1] != uinput):
                        hlist.append(uinput)

                    # request #
                    SysMgr.doRequest(uinput)
                except SystemExit:
                    return
                except:
                    SysMgr.printErr("failed to request URL", True)
                finally:
                    # reset signal and exit flag #
                    SysMgr.setSimpleSignal()

        # import package #
        requests = SysMgr.getPkg("requests")

        # add ssl variables for TLS 1.0 #
        try:
            urllib3 = requests.packages.urllib3
            urllib3.util.ssl_.DEFAULT_CIPHERS += ":DES-CBC3-SHA"
            urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
        except:
            pass

        # get requests #
        if reqstr:
            pass
        elif SysMgr.hasMainArg():
            reqstr = SysMgr.getMainArg()
        elif SysMgr.inputParam:
            reqstr = SysMgr.inputParam
        else:
            _runCLIMode()
            sys.exit(0)

        # split requests #
        reqs = reqstr.split("|")

        # get repeat count #
        if SysMgr.repeatCount > 1:
            repeat = SysMgr.repeatCount
            delay = SysMgr.intervalEnable / 1000.0
        elif SysMgr.intervalEnable > 0:
            repeat = SysMgr.intervalEnable
            delay = 0
        else:
            repeat = 1
            delay = 0

        # define cache list #
        cache = {}

        # set log for delay #
        if delay > 0:
            delayStr = " with %s second delay" % delay
        else:
            delayStr = ""

        # set log for processes #
        if SysMgr.utilProc > 1:
            procStr = " by %s processes" % SysMgr.utilProc
        else:
            procStr = ""

        # make repeat string #
        if repeat == sys.maxsize or repeat == SysMgr.maxSize:
            repeatStr = "INFINITE"
        else:
            repeatStr = UtilMgr.convNum(repeat)

        SysMgr.printInfo(
            "request %s times%s%s" % (repeatStr, delayStr, procStr)
        )

        start = time.time()

        try:
            # process #
            if SysMgr.utilProc > 1:
                if SysMgr.isLinux:
                    for idx in xrange(1, SysMgr.utilProc + 1):
                        # create a new worker #
                        pid = SysMgr.createProcess()
                        if pid == 0:
                            _task(reqs, repeat, delay, cache)

                            sys.exit(0)

                    # wait for childrenren #
                    SysMgr.waitChild()
                else:
                    SysMgr.spawnProcess(
                        _task, (reqs, repeat, delay, cache), SysMgr.utilProc
                    )
            else:
                _task(reqs, repeat, delay, cache)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to request", reason=True)
            sys.exit(-1)

        # print elapsed time #
        elapsed = time.time() - start
        SysMgr.printInfo("finished all requests for %.6f sec" % elapsed)

    @staticmethod
    def doExec():
        def _customxrange(start, end, step):
            r = start
            while r < end:
                yield r
                r += step

        def _exeCmd(cmd):
            # get subprocess object #
            subprocess = SysMgr.getPkg("subprocess")

            SysMgr.printInfo("executed '%s'\n" % cmd)

            # get environment variables #
            env = SysMgr.getEnvList()

            startTime = time.time()

            # redirect stdin to file #
            if "STDIN" in SysMgr.environList:
                path = SysMgr.environList["STDIN"][0]
                stdin = open(path, "rb")
            else:
                stdin = None

            # redirect stdout to file #
            if "STDOUT" in SysMgr.environList:
                path = SysMgr.environList["STDOUT"][0]
                stdout = open(path, "wb")
            else:
                stdout = None

            # redirect stderr to file #
            if "STDERR" in SysMgr.environList:
                path = SysMgr.environList["STDERR"][0]
                stderr = open(path, "wb")
            else:
                stderr = None

            # create process to communicate #
            procObj = subprocess.Popen(
                cmd,
                shell=True,
                bufsize=0,
                env=env,
                stdin=stdin,
                stdout=stdout,
                stderr=stderr,
            )

            # run mainloop #
            try:
                procObj.wait()
            except SystemExit:
                sys.exit(0)
            except:
                duration = time.time() - startTime

                SysMgr.printErr(
                    "failed to wait termination for '%s'" % cmd, True
                )

                sys.exit(-1)

            # kill subprocess group #
            SysMgr.killProcGroup(procObj)

            # get duration time #
            duration = time.time() - startTime

            SysMgr.printInfo(
                "terminated '%s' and elapsed %s sec" % (cmd, duration)
            )

        def _iterVarCmd(cmd, var):
            if not var:
                _exeCmd(cmd)
                return

            # pop a variable #
            conv = var.pop(0)
            item = conv.split(":")
            if len(item) == 4:
                # split variables #
                key, start, end, step = item

                # convert type #
                if "." in step:
                    step = float(step)
                    start = float(start)
                    end = float(end)
                else:
                    step = long(step)
                    start = long(start)
                    end = long(end)

                # loop in range #
                for num in _customxrange(start, end, step):
                    if type(num) is float:
                        num = round(num, 6)

                    tcmd = cmd.replace(key, str(num))

                    try:
                        _iterVarCmd(tcmd, list(var))
                    except SystemExit:
                        sys.exit(0)
                    except:
                        SysMgr.printErr("failed to execute '%s'" % tcmd, True)
                        sys.exit(-1)
            elif len(item) == 2:
                key = item[0]
                flist = UtilMgr.getFileList([item[1]], exceptDir=True)
                for item in flist:
                    try:
                        tcmd = cmd.replace(key, item)
                        _iterVarCmd(tcmd, list(var))
                    except SystemExit:
                        sys.exit(0)
                    except:
                        SysMgr.printErr("failed to execute '%s'" % tcmd, True)
                        sys.exit(-1)
            else:
                SysMgr.printErr("wrong variable '%s'" % conv)
                sys.exit(-1)

        # get command #
        if SysMgr.hasMainArg():
            cmd = SysMgr.getMainArg()
        elif SysMgr.inputParam:
            cmd = SysMgr.inputParam
        else:
            SysMgr.printErr("no input for command")
            sys.exit(-1)

        # convert command #
        try:
            confData = SysMgr.getConfigItem("threshold")
            cmd = confData["COMMAND"][cmd]
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # convert Guider path #
        if cmd.startswith("GUIDER "):
            exe = " ".join(SysMgr.getExeCmd(SysMgr.pid))
            cmd = UtilMgr.lstrip(cmd, "GUIDER ")
            cmd = "%s %s" % (exe, cmd)

        # convert variables #
        if SysMgr.customCmd:
            _iterVarCmd(cmd, SysMgr.customCmd)
        else:
            _exeCmd(cmd)

    @staticmethod
    def doGpuTest():
        pass

    @staticmethod
    def doDrawTimeline():
        # get output file name #
        if SysMgr.hasMainArg():
            inputList = SysMgr.getMainArgs()
        elif SysMgr.inputParam:
            inputList = SysMgr.inputParam.split(",")
            inputList = UtilMgr.cleanItem(inputList)
        else:
            SysMgr.printErr("no input for path")
            sys.exit(-1)

        # get config path #
        if SysMgr.getOption("C"):
            config = SysMgr.confFileName
        else:
            config = None

        # set custom interval #
        try:
            begin, end = SysMgr.environList["TRIM"][0].split(":")
            begin = begin.strip()
            begin = float(begin) if begin else 0
            end = end.strip()
            end = float(end) if end else 0
        except SystemExit:
            sys.exit(0)
        except:
            begin = end = 0

        # draw files #
        for inputPath in inputList:
            # set output path #
            outputPath = UtilMgr.getDrawOutputPath(inputPath, "timeline")

            # backup #
            SysMgr.backupFile(outputPath)

            # draw timeline #
            SysMgr.drawTimeline(
                inputPath=inputPath,
                outputPath=outputPath,
                configPath=config,
                begin=begin,
                end=end,
            )

    @staticmethod
    def doCpuTest():
        random = SysMgr.getPkg("random")

        def _cputask(idx, load):
            try:
                SysMgr.setDefaultSignal()
            except:
                pass

            # print profile #
            if SysMgr.isLinux:
                tid = SysMgr.syscall("gettid")
            else:
                tid = os.getpid()

            SysMgr.printWarn(
                "started %sth %s(%s)"
                % (UtilMgr.convNum(idx), SysMgr.comm, tid)
            )

            # run loop #
            while 1:
                if load == 0:
                    signal.pause()
                else:
                    before = time.time()
                    sorted([long(random.random()) for i in xrange(1 << 20)])
                    elapsed = time.time() - before
                    SysMgr.printWarn(
                        "%sth %s(%s) took %.6f seconds to finish one job"
                        % (UtilMgr.convNum(idx), SysMgr.comm, tid, elapsed)
                    )

        # get the number of task and load #
        try:
            if SysMgr.hasMainArg():
                value = SysMgr.getMainArgs(union=False, token=":")
            else:
                value = [100 * SysMgr.getNrCore()]

            # parse values #
            if len(value) > 2:
                raise Exception("too many arguments")
            elif len(value) == 2:
                totalLoad, nrTask = list(map(long, value))
                if nrTask == 0:
                    nrTask = 1
                load = totalLoad / nrTask
            else:
                totalLoad = long(value[0])
                nrTask = long(totalLoad / 100)
                modLoad = totalLoad % 100

                if modLoad > 0:
                    nrTask += 1

                load = long(totalLoad / nrTask)

            nrTask = long(nrTask)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                (
                    "wrong value for CPU load because %s, "
                    "input number in the format LOAD{:NRTASK}"
                )
                % SysMgr.getErrMsg()
            )
            sys.exit(-1)

        # check target type #
        if SysMgr.processEnable:
            if nrTask > 1:
                taskstr = "%s processes" % UtilMgr.convNum(nrTask)
            else:
                taskstr = "a process"
        else:
            if nrTask > 1:
                taskstr = "%s threads" % UtilMgr.convNum(nrTask)
            else:
                taskstr = "a thread"

        # run tasks #
        limitInfo = {}
        try:
            # process #
            if SysMgr.processEnable:
                for idx in xrange(1, nrTask + 1):
                    pid = SysMgr.createProcess()
                    if pid == 0:
                        _cputask(idx, load)
                    else:
                        limitInfo[pid] = load
            # thread #
            else:
                threadObj = SysMgr.getPkg("threading")
                pid = SysMgr.createProcess()
                if pid == 0:
                    for idx in xrange(1, nrTask):
                        tobj = threadObj.Thread(
                            target=_cputask, args=[idx, load]
                        )
                        tobj.daemon = True
                        tobj.start()
                    _cputask(nrTask, load)
                else:
                    limitInfo[pid] = load
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to create %s" % taskstr, True)
            sys.exit(-1)

        SysMgr.printInfo(
            (
                "created %s and limited them to use CPU a total of %d%% "
                "and %d%% respectively"
            )
            % (taskstr, totalLoad, load)
        )

        # set affinity #
        for pid in list(limitInfo):
            for item in SysMgr.affinityFilter:
                SysMgr.setAffinity(item[1], [pid])

        # set signal #
        try:
            # set alarm #
            signal.signal(signal.SIGALRM, SysMgr.onAlarm)
            signal.alarm(SysMgr.intervalEnable)

            # ignore SIGCHLD #
            signal.signal(signal.SIGCHLD, signal.SIG_DFL)
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # limit CPU usage of tasks #
        SysMgr.doLimitCpu(limitInfo, verb=False)

    @staticmethod
    def doMemTest():
        def _getMeminfo():
            # save mem info #
            memBuf = SysMgr.getMemInfo()
            if not memBuf:
                return ""

            memData = {}
            for line in memBuf:
                memList = line.split()
                memData[memList[0][:-1]] = long(memList[1])

            conv = UtilMgr.convSize2Unit
            memTotal = conv(memData["MemTotal"] << 10)
            memFree = conv(memData["MemFree"] << 10)
            memFreePer = (
                memData["MemFree"] / float(memData["MemTotal"])
            ) * 100

            try:
                memAvailKb = memData["MemAvailable"]
                memAvail = conv(memAvailKb << 10)
                memAvailPer = (memAvailKb / float(memData["MemTotal"])) * 100
                memAvailPer = "%.1f%%" % memAvailPer
            except:
                memAvail = memAvailPer = "-"

            memCache = conv(memData["Cached"] << 10)
            swapTotalKb = memData["SwapTotal"]
            swapTotal = conv(swapTotalKb << 10)
            swapFreeKb = memData["SwapFree"]
            swapFree = conv(swapFreeKb << 10)
            if swapTotal == "0":
                swapFreePer = 100.0
            else:
                swapFreePer = (swapFreeKb / float(swapTotalKb)) * 100

            memstr = (
                "\n[%9s] MemTotal: %s, MemFree: %s(%.1f%%), "
                "MemAvail: %s(%s), Cached: %s, SwapTotal: %s, "
                "SwapFree: %s(%.1f%%)"
            ) % (
                "TOTAL",
                memTotal,
                memFree,
                memFreePer,
                memAvail,
                memAvailPer,
                memCache,
                swapTotal,
                swapFree,
                swapFreePer,
            )

            return memstr

        def _getVminfo():
            # save mem info #
            vmBuf = SysMgr.getVmstat()
            if not vmBuf:
                return ""

            vmData = {}

            conv = UtilMgr.convSize2Unit
            for line in vmBuf:
                vmList = line.split()
                item = vmList[0]
                if (
                    item.startswith("pgscan_")
                    or item.startswith("pgstreal_")
                    or item.startswith("kswapd_")
                    or item.startswith("compact_")
                    or item.startswith("oom_")
                    or item.startswith("pswin")
                ):
                    vmData[item] = long(vmList[1])

            cnt = 1
            vmstr = "\n[%9s] " % "VMSTAT"
            for vm, item in sorted(vmData.items()):
                vmstr += "%s: %s, " % (vm, conv(item << 12))
                if cnt % 4 == 0 and cnt != len(vmData):
                    vmstr += "\n[%9s] " % "VMSTAT"
                cnt += 1

            return vmstr[:-2]

        def _getZoneinfo():
            # read zone buf #
            memBuf = SysMgr.readProcStat(
                SysMgr.zoneFd, "zoneinfo", SysMgr, "zoneFd"
            )
            if not memBuf:
                return ""

            memData = {}
            conv = UtilMgr.convSize2Unit

            zone = None
            for line in memBuf:
                zl = line.split()
                item = zl[0]
                if item == "Node":
                    zone = "%s-%s" % (zl[1][:-1], zl[3])
                    memData[zone] = {}
                elif item == "pages" and zl[1] == "free":
                    memData[zone]["free"] = long(zl[2])
                elif item in (
                    "min",
                    "low",
                    "high",
                    "spanned",
                    "present",
                    "managed",
                ):
                    memData[zone][item] = long(zl[1])
                elif item == "protection:":
                    values = []
                    for item in zl[1:]:
                        if item.startswith("("):
                            item = item[1:]
                        if item.endswith(",") or item.endswith(")"):
                            item = item[:-1]
                        values.append(item)

                    values = list(map(lambda x: conv(long(x) << 12), values))
                    memData[zone]["protection"] = values
                else:
                    continue

            # define stat list #
            STAT_LIST = [
                "free",
                "min",
                "low",
                "high",
                "managed",
                "present",
                "spanned",
                "protection",
            ]

            zonestr = "\n"
            for zone, items in sorted(memData.items()):
                zonestr += "[%9s] " % zone

                for name in STAT_LIST:
                    val = items[name]

                    if name == "protection":
                        zonestr = "%s%s: (%7s)" % (
                            zonestr,
                            "protection",
                            ", ".join(val),
                        )
                        zonestr = "%s\n" % zonestr
                    else:
                        zonestr = "%s%s:%7s, " % (
                            zonestr,
                            name,
                            conv(val << 12),
                        )

            return zonestr[:-2]

        def _getLMKinfo():
            # save LMK info #
            try:
                memBuf = None
                SysMgr.lmkFd.seek(0)
                memBuf = SysMgr.lmkFd.readline()
            except:
                try:
                    memPath = SysMgr.lmkPath
                    SysMgr.lmkFd = open(memPath, "r")
                    memBuf = SysMgr.lmkFd.readline()
                except:
                    SysMgr.printOpenWarn(memPath)

            if not memBuf:
                return ""

            # threshold list #
            threshold = [
                "FGAPP",
                "VISAPP",
                "SECSER",
                "HIDAPP",
                "CONPRO",
                "EMPAPP",
            ]

            stats = memBuf.split(",")
            if stats:
                stats = list(map(long, stats))

            lmkstr = "\n[%9s] " % "LMK"

            for idx, item in enumerate(stats):
                lmkstr = "%s%s: %s, " % (
                    lmkstr,
                    threshold[idx],
                    UtilMgr.convSize2Unit(item << 12),
                )

            return "%s" % lmkstr[:-2]

        def _allocMemory(size, wrPipe=None, ret=False):
            SysMgr.setDefaultSignal()

            # allocate memory #
            try:
                SysMgr.procBuffer = bytearray(size)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("failed to allocate memory", True)
                sys.exit(-1)

            if wrPipe:
                os.write(wrPipe, "1".encode())

            if ret:
                return

            SysMgr.waitEvent()

            sys.exit(0)

        def _printUsage(obj, pid, size, alloc=True):
            conv = UtilMgr.convSize2Unit

            # get system stat #
            try:
                memstr = _getMeminfo()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("failed to get memory stat", True)
                return

            # get vmstat #
            try:
                vmstr = _getVminfo()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("failed to get virtual memory stat", True)
                return

            # get zone stat #
            try:
                zonestr = _getZoneinfo()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("failed to get zone memory stat", True)
                return

            # get LMK stat #
            try:
                lmkstr = _getLMKinfo()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn("failed to get LMK stat", reason=True)

            # get process stat #
            pid = str(pid)
            procPath = "%s/%s" % (SysMgr.procPath, pid)
            obj.saveProcStat()
            procs = obj.procData
            prevProcs = obj.prevProcData
            if SysMgr.isRoot():
                obj.saveProcSmapsData(procPath, pid, mini=True)
                ret = obj.getMemDetails(pid, procs[pid]["maps"])
                statstr = "RSS: %s, PSS: %s, USS: %s" % (
                    conv(ret[1] << 10),
                    conv(ret[2] << 10),
                    conv(ret[3] << 10),
                )
            else:
                # save RSS stat #
                mlist = SysMgr.getMemStat(pid)
                if not mlist:
                    SysMgr.printErr("failed to get memory size of Guider")
                    sys.exit(-1)

                # get memory size #
                rssIdx = ConfigMgr.STATM_TYPE.index("RSS")
                statstr = "RSS: %s" % conv(long(mlist[rssIdx]) << 12)

            # get new task #
            newTasks = set(procs) - set(prevProcs)
            if newTasks:
                newstr = "\n[%9s]" % "NEW"
                for pid in sorted(newTasks):
                    comm = procs[pid]["stat"][obj.commIdx].strip("()")
                    rss = conv(long(procs[pid]["stat"][obj.rssIdx]) << 12)
                    newstr = "%s %s(%s)[%s], " % (newstr, comm, pid, rss)
                newstr = newstr[:-2]
            else:
                newstr = ""

            # get die task #
            dieTasks = set(prevProcs) - set(procs)
            if dieTasks:
                diestr = "\n[%9s]" % "DIE"
                for pid in sorted(dieTasks):
                    comm = prevProcs[pid]["stat"][obj.commIdx].strip("()")
                    rss = conv(long(prevProcs[pid]["stat"][obj.rssIdx]) << 12)
                    diestr = "%s %s(%s)[%s], " % (diestr, comm, pid, rss)
                diestr = diestr[:-2]
            else:
                diestr = ""

            if alloc:
                allocstr = "\n[%9s] SIZE: %s, %s" % (
                    "ALLOC",
                    conv(size, True),
                    statstr,
                )
            else:
                allocstr = "\n[%9s] %.3f" % ("TIME", SysMgr.updateUptime())

            SysMgr.printPipe(
                "%s%s%s%s%s%s%s"
                % (allocstr, memstr, vmstr, zonestr, lmkstr, newstr, diestr),
                pager=False,
            )

        # convert time #
        try:
            if SysMgr.hasMainArg():
                value = SysMgr.getMainArgs(token=":")
            else:
                value = ["100M"]

            # parse option #
            if len(value) == 3:
                size, interval, count = value
            elif len(value) == 2:
                size, interval = value
                count = 0
            elif len(value) == 1:
                size = value[0]
                interval = count = 0
            else:
                raise Exception("wrong arguments")

            # get interval #
            cont = False
            interval = long(interval)
            if interval:
                cont = True
                interval = UtilMgr.convUnit2Time(interval)
            elif SysMgr.getOption("i"):
                try:
                    interval = long(SysMgr.getOption("i"))
                except:
                    SysMgr.printErr("failed to get interval time", True)
                    sys.exit(-1)
            else:
                interval = 0

            count = long(count)

            # convert memory size #
            size = UtilMgr.convUnit2Size(size)
            if not size:
                raise Exception("wrong size")
        except SystemExit:
            sys.exit(0)
        except:
            errMsg = (
                "wrong value for memory load because %s, "
                "input number in the format SIZE{:INTERVAL:COUNT}"
            ) % SysMgr.getErrMsg()
            SysMgr.printErr(errMsg)
            sys.exit(-1)

        # set alarm #
        if SysMgr.getOption("R"):
            try:
                timeout = long(SysMgr.getOption("R"))
            except:
                SysMgr.printErr("failed to get timeout value", True)
                sys.exit(-1)

            signal.signal(signal.SIGALRM, SysMgr.onAlarm)
            signal.alarm(timeout)

        # create task object #
        obj = TaskAnalyzer(onlyInstance=True)
        obj.saveProcStat()
        pid = SysMgr.pid
        pidList = []

        if count == 0:
            count = sys.maxsize

        for _ in xrange(count):
            try:
                pid = SysMgr.createProcess()
            except SystemExit:
                pass
            except:
                SysMgr.printErr("failed to start process", True)
                sys.exit(-1)

            # child #
            if pid == 0:
                try:
                    _allocMemory(size)
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr("failed to alloc memory", True)
                    sys.exit(-1)
            # parent #
            elif pid > 0:
                pidList.append(pid)

                # print stats #
                try:
                    _printUsage(obj, pid, size)
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(
                        "failed to print memory stats", reason=True
                    )

                # no count #
                if count == sys.maxsize and interval == 0:
                    time.sleep(1)
                else:
                    time.sleep(interval)

                if count == sys.maxsize and not cont:
                    break
            # error #
            else:
                sys.exit(-1)

        # set default interval for print #
        if interval == 0:
            interval = 1

        # wait for childrenren #
        if pidList:
            while 1:
                try:
                    _printUsage(obj, pid, size, alloc=False)
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(
                        "failed to print memory stats", reason=True
                    )

                time.sleep(interval)

    @staticmethod
    def doPstree(targets, title=True, printFunc=None):
        if title:
            SysMgr.printLogo(big=True, onlyFile=True)

        obj = TaskAnalyzer(onlyInstance=True)

        if SysMgr.isLinux:
            obj.saveSystemStat()
        else:
            obj.saveSystemStatGen()

        TaskAnalyzer.printProcTree(
            obj.procData, title=title, printFunc=printFunc, targets=targets
        )

    @staticmethod
    def doCompress():
        SysMgr.printFd = None
        SysMgr.setStream()
        SysMgr.setDefaultSignal()

        # check input #
        if SysMgr.hasMainArg():
            args = SysMgr.getMainArgs()
        else:
            SysMgr.printErr("no path for compression")
            sys.exit(-1)

        # get file list #
        infileList = UtilMgr.getFileList(args, exceptDir=True)
        if not infileList:
            SysMgr.printErr("no file for the path")
            sys.exit(-1)

        # get compressor #
        compressor = SysMgr.getPkg("gzip")

        for infile in infileList:
            # check file #
            if not os.path.isfile(infile):
                SysMgr.printErr("wrong path '%s' for decompression" % infile)
                sys.exit(-1)

            # check output #
            outfile = SysMgr.outPath
            SysMgr.outPath = None
            if outfile:
                # check dir #
                if os.path.isdir(outfile):
                    outfile = os.path.join(outfile, infile + ".gz")
            else:
                outfile = "%s.gz" % infile

            # check final input and output path #
            if infile == outfile:
                SysMgr.printErr(
                    "both input and output are the same as '%s' " % infile
                )
                sys.exit(-1)

            # check exist file #
            if os.path.exists(outfile):
                SysMgr.backupFile(outfile)
                newline = False
            else:
                newline = True

            # 1MB chunk size #
            chunkSize = 1 << 20

            # open input file #
            infd = open(infile, "rb")

            # get total file size #
            wroteSize = 0
            fileSize = long(os.fstat(infd.fileno()).st_size)
            infileSizeStr = UtilMgr.convSize2Unit(fileSize)

            # open output file #
            outfd = compressor.open(outfile, "wb")
            os.chmod(outfile, 0o777)

            SysMgr.printInfo(
                "start compressing '%s' [%s] to '%s'"
                % (infile, infileSizeStr, outfile),
                prefix=newline,
            )

            while 1:
                chunk = infd.read(chunkSize)
                if not chunk:
                    outfd.flush()
                    break

                outfd.write(chunk)

                wroteSize += len(chunk)
                UtilMgr.printProgress(wroteSize, fileSize)

            if wroteSize:
                UtilMgr.deleteProgress()

            outfileSize = long(os.fstat(outfd.fileno()).st_size)
            outfileSizeStr = UtilMgr.convSize2Unit(outfileSize)

            SysMgr.printInfo(
                "finished compressing '%s' [%s] to '%s' [%s]"
                % (infile, infileSizeStr, outfile, outfileSizeStr),
                prefix=False,
            )

    @staticmethod
    def doDecompress():
        SysMgr.printFd = None
        SysMgr.setStream()
        SysMgr.setDefaultSignal()

        # check input #
        if SysMgr.hasMainArg():
            args = SysMgr.getMainArgs()
        else:
            SysMgr.printErr("no path for decompression")
            sys.exit(-1)

        # get file list #
        infileList = UtilMgr.getFileList(args, exceptDir=True)
        if not infileList:
            SysMgr.printErr("no file for the path")
            sys.exit(-1)

        # get compressor #
        compressor = SysMgr.getPkg("gzip")

        for infile in infileList:
            # check file #
            if not os.path.isfile(infile):
                SysMgr.printErr("wrong path '%s' for decompression" % infile)
                sys.exit(-1)

            # check output #
            outfile = SysMgr.outPath
            SysMgr.outPath = None
            if outfile:
                # check dir #
                if os.path.isdir(outfile):
                    outfile = os.path.join(outfile, infile.replace(".gz", ""))
            else:
                if infile.endswith(".gz"):
                    outfile = infile.replace(".gz", "")
                else:
                    outfile = infile + ".decomp"

            # check final input and output path #
            if infile == outfile:
                SysMgr.printErr(
                    "both input and output are the same as '%s' " % infile
                )
                sys.exit(-1)

            # check exist file #
            if os.path.exists(outfile):
                SysMgr.backupFile(outfile)
                newline = False
            else:
                newline = True

            # 1MB chunk size #
            chunkSize = 1 << 20

            # open input file #
            infd = compressor.open(infile, "rb")

            # get total file size #
            wroteSize = 0
            fileSize = long(os.fstat(infd.fileno()).st_size)
            infileSizeStr = UtilMgr.convSize2Unit(fileSize)

            # open output file #
            outfd = open(outfile, "wb")
            os.chmod(outfile, 0o777)

            SysMgr.printInfo(
                "start decompressing '%s' [%s] to '%s'"
                % (infile, infileSizeStr, outfile),
                prefix=newline,
            )

            while 1:
                chunk = infd.read(chunkSize)
                if not chunk:
                    outfd.flush()
                    break

                outfd.write(chunk)

                wroteSize += len(chunk)
                UtilMgr.printProgress(wroteSize, fileSize)

            if wroteSize:
                UtilMgr.deleteProgress()

            outfileSize = long(os.fstat(outfd.fileno()).st_size)
            outfileSizeStr = UtilMgr.convSize2Unit(outfileSize)

            SysMgr.printInfo(
                "finished decompressing '%s' [%s] to '%s' [%s]"
                % (infile, infileSizeStr, outfile, outfileSizeStr),
                prefix=False,
            )

    @staticmethod
    def doPrintSig(target=None):
        SysMgr.printLogo(big=True, onlyFile=True)

        # get pid list #
        pids = []
        if target:
            pids += SysMgr.getTids(target)
        elif SysMgr.hasMainArg():
            items = SysMgr.getMainArgs()
            for item in items:
                pids += SysMgr.getTids(item)
        else:
            for item in SysMgr.filterGroup:
                pids += SysMgr.getTids(item)

        # check pid #
        if not pids:
            SysMgr.printErr("no target thread")
            sys.exit(-1)

        # initialize task stats #
        tobj = TaskAnalyzer(onlyInstance=True)

        for pid in sorted(pids):
            proc = "%s(%s)" % (SysMgr.getComm(pid), pid)

            # get process info #
            path = "%s/%s" % (SysMgr.procPath, pid)
            tobj.saveProcData(path, pid)
            tobj.saveProcStatusData(path, pid)

            # print process name #
            if not SysMgr.jsonEnable:
                SysMgr.printPipe(
                    "\n[Signal Status Info] %s\n%s" % (proc, twoLine)
                )

            # set maximum signal length #
            printed = False
            if SysMgr.jsonEnable:
                sigDict = {}
            else:
                maxSigLen = max([len(sig) for sig in ConfigMgr.SIG_LIST])

            # get signal info #
            for name, val in tobj.procData[pid]["status"].items():
                if not name.startswith("Sig") or len(name) != 6:
                    continue

                sigList = []
                listLen = len(val) * 4 + 1
                for pos in xrange(1, listLen):
                    if (
                        UtilMgr.isBitEnabled(pos, val)
                        and len(ConfigMgr.SIG_LIST) > pos
                        and ConfigMgr.SIG_LIST[pos] != "NONE"
                    ):
                        sigList.append(ConfigMgr.SIG_LIST[pos])

                # check skip condition #
                if not sigList:
                    continue
                elif SysMgr.jsonEnable:
                    sigDict.setdefault(name, sigList)
                    continue

                # set variables for print #
                printed = True
                if SysMgr.ttyCols:
                    maxItemLine = long(SysMgr.ttyCols / maxSigLen) - 1
                else:
                    maxItemLine = sys.maxsize
                nameStr = "%s: " % name
                string = nameStr

                # build string for print #
                for idx, sig in enumerate(sigList):
                    if idx and idx % maxItemLine == 0:
                        string = "%s\n%s" % (string, " " * len(nameStr))
                    string = "{0:1}{1:{sz}}".format(
                        string,
                        "{0:{sz}}|".format(sig, sz=maxSigLen - 1),
                        sz=maxSigLen,
                    )

                # print string for signal list #
                SysMgr.printPipe(string)

            if SysMgr.jsonEnable:
                SysMgr.printPipe(
                    UtilMgr.convDict2Str(
                        sigDict, pretty=not SysMgr.streamEnable
                    )
                )
                return
            elif not printed:
                SysMgr.printPipe("\tNone\n")
            SysMgr.printPipe(oneLine)

    @staticmethod
    def doSystat(isProcess=True):
        SysMgr.printLogo(big=True, onlyFile=True)

        SysMgr.checkRootPerm()

        # enable default attributes #
        SysMgr.showAll = True
        SysMgr.memEnable = True
        SysMgr.cgroupEnable = True
        SysMgr.cmdlineEnable = True
        SysMgr.irqEnable = True
        SysMgr.perfEnable = True
        SysMgr.nsEnable = True
        SysMgr.ttyRows = sys.maxsize
        SysMgr.diskEnable = True
        SysMgr.blockEnable = True
        SysMgr.networkEnable = True
        SysMgr.delayEnable = True

        # initialize perf events #
        SysMgr.initSystemPerfEvents()

        # snapshot system info #
        SysMgr()
        obj = TaskAnalyzer(onlyInstance=True)
        obj.saveSystemStat()

        if SysMgr.intervalEnable:
            time.sleep(SysMgr.intervalEnable)
        else:
            time.sleep(1)

        # save system stat #
        obj.reinitStats()
        obj.saveSystemStat()

        # print stat #
        if SysMgr.jsonEnable:
            # process system stat #
            obj.printSystemUsage()

            # process task stat #
            obj.printTaskUsage()
        else:
            # process system stat #
            obj.printSystemStat()

        SysMgr.printTopStats()

    @staticmethod
    def mergeCommStat(statList, commIdx=None):
        if not commIdx:
            commIdx = ConfigMgr.STAT_ATTR.index("COMM")

        # merge comm parts that splited by space #
        if statList[commIdx][-1] != ")":
            idx = commIdx + 1
            while 1:
                tmpStr = str(statList[idx])
                statList[commIdx] = "%s %s" % (statList[commIdx], tmpStr)
                statList.pop(idx)
                if ")" in tmpStr:
                    break

        return statList

    @staticmethod
    def doLimitCpu(limitInfo, isProcess=False, verb=True):
        CLK_PRECISION = 100000
        MAX_BUCKET = CLK_PRECISION / 1000
        SLEEP_SEC = 1 / float(MAX_BUCKET)
        COMM_IDX = ConfigMgr.STAT_ATTR.index("COMM")
        UTIME_IDX = ConfigMgr.STAT_ATTR.index("UTIME")
        STIME_IDX = ConfigMgr.STAT_ATTR.index("STIME")
        NR_TARGET = len(limitInfo)

        elapsed = 0
        nowTime = None
        taskList = {}

        def _openStatFd(tid, isProcess):
            if not SysMgr.isLinux:
                try:
                    return SysMgr.getPkg("psutil").Process(long(tid))
                except SystemExit:
                    sys.exit(0)
                except:
                    return None

            # set stat file path #
            if isProcess:
                statPath = "%s/%s/stat" % (SysMgr.procPath, tid)
            else:
                statPath = "%s/%s/task/%s/stat" % (SysMgr.procPath, tid, tid)

            # return stat fd #
            try:
                return open(statPath, "r")
            except:
                return None

        def _getTaskStat(fd):
            if not SysMgr.isLinux:
                try:
                    stats = fd.cpu_times()
                    usage = stats[0] + stats[1]
                    return (fd.name(), usage * 100)
                except SystemExit:
                    sys.exit(0)
                except:
                    return None

            # read buffer #
            try:
                fd.seek(0)
                statBuf = fd.read()
            except SystemExit:
                sys.exit(0)
            except:
                return None

            # convert string to list #
            statList = statBuf.split()
            if len(statList) + 1 < len(ConfigMgr.STAT_ATTR):
                SysMgr.printWarn("failed to read stat for the task")
                return None

            # merge comm parts that splited by space #
            statList = SysMgr.mergeCommStat(statList, COMM_IDX)

            comm = statList[COMM_IDX].strip("()")
            cputime = long(statList[UTIME_IDX]) + long(statList[STIME_IDX])
            return (comm, cputime)

        # initialize task list #
        for task, per in limitInfo.items():
            taskList[task] = {
                "per": per,
                "nowTick": 0,
                "prevTick": 0,
                "ticks": 0,
                "running": True,
            }

            if isProcess:
                taskList[task]["group"] = SysMgr.getThreadList(task)
                if not taskList[task]["group"]:
                    SysMgr.printErr(
                        "failed to get thread list of '%s' process" % task
                    )
                    return

                taskList[task]["fd"] = _openStatFd(task, isProcess)
                if not taskList[task]["fd"]:
                    SysMgr.printErr("failed to get stats of %s thread" % task)
                    return
            else:
                taskList[task]["group"] = [int(task)]
                taskList[task]["fd"] = _openStatFd(task, isProcess)
                if not taskList[task]["fd"]:
                    SysMgr.printErr("failed to get stats of %s thread" % task)
                    return

        # set alarm #
        try:
            signal.signal(signal.SIGALRM, SysMgr.onAlarm)
            signal.alarm(SysMgr.intervalEnable)
        except SystemExit:
            sys.exit(0)
        except:
            pass

        try:
            while 1:
                # backup time #
                prevTime = nowTime

                # get current time #
                nowTime = time.time()

                # check task #
                if not taskList:
                    SysMgr.printErr("failed to find task to limit CPU usage")
                    return

                for tid in list(taskList):
                    val = taskList[tid]
                    val["prevTick"] = val["nowTick"]

                    # get current tick #
                    stat = _getTaskStat(val["fd"])
                    if not stat:
                        SysMgr.printErr(
                            "failed to get CPU time of %s thread" % tid
                        )
                        taskList.pop(tid, None)
                    else:
                        val["comm"], val["nowTick"] = stat

                if not prevTime:
                    continue

                for tid, val in taskList.items():
                    # get used tick for interval #
                    diffTick = val["nowTick"] - val["prevTick"]
                    val["ticks"] += diffTick

                # get interval time #
                diffTime = nowTime - prevTime
                elapsed += diffTime
                if elapsed >= 1:
                    elapsed = 0

                    for tid, val in taskList.items():
                        # update thread list in a process #
                        if isProcess:
                            taskList[tid]["group"] = SysMgr.getThreadList(tid)
                            if not taskList[tid]["group"]:
                                continue

                            tasktype = "process"
                        else:
                            tasktype = "thread"

                        if verb:
                            SysMgr.printInfo(
                                (
                                    "try to limit CPU usage for %s(%s) %s"
                                    " to %s%%, it used %s%%"
                                )
                                % (
                                    val["comm"],
                                    tid,
                                    tasktype,
                                    val["per"],
                                    val["ticks"],
                                )
                            )

                        val["ticks"] = 0
                    continue

                for tid, val in taskList.items():
                    limitTick = val["per"] * elapsed

                    # exceed limited tick #
                    if val["ticks"] > limitTick:
                        if val["running"]:
                            for tid in val["group"]:
                                try:
                                    if SysMgr.isLinux:
                                        os.kill(tid, signal.SIGSTOP)
                                    else:
                                        val["fd"].suspend()
                                except SystemExit:
                                    raise Exception("exit")
                                except:
                                    SysMgr.printSigError(tid, "SIGSTOP")
                            val["running"] = False
                    # continue #
                    else:
                        if not val["running"]:
                            val["running"] = True
                            for tid in val["group"]:
                                try:
                                    if SysMgr.isLinux:
                                        os.kill(tid, signal.SIGCONT)
                                    else:
                                        val["fd"].resume()
                                except SystemExit:
                                    raise Exception("exit")
                                except:
                                    SysMgr.printSigError(tid, "SIGCONT")

                time.sleep(SLEEP_SEC)
        except SystemExit:
            pass
        except:
            SysMgr.printWarn("failed to limit CPU for tasks", reason=True)
        finally:
            for task, val in taskList.items():
                for tid in val["group"]:
                    try:
                        if SysMgr.isLinux:
                            os.kill(tid, signal.SIGCONT)
                        else:
                            val["fd"].resume()
                    except SystemExit:
                        pass
                    except:
                        SysMgr.printSigError(tid, "SIGCONT")

    @staticmethod
    def terminateTasks(targetList, sig=ConfigMgr.SIGKILL, group=False):
        if group:
            kill = os.killpg
        else:
            kill = os.kill

        for pid in targetList:
            try:
                pid = long(pid)

                if SysMgr.isLinux:
                    kill(pid, sig)
                else:
                    SysMgr.getPkg("psutil").Process(pid).terminate()
            except:
                SysMgr.printSigError(pid, "SIGKILL")

    @staticmethod
    def convTaskList(
        procList,
        isThread=False,
        exceptMe=False,
        sibling=False,
        inc=False,
        cache=False,
    ):

        if not procList:
            return

        targetList = []

        # get pids #
        for pid in procList:
            taskList = SysMgr.getTids(
                pid, isThread, sibling, False, False, cache
            )
            targetList += taskList

        # remove redundant items #
        finalList = list(set(targetList))

        if exceptMe:
            try:
                finalList.remove(SysMgr.pid)
            except:
                pass

        return finalList

    @staticmethod
    def getSigNum(val):
        if val.isdigit():
            return long(val)

        val = val.upper()
        if val in ConfigMgr.SIG_LIST:
            return ConfigMgr.SIG_LIST.index(val)

        val = "SIG%s" % val
        if val in ConfigMgr.SIG_LIST:
            return ConfigMgr.SIG_LIST.index(val)

        return None

    @staticmethod
    def sendSignalArgs(argList, isThread=False):
        sig = signal.SIGQUIT
        SIG_LIST = ConfigMgr.SIG_LIST
        if not argList:
            return

        # get signal candidates #
        options = [item for item in argList if item.startswith("-")]

        isFound = False
        for val in options:
            try:
                if not val.startswith("-"):
                    continue

                if not isFound:
                    sig = SysMgr.getSigNum(val[1:])
                    if sig:
                        isFound = True

                del argList[argList.index(val)]
            except SystemExit:
                sys.exit(0)
            except:
                pass

        # check type #
        if not isFound:
            sig = signal.SIGINT

        # check signal #
        if sig is None:
            SysMgr.printErr("failed to recognize signal to be sent")
            return

        # convert target list #
        try:
            argList = UtilMgr.cleanItem(("".join(argList)).split(","))
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # convert items to pid #
        targets = SysMgr.convTaskList(
            argList, isThread=isThread, exceptMe=True
        )
        if targets:
            targetList = targets
        else:
            targetList = argList

        # send signal #
        SysMgr.sendSignalProcs(sig, targetList, isThread=isThread)

    @staticmethod
    def sendSignalProcs(
        nrSig, pidList=[], isThread=False, verb=True, exceptList=[]
    ):
        def _kill(pid, nrSig):
            if isThread:
                return SysMgr.syscall("tkill", pid, nrSig)
            else:
                return os.kill(pid, nrSig)

        SIG_LIST = ConfigMgr.SIG_LIST
        exceptList = list(map(long, exceptList))

        if isThread:
            taskType = "thread"
        else:
            taskType = "process"

        nrProc = 0
        isSent = False
        if pidList and type(pidList) is list:
            for pid in pidList:
                try:
                    pid = pid.strip()
                except:
                    pass

                if not pid:
                    continue

                # check pid type #
                try:
                    pid = long(pid)
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(
                        "failed to find '%s' as a %s" % (pid, taskType)
                    )
                    return

                # skip myself #
                if pid == SysMgr.pid or pid in exceptList:
                    continue

                isSent = True

                # send signal to a process #
                try:
                    # get comm #
                    comm = SysMgr.getComm(pid)

                    _kill(pid, nrSig)

                    if verb:
                        SysMgr.printInfo(
                            "sent %s to %s(%s) %s"
                            % (SIG_LIST[nrSig], comm, pid, taskType)
                        )
                except SystemExit:
                    sys.exit(0)
                except:
                    if nrSig in SIG_LIST:
                        signame = SIG_LIST[nrSig]
                    else:
                        signame = nrSig

                    SysMgr.printSigError(pid, signame, False)

            if isSent:
                return

        # get my comm #
        myComm = SysMgr.getComm(SysMgr.pid)
        if not myComm:
            SysMgr.printErr("failed to get my comm", True)
            sys.exit(-1)

        # get my cmdline #
        myCmdline = SysMgr.getCmdline(SysMgr.pid)
        if myCmdline:
            myCmdline = myCmdline.split()
        else:
            SysMgr.printErr("failed to get my cmdline", True)
            sys.exit(-1)

        # get pid list #
        myPid = str(SysMgr.pid)
        myPpid = str(os.getppid())
        pids = SysMgr.getPidList()

        # handle Guider processes #
        nrProc = 0
        for pid in pids:
            if not pid.isdigit() or pid in (myPid, myPpid):
                continue

            # check comm #
            comm = SysMgr.getComm(pid)
            if not comm or not comm.startswith(myComm):
                continue

            # check cmdline again #
            if myComm != __module__:
                cmdlineList = SysMgr.getCmdline(pid, True)
                if len(cmdlineList) > 2 and myCmdline[:2] != cmdlineList[:2]:
                    continue

            if nrSig == signal.SIGINT:
                waitStatus = False

                # check wait option in cmdline #
                try:
                    cmdList = SysMgr.getCmdline(pid, True)
                    for val in cmdList:
                        if val == "-W":
                            waitStatus = True
                except SystemExit:
                    sys.exit(0)
                except:
                    continue

                # send signal #
                try:
                    pid = long(pid)
                    if pid in exceptList:
                        continue

                    _kill(pid, nrSig)

                    if verb:
                        if SysMgr.checkMode("start") and waitStatus:
                            SysMgr.printInfo(
                                "started %s(%s) to profile" % (comm, pid)
                            )
                        else:
                            SysMgr.printInfo(
                                "sent %s to %s(%s) %s"
                                % (SIG_LIST[nrSig], comm, pid, taskType)
                            )
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printSigError(pid, SIG_LIST[nrSig])
            else:
                try:
                    _kill(long(pid), nrSig)

                    if verb:
                        SysMgr.printInfo(
                            "sent %s to %s(%s) %s"
                            % (SIG_LIST[nrSig], comm, pid, taskType)
                        )
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printSigError(pid, SIG_LIST[nrSig])

            nrProc += 1

        if nrProc == 0 and verb:
            SysMgr.printInfo("no running process in the background")

    @staticmethod
    def getThreadList(tid):
        taskPath = "%s/%s/task" % (SysMgr.procPath, tid)

        try:
            return list(map(long, os.listdir(taskPath)))
        except:
            return None

    @staticmethod
    def getDeadlineArgs(value):
        value = value.split("/")
        if len(value) == 3:
            return list(map(long, value))
        elif len(value) == 2:
            value.append(value[-1])
            return list(map(long, value))
        else:
            return [0, 0, 0]

    @staticmethod
    def applyPriority(value):
        if not value:
            SysMgr.printErr(
                (
                    "wrong value '%s' to apply new priority, "
                    "input POLICY:PRIORITY|TIME:TID|COMM in the format"
                )
                % value
            )
            sys.exit(-1)

        SysMgr.checkRootPerm()

        # check process based search option #
        if "PROCSEARCH" in SysMgr.environList:
            procSearch = True
        else:
            procSearch = False

        # parse sched group #
        schedGroup = value.split(",")
        schedGroup = UtilMgr.cleanItem(schedGroup)

        for item in schedGroup:
            lastIdx = 4
            schedSet = item.split(":")

            # I/O #
            try:
                # check I/O sched #
                ioclass = None
                if schedSet[0] in ConfigMgr.IOSCHED_CLASS:
                    # set class #
                    ioclass = ConfigMgr.IOSCHED_CLASS.index(schedSet[0])
                else:
                    nmClass = "IOPRIO_CLASS_%s" % schedSet[0].upper()
                    if nmClass in ConfigMgr.IOSCHED_CLASS:
                        ioclass = ConfigMgr.IOSCHED_CLASS.index(nmClass)

                # apply I/O sched #
                if ioclass:
                    # set who #
                    if len(schedSet) == 4:
                        if schedSet[1] in ConfigMgr.IOSCHED_TARGET:
                            who = ConfigMgr.IOSCHED_TARGET.index(schedSet[1])
                        else:
                            nmWho = "IOPRIO_WHO_%s" % schedSet[1].upper()
                            who = ConfigMgr.IOSCHED_TARGET.index(nmWho)
                        pri = long(schedSet[2])
                        task = schedSet[3]
                    else:
                        who = 1
                        pri = long(schedSet[1])
                        task = schedSet[2]

                    # get thread list #
                    sibling = SysMgr.groupProcEnable
                    if task == "0":
                        targetList = [SysMgr.pid]
                        SysMgr.ioprio = pri
                    elif procSearch:
                        targetList = []
                        pidList = SysMgr.getTids(task, isThread=False)
                        if sibling:
                            for pid in pidList:
                                siblingList = SysMgr.getThreadList(pid)
                                if siblingList:
                                    targetList += siblingList
                        else:
                            targetList = pidList
                    else:
                        targetList = SysMgr.getTids(task, sibling=sibling)

                    # convert thread list #
                    targetList = list(map(long, list(set(targetList))))
                    if not targetList:
                        SysMgr.printWarn("no thread related to '%s'" % task)

                    # change the I/O scheduling priority for tasks #
                    for task in sorted(targetList):
                        SysMgr.setIoPriority(task, ioclass, pri, who)

                    continue
            except SystemExit:
                sys.exit(0)
            except:
                err = map(str, sys.exc_info()[1].args)
                SysMgr.printErr(
                    (
                        "wrong value '%s' to apply new priority because %s, "
                        "input in the format CLASS:WHO:PRI:TID|COMM"
                    )
                    % (item, " ".join(list(err)))
                )
                sys.exit(-1)

            # CPU #
            try:
                # policy and priority #
                try:
                    pri = long(schedSet[0])
                    policy = "C"

                    # change myself #
                    if len(schedSet) == 1:
                        task = SysMgr.pid
                        SysMgr.prio = pri
                    # change others #
                    else:
                        task = schedSet[1]

                    lastIdx = 3
                except SystemExit:
                    sys.exit(0)
                except:
                    policy = schedSet[0].upper()
                    ConfigMgr.SCHED_POLICY.index(policy)

                    pri = schedSet[1]
                    if UtilMgr.isNumber(pri):
                        pri = long(pri)

                    # change myself #
                    if len(schedSet) == 2:
                        task = SysMgr.pid
                        SysMgr.prio = pri
                    # change others #
                    else:
                        task = schedSet[2]

                # get thread list #
                sibling = SysMgr.groupProcEnable
                if procSearch:
                    targetList = []
                    pidList = SysMgr.getTids(task, isThread=False)
                    if sibling:
                        for pid in pidList:
                            siblingList = SysMgr.getThreadList(pid)
                            if siblingList:
                                targetList += siblingList
                    else:
                        targetList = pidList
                else:
                    targetList = SysMgr.getTids(task, sibling=sibling)

                # convert thread list #
                targetList = list(map(long, list(set(targetList))))
                if not targetList:
                    SysMgr.printWarn("no thread related to '%s'" % task)

                # change the CPU scheduling priority for tasks #
                for task in sorted(targetList):
                    if schedSet[0].upper() == "D":
                        # parse deadline arguments #
                        runtime, deadline, period = SysMgr.getDeadlineArgs(
                            schedSet[1]
                        )

                        # set deadline sched #
                        SysMgr.setDeadlinePriority(
                            task, runtime, deadline, period
                        )
                    else:
                        # set other sched #
                        SysMgr.setPriority(task, policy, pri)

                # change others continually #
                if len(schedSet) == lastIdx:
                    if schedSet[lastIdx - 1] != "CONT":
                        raise Exception("wrong last value")

                    # add sched item to list #
                    SysMgr.schedFilter.append([policy, pri, task])
            except SystemExit:
                sys.exit(0)
            except:
                err = map(str, sys.exc_info()[1].args)
                SysMgr.printErr(
                    (
                        "wrong value '%s' to apply new priority because %s, "
                        "input in the format POLICY:PRIORITY|TIME:TID|COMM"
                    )
                    % (item, " ".join(list(err)))
                )
                sys.exit(-1)

    @staticmethod
    def setDeadlinePriority(pid, runtime, deadline, period):
        if not SysMgr.isLinux:
            return

        # get comm #
        comm = SysMgr.getComm(pid)

        # check kernel version #
        try:
            ver = SysMgr.getKernelVersion().split(".")[0:2]
            ver = float(".".join(ver))
            # check whether kernel version is higher than 3.14 #
            if ver < 3.14:
                SysMgr.printErr(
                    (
                        "failed to set the CPU scheduling priority for %s(%s) "
                        "because kernel version %s is lesser than 3.14"
                    )
                    % (comm, pid, UtilMgr.convFloat2Str(ver))
                )
                return -1
        except SystemExit:
            sys.exit(0)
        except:
            err = sys.exc_info()[1]
            SysMgr.printWarn(
                (
                    "failed to check kernel version because %s "
                    "to set deadline priority"
                )
                % err.args[0],
                True,
            )
            return -1

        # load libc #
        SysMgr.loadLibcObj(exit=True)

        # define struct sched_attr #
        class struct_sched_attr(Structure):
            pass

        struct_sched_attr._slots_ = [
            "size",
            "sched_policy",
            "sched_flags",
            "sched_nice",
            "sched_priority",
            "sched_runtime",
            "sched_deadline",
            "sched_period",
        ]

        struct_sched_attr._fields_ = [
            ("size", c_uint32),
            ("sched_policy", c_uint32),
            ("sched_flags", c_uint64),
            ("sched_nice", c_int32),
            ("sched_priority", c_uint32),
            ("sched_runtime", c_uint64),
            ("sched_deadline", c_uint64),
            ("sched_period", c_uint64),
        ]

        # set parameters #
        sched_attr = struct_sched_attr()
        sched_attr.size = c_uint32(sizeof(sched_attr))
        sched_attr.sched_flags = c_uint64(0)
        sched_attr.sched_nice = c_int32(0)
        sched_attr.sched_priority = c_uint32(0)
        sched_attr.sched_policy = c_uint32(ConfigMgr.SCHED_POLICY.index("D"))

        # set runtime(ns) #
        sched_attr.sched_runtime = c_uint64(runtime)

        # check deadline and period #
        if deadline == period == 0:
            SysMgr.printErr(
                (
                    "failed to set the CPU scheduling priority for %s(%s) "
                    "to runtime(ns)/deadline(ns)/period(ns)[D]"
                )
                % (comm, pid)
            )
            return -1
        elif deadline == 0:
            deadline = period
        elif period == 0:
            period = deadline

        # set period(ns) #
        sched_attr.sched_deadline = c_uint64(deadline)
        sched_attr.sched_period = c_uint64(period)

        # call sched_setattr() to set deadline sched #
        ret = SysMgr.syscall("sys_sched_setattr", pid, pointer(sched_attr), 0)

        # check return value #
        if ret == 0:
            SysMgr.printInfo(
                (
                    "changed the CPU scheduling priority for %s(%s) to "
                    "runtime(%d)/deadline(%d)/period(%d)[D]"
                )
                % (comm, pid, runtime, deadline, period)
            )
        else:
            SysMgr.printErr(
                (
                    "failed to set the CPU scheduling priority for %s(%s) to "
                    "runtime(%d)/deadline(%d)/period(%d)[D]"
                )
                % (comm, pid, runtime, deadline, period)
            )

        return ret

    @staticmethod
    def getEnv(pid, retdict=False):
        path = "%s/%s/environ" % (SysMgr.procPath, pid)

        # open the environ file #
        try:
            with open(path, "r") as fd:
                data = fd.readlines()
                if not data:
                    comm = SysMgr.getComm(pid, True)
                    SysMgr.printWarn(
                        "failed to read environment variables for %s(%s)"
                        % (comm, pid)
                    )
                    return
                elist = data[0].split("\x00")[:-1]
        except SystemExit:
            sys.exit(0)
        except:
            comm = SysMgr.getComm(pid, True)
            SysMgr.printWarn(
                "failed to get environment variables of %s(%s)" % (comm, pid),
                True,
            )
            elist = []

        # convert list to dictionary #
        if retdict:
            dlist = {}
            for item in elist:
                var = item.split("=", 1)
                name = var[0]
                if len(var) == 1:
                    val = ""
                else:
                    val = var[1]
                dlist[name] = val
            return dlist
        else:
            return elist

    @staticmethod
    def setIoPriority(pid=0, ioclass=2, pri=0, who=1, verb=True):
        if not SysMgr.isLinux:
            return

        # define attributes #
        IOPRIO_CLASS_SHIFT = 13

        nmWho = nmClass = None

        try:
            # get pri #
            pri = long(pri)

            # set pid #
            pid = long(pid)
            if pid == 0:
                pid = os.getpid()

            # set comm #
            comm = SysMgr.getComm(pid)

            # set group (default: IOPRIO_WHO_PROCESS) #
            if not UtilMgr.isNumber(who):
                who = ConfigMgr.IOSCHED_TARGET.index(who)
            nmWho = ConfigMgr.IOSCHED_TARGET[who]

            # set I/O class (default: IOPRIO_CLASS_BE) #
            if not UtilMgr.isNumber(ioclass):
                ioclass = ConfigMgr.IOSCHED_CLASS.index(ioclass)
            nmClass = ConfigMgr.IOSCHED_CLASS[ioclass]

            # set priority value #
            iopri = ((ioclass) << IOPRIO_CLASS_SHIFT) | pri

            # call syscall #
            ret = SysMgr.syscall(
                "ioprio_set", c_int(who), c_int(pid), c_int(iopri)
            )
            if ret < 0:
                raise Exception("error return")

            if verb:
                SysMgr.printInfo(
                    (
                        "changed the I/O scheduling priority "
                        "for %s(%s) to %s(%s)[%s]"
                    )
                    % (comm, pid, nmClass, pri, nmWho)
                )
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                (
                    "failed to set the I/O schedling priority "
                    "for %s(%s) to %s(%s)[%s]"
                )
                % (comm, pid, ioclass, pri, nmWho),
                True,
            )
            sys.exit(-1)

    @staticmethod
    def setPriority(
        pid, policy, pri, runtime=0, deadline=0, period=0, verb=True
    ):
        if not SysMgr.isLinux:
            return

        try:
            # get args #
            pri = long(pri)
            comm = SysMgr.getComm(pid)
            upolicy = policy.upper()

            # load libc #
            if not SysMgr.loadLibcObj():
                raise Exception("no libc")

            argPolicy = ConfigMgr.SCHED_POLICY.index(upolicy)
            if not SysMgr.guiderObj:
                argPolicy = c_int(argPolicy)

            # set default priority #
            if upolicy in ("I", "C", "B"):
                argPriority = 0
            else:
                argPriority = pri

            # prepare for libc call #
            if not SysMgr.guiderObj:
                argPriority = c_int(argPriority)

            # define object #
            if not SysMgr.guiderObj:
                funcObj = SysMgr.libcObj
            else:
                funcObj = SysMgr.guiderObj

            # define sched_setscheduler function #
            if not hasattr(funcObj, "sched_setscheduler"):
                raise Exception("no sched_setscheduler")
            func = funcObj.sched_setscheduler

            # call sched_setscheduler function #
            ret = SysMgr.libcObj.sched_setscheduler(
                pid, argPolicy, byref(argPriority)
            )
            if ret != 0:
                policy = upolicy
                emsg = SysMgr.getErrReason()
                raise Exception(emsg)

            # set nice value #
            if upolicy == "C" or upolicy == "B":
                # check setpriority function #
                if not hasattr(funcObj, "setpriority"):
                    raise Exception("no setpriority")

                # call setpriority function #
                ret = funcObj.setpriority(0, pid, c_int(pri))
                if ret != 0:
                    policy = upolicy
                    emsg = SysMgr.getErrReason()
                    raise Exception(emsg)

            # print result #
            if verb:
                SysMgr.printInfo(
                    (
                        "changed the CPU scheduling priority "
                        "for %s(%s) to %d[%s]"
                    )
                    % (comm, pid, pri, upolicy)
                )
        except SystemExit:
            sys.exit(0)
        except:
            err = (
                "failed to set the CPU scheduling priority "
                "for %s(%s) to %s[%s]"
            ) % (comm, pid, pri, upolicy)
            SysMgr.printWarn(err, always=True, reason=True)

    @staticmethod
    def setTTYAuto(setRows=True, setCols=True, verb=True):
        if not SysMgr.isLinux and not SysMgr.isDarwin:
            return

        # update current terminal size #
        SysMgr.getTty()

        # decide terminal size #
        if setRows and SysMgr.ttyRows < 24:
            SysMgr.ttyRows = 24
        if setCols and SysMgr.ttyCols <= len(oneLine):
            SysMgr.ttyCols = len(oneLine) + 1

        # set terminal size #
        SysMgr.setTTY(SysMgr.ttyRows, SysMgr.ttyCols, verb)

        # update current terminal size #
        SysMgr.getTty()

    @staticmethod
    def disableBuffer(fd=None):
        if not SysMgr.isLinux:
            return

        if not fd:
            fd = sys.stdin.fileno()

        try:
            termios = SysMgr.getPkg("termios", False)
            attr = termios.tcgetattr(fd)
            attr[3] = attr[3] & ~termios.ECHO
            termios.tcsetattr(fd, termios.TCSANOW, attr)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to remove buffer for fd %s" % fd, reason=True
            )

    @staticmethod
    def hasStty():
        if SysMgr.sttyEnable:
            return True
        elif SysMgr.sttyEnable is False:
            return False

        if UtilMgr.which("stty"):
            SysMgr.sttyEnable = True
        else:
            SysMgr.sttyEnable = False

        return SysMgr.sttyEnable

    @staticmethod
    def saveTTY():
        if not SysMgr.isLinux:
            return
        elif not SysMgr.hasStty():
            return

        # read current setting #
        try:
            subprocess = SysMgr.getPkg("subprocess", False)
            pd = subprocess.Popen(["stty", "-g"], stdout=subprocess.PIPE)
            SysMgr.ttyData = pd.stdout.read().strip()
        except SystemExit:
            sys.exit(0)
        except:
            conf = False
            SysMgr.printWarn("failed to get terminal info", reason=True)

    @staticmethod
    def resetTTY():
        if not SysMgr.isLinux:
            return
        elif not SysMgr.hasStty():
            return
        elif not SysMgr.ttyData:
            return

        # reset terminal #
        try:
            SysMgr.getPkg("subprocess").Popen(
                ["stty", "sane"],
                stdout=open(os.devnull, "wb"),
                stderr=open(os.devnull, "wb"),
            )
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # restore terminal #
        try:
            SysMgr.getPkg("subprocess").Popen(
                ["stty", SysMgr.ttyData],
                stdout=open(os.devnull, "wb"),
                stderr=open(os.devnull, "wb"),
            )
        except SystemExit:
            sys.exit(0)
        except:
            pass

    @staticmethod
    def setTTY(rows, cols, verb=True):
        if (
            not SysMgr.isLinux and not SysMgr.isDarwin
        ) or SysMgr.parentPid > 0:
            return

        # set terminal size by ioctl #
        try:
            if not SysMgr.termSetId:
                termios = SysMgr.getPkg("termios", False)
                SysMgr.termSetId = getattr(termios, "TIOCSWINSZ", -2146929561)

            # get fcntl object #
            fcntlObj = SysMgr.getPkg("fcntl", False)

            # set terminal width size #
            fcntlObj.ioctl(
                sys.stdout.fileno(),
                SysMgr.termSetId,
                struct.pack("HHHH", rows, cols, 0, 0),
            )

            # update current terminal size #
            SysMgr.getTty()

            if not verb:
                return

            SysMgr.printInfo(
                "set terminal size [ %sx%s ]"
                % (SysMgr.ttyRows, SysMgr.ttyCols)
            )

            return
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # set terminal size by command #
        try:
            if not SysMgr.hasStty():
                return

            os.system("stty rows %d 2> %s" % (long(rows), SysMgr.nullPath))
            os.system("stty cols %d 2> %s" % (long(cols), SysMgr.nullPath))
            SysMgr.ttyRows = rows
            SysMgr.ttyCols = cols
        except SystemExit:
            sys.exit(0)
        except:
            return

    @staticmethod
    def getTty(update=False):
        if (
            not SysMgr.isLinux and not SysMgr.isDarwin
        ) or SysMgr.parentPid > 0:
            return

        if update and not SysMgr.termGetId:
            return

        # update tty info by ioctl #
        try:
            if not SysMgr.termGetId:
                termios = SysMgr.getPkg("termios", False)
                SysMgr.termGetId = termios.TIOCGWINSZ

            # get fcntl object #
            fcntlObj = SysMgr.getPkg("fcntl", False)

            SysMgr.ttyRows, SysMgr.ttyCols = struct.unpack(
                "hh",
                fcntlObj.ioctl(sys.stdout.fileno(), SysMgr.termGetId, "1234"),
            )

            # update encoding option #
            if SysMgr.encodeEnable and SysMgr.ttyCols < SysMgr.lineLength:
                SysMgr.encodeEnable = False

            return
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # update tty info by stty #
        try:
            if not SysMgr.hasStty():
                raise Exception("no stty")

            subprocess = SysMgr.getPkg("subprocess", False)
            pd = subprocess.Popen(["stty", "size"], stdout=subprocess.PIPE)
            SysMgr.ttyRows, SysMgr.ttyCols = list(
                map(long, pd.stdout.readline().split())
            )
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("failed to get terminal info", reason=True)

    def saveSystemInfo(self):
        # update uptime #
        SysMgr.updateUptime()

        # cmdline #
        try:
            self.cmdlineData = SysMgr.procReadline("cmdline")[0:-1]
        except:
            SysMgr.printOpenWarn("cmdline")

        # load #
        try:
            self.loadData = SysMgr.procReadline("loadavg")
        except:
            SysMgr.printWarn("failed to get load", reason=True)

        self.loadData = self.loadData.split()
        """
        loadData[0] = 1min usage,
        [1] = 5min usage,
        [2] = 15min usage,
        [3] = running/total thread,
        [4] = lastPid
        """

        # maximum threads #
        self.nrMaxThread = SysMgr.getMaxThread()

        # rtc #
        try:
            timeInfo = SysMgr.procReadlines("driver/rtc")

            for val in timeInfo:
                timeEntity = val.split()

                if timeEntity[0] == "rtc_time":
                    self.systemInfo["time"] = timeEntity[2]
                elif timeEntity[0] == "rtc_date":
                    self.systemInfo["date"] = timeEntity[2]
        except:
            pass

    @staticmethod
    def saveSysStats():
        if not SysMgr.sysInstance:
            SysMgr()

        if SysMgr.sysInstance:
            SysMgr.sysInstance.saveSysStat()

    def saveSysStat(self, initialized=True):
        if not SysMgr.isLinux:
            return

        # update time #
        SysMgr.updateUptime()

        # save resource usage #
        self.updateMemInfo()
        self.updateStorageInfo(isGeneral=True)
        self.updateNetworkInfo()
        self.updateIPCInfo()
        self.saveMacAddr()

        # save system info #
        self.saveUnameInfo()
        self.saveUserInfo()
        self.saveOpenFileInfo()
        self.saveLimitInfo()

        # save system info #
        if initialized:
            # process info #
            if SysMgr.isRecordMode():
                self.saveProcTreeComm()

            # resource info #
            self.saveSystemInfo()
            self.saveCpuInfo()
            self.saveCpuCacheInfo()

            # block device info #
            self.saveBlockInfo()

            # os specific info #
            self.saveWebOSInfo()
            self.saveLinuxInfo()

            # print resource info to temporary buffer #
            self.printResourceInfo()

    def saveCommCache(self):
        try:
            path = "%s/../saved_cmdlines" % SysMgr.mountPath
            with open(path, "r") as fd:
                commList = fd.readlines()
                for item in commList:
                    pid, comm = item.split(" ", 1)
                    if not pid in SysMgr.commCache:
                        SysMgr.commCache[pid] = comm.rstrip()
        except SystemExit:
            sys.exit(0)
        except:
            pass

    def saveProcTreeComm(self):
        # read comm cache #
        self.saveCommCache()

        # read proc tree #
        procTree = SysMgr.getProcTree()
        self.procData = "!!!!!"
        for tid, pid in procTree.items():
            self.procData += "%s#%s," % (tid, pid)

        # add comm cache #
        self.procData += "!!!!!"
        self.procData += str(SysMgr.commCache)

    def saveLinuxInfo(self):
        OSFile = "/etc/os-release"

        try:
            with open(OSFile, "r") as osf:
                self.osData = osf.readlines()
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenWarn(OSFile)

    def saveWebOSInfo(self):
        OSFile = "/var/run/nyx/os_info.json"
        devFile = "/var/run/nyx/device_info.json"
        osf = devf = None

        try:
            osf = open(OSFile, "r")
        except:
            pass

        try:
            devf = open(devFile, "r")
        except:
            pass

        # check webOS #
        if not osf and not devf:
            return False

        try:
            self.osData = osf.readlines()
            osf.close()
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenWarn(OSFile)

        try:
            self.devData = devf.readlines()
            devf.close()
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenWarn(devFile)

    def saveCpuInfo(self):
        try:
            self.cpuData = SysMgr.procReadlines("cpuinfo")
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("failed to save CPU info", reason=True)

    def saveCpuCacheInfo(self, data=False):
        cpuPath = "/sys/devices/system/cpu"

        if data:
            cpuCacheList = self.cpuCacheData
        else:
            cpuCacheList = self.cpuCacheInfo

        try:
            corelist = os.listdir(cpuPath)

            for core in corelist:
                cachePath = "/sys/devices/system/cpu/%s/cache" % core

                if data:
                    core = core.lstrip("cpu")

                cpuCacheList[core] = ""

                try:
                    typelist = os.listdir(cachePath)

                    for index in sorted(typelist):
                        if not index.startswith("index"):
                            continue

                        level = "?"
                        path = "%s/%s/level" % (cachePath, index)
                        with open(path, "r") as fd:
                            level = fd.readline()

                        type = "?"
                        path = "%s/%s/type" % (cachePath, index)
                        with open(path, "r") as fd:
                            type = fd.readline()

                        size = "?"
                        path = "%s/%s/size" % (cachePath, index)
                        with open(path, "r") as fd:
                            size = fd.readline()

                        if data:
                            size = UtilMgr.convUnit2Size(size[:-1])
                            size = UtilMgr.convSize2Unit(size, isInt=True)
                            if cpuCacheList[core]:
                                cpuCacheList[core] += "/%s" % size
                            else:
                                cpuCacheList[core] = size
                        else:
                            cpuCacheList[core] = "%sL%s(%s)=%s   " % (
                                cpuCacheList[core],
                                level[:-1],
                                type[:-1],
                                size[:-1],
                            )
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

                if not cpuCacheList[core]:
                    del cpuCacheList[core]
        except SystemExit:
            sys.exit(0)
        except:
            pass

    def saveDevInfo(self):
        try:
            target = None
            devData = SysMgr.procReadlines("devices")

            for line in devData:
                if line.startswith("Character"):
                    target = self.devInfo["char"] = {}
                elif line.startswith("Block"):
                    target = self.devInfo["block"] = {}

                item = line.split()

                if len(item) != 2:
                    continue

                try:
                    num = long(item[0])
                except:
                    continue

                try:
                    target[num].append(item[1])
                except:
                    target[num] = [item[1]]
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("failed to save deice info", reason=True)

    def saveBlockInfo(self):
        try:
            blockDir = "/sys/block"

            for dirnames in os.walk(blockDir):
                for dev in dirnames[1]:
                    # I/O scheduler #
                    schedPath = os.path.join(blockDir, dev, "queue/scheduler")
                    schedList = SysMgr.readFile(schedPath).split()
                    sched = None
                    for item in schedList:
                        if item.startswith("["):
                            sched = item.strip("[]")
                            break

                    # readahead size in KB #
                    raPath = os.path.join(blockDir, dev, "queue/read_ahead_kb")
                    ra = SysMgr.readFile(raPath)
                    if ra:
                        ra = UtilMgr.convSize2Unit(long(ra) << 10)

                    # physical block #
                    sizePath = os.path.join(
                        blockDir, dev, "queue/physical_block_size"
                    )
                    size = SysMgr.readFile(sizePath)
                    if size:
                        size = long(size)

                    # write cache #
                    wrPath = os.path.join(blockDir, dev, "queue/write_cache")
                    wr = SysMgr.readFile(wrPath)
                    if wr:
                        wr = wr.split()
                        if len(wr) == 2:
                            wr = wr[1]

                    # min size for random I/O #
                    minSizePath = os.path.join(
                        blockDir, dev, "queue/minimum_io_size"
                    )
                    minSize = SysMgr.readFile(minSizePath)

                    # optimal size for streaming I/O #
                    optSizePath = os.path.join(
                        blockDir, dev, "queue/optimal_io_size"
                    )
                    optSize = SysMgr.readFile(optSizePath)

                    # rq_affinity #
                    afntPath = os.path.join(blockDir, dev, "queue/rq_affinity")
                    afnt = SysMgr.readFile(afntPath)

                    # io_poll #
                    pollPath = os.path.join(blockDir, dev, "queue/io_poll")
                    poll = SysMgr.readFile(pollPath)

                    # save info #
                    self.blockData[dev] = {
                        "size": size,
                        "sched": sched,
                        "schedList": schedList,
                        "wrCache": wr,
                        "readahead": ra,
                        "minSize": minSize,
                        "optSize": optSize,
                        "affinity": afnt,
                        "poll": poll,
                    }
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("failed to block deice info", reason=True)

    def saveStorageInfo(self, isGeneral):
        blockDir = "/sys/class/block"
        partFile = "%s/partitions" % SysMgr.procPath

        # update disk data #
        SysMgr.updateDiskStats()
        self.updateNodeInfo()

        # update only a last diskstats if there is a first diskstats exist #
        if not "prev" in self.diskData:
            self.diskData["prev"] = SysMgr.diskStats
            self.updateDiskInfo("prev", SysMgr.diskStats)
        else:
            self.diskData["next"] = SysMgr.diskStats
            self.updateDiskInfo("next", SysMgr.diskStats)

        # update mount data #
        newMountData = SysMgr.getMountData()
        if self.mountData == newMountData:
            self.mountUpdated = False
        else:
            self.mountUpdated = True
            self.mountData = newMountData

        # check data type #
        if not isGeneral:
            return

        # save partition range #
        for dirnames in os.walk(blockDir):
            for subdirname in dirnames[1]:
                try:
                    devPath = "/sys/class/block/%s/dev" % subdirname
                    startPath = "/sys/class/block/%s/start" % subdirname
                    sizePath = "/sys/class/block/%s/size" % subdirname
                    listPath = "/sys/class/block/%s/device" % subdirname

                    with open(sizePath, "r") as sizeFd:
                        size = sizeFd.readline()[:-1]

                    if any(
                        char.isdigit() for char in subdirname
                    ) and os.path.exists(startPath):
                        with open(startPath, "r") as startFd:
                            start = startFd.readline()[:-1]
                    else:
                        start = 0

                    with open(devPath, "r") as devFd:
                        partName = devFd.readline()[:-1]
                        self.partitionInfo[partName] = {}
                        self.partitionInfo[partName]["start"] = long(start)
                        self.partitionInfo[partName]["end"] = long(
                            start
                        ) + long(size)

                    # skip slave dev #
                    if not os.path.exists(listPath):
                        continue

                    # master dev #
                    dirPath = "/sys/class/block/%s" % subdirname
                    dirList = [subdirname] + os.listdir(dirPath)
                    for subdev in dirList:
                        if subdev == subdirname:
                            subdevPath = "%s/dev" % (dirPath)
                        elif subdev.startswith(subdirname):
                            subdevPath = "%s/%s/dev" % (dirPath, subdev)
                        else:
                            continue

                        with open(subdevPath, "r") as subdevFd:
                            devid = subdevFd.readline()[:-1]
                            if devid in self.devNodeInfo:
                                rpath = self.devNodeInfo[devid]
                            elif subdev in self.devNodeInfo:
                                rpath = self.devNodeInfo[subdev]
                            else:
                                rpath = subdevPath

                            self.devArchInfo.setdefault(subdirname, {})
                            self.devArchInfo[subdirname][rpath] = devid
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

    def updateMemInfo(self):
        try:
            lines = SysMgr.procReadlines("meminfo")

            if not "prev" in self.memData:
                self.memData["prev"] = lines
            else:
                self.memData["next"] = lines
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("failed to update memory", reason=True)

    @staticmethod
    def getBufferSize():
        bufFile = "%s../buffer_size_kb" % SysMgr.mountPath

        try:
            f = open(bufFile, "r")
            size = f.readlines()
            f.close()
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenWarn(bufFile)
            return 0

        return long(size[0])

    @staticmethod
    def setBufferSize(bufferSize):
        SysMgr.writeTraceCmd("../buffer_size_kb", bufferSize)

    @staticmethod
    def copyPipeToFile(pipePath, filePath):
        try:
            pd = open(pipePath, "r")
        except:
            SysMgr.printOpenErr(pipePath)
            sys.exit(-1)

        try:
            # use os.O_DIRECT | os.O_RDWR | os.O_TRUNC | os.O_CREAT #
            fd = open(filePath, "w")
            os.chmod(filePath, 0o777)
        except:
            SysMgr.printOpenErr(filePath)
            sys.exit(-1)

        pageSize = SysMgr.PAGESIZE

        while 1:
            try:
                # read each 4k data through pipe #
                buf = pd.read(pageSize)

                fd.write(buf)

                # print to console #
                if SysMgr.streamEnable:
                    SysMgr.printPipe(buf, newline=False)

                if SysMgr.recordStatus:
                    continue

                raise Exception("recording termination")
            except:
                # close pipe #
                pd.close()

                # read the remaining data under 4k from log buffer #
                tpath = os.path.join(SysMgr.mountPath, "../trace")
                with open(tpath, "r") as fr:
                    fd.write(fr.read())

                # close file to sync disk buffer #
                fd.close()

                # save system info #
                SysMgr.saveSysStats()

                path = SysMgr.outputFile

                rbuf = ""
                with open(path, "r") as fd:
                    rbuf = fd.read()

                with open(path, "w") as fd:
                    if SysMgr.systemInfoBuffer != "":
                        fd.writelines(SysMgr.magicStr + "\n")
                        fd.writelines(SysMgr.systemInfoBuffer)
                        fd.writelines(SysMgr.magicStr + "\n")
                        fd.writelines(rbuf)
                    os.chmod(path, 0o777)

                SysMgr.printInfo(
                    "wrote data to '%s' [%s] successfully"
                    % (path, UtilMgr.getFileSize(path))
                )

                return

    @staticmethod
    def getDebugfsPath():
        try:
            lines = SysMgr.procReadlines("mounts")
        except:
            SysMgr.printErr("failed to get mount path", True)
            return None

        ret = None
        for l in lines:
            m = re.match(r"(?P<dev>\S+)\s+(?P<dir>\S+)\s+(?P<fs>\S+)", l)
            if not m:
                continue

            d = m.groupdict()
            if d["fs"] == "debugfs":
                ret = "%s/tracing/events/" % d["dir"]

        return ret

    @staticmethod
    def getRootDevice():
        try:
            if SysMgr.rootdevPath:
                return SysMgr.rootdevPath

            cmdline = SysMgr.procReadline("cmdline")[0:-1]
            for item in cmdline.split(" "):
                if item.startswith("root="):
                    SysMgr.rootdevPath = UtilMgr.lstrip(item, "root=")
                    return SysMgr.rootdevPath
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("failed to get root device path", reason=True)
            SysMgr.rootdevPath = "/dev/root"
            return SysMgr.rootdevPath

    @staticmethod
    def getChildList(update=True):
        if update:
            SysMgr.updateChildList()
        return SysMgr.childList

    @staticmethod
    def clearChildList():
        SysMgr.childList = {}

    @staticmethod
    def isNoChild():
        if not SysMgr.childList:
            return True
        else:
            return False

    @staticmethod
    def updateChildList():
        childList = list(SysMgr.childList)

        for pid in childList:
            if not SysMgr.isAlive(pid):
                try:
                    os.waitpid(pid, os.WNOHANG)
                except:
                    pass

                SysMgr.childList.pop(pid, None)

    @staticmethod
    def killChildren(
        sig=None, children=None, wait=False, group=False, clear=True
    ):
        if not sig:
            sig = ConfigMgr.SIGKILL

        # get child list #
        if children is None:
            SysMgr.updateChildList()
            children = list(SysMgr.childList)

        # kill children #
        SysMgr.terminateTasks(children, sig, group)

        # remove child list #
        if clear:
            SysMgr.clearChildList()

        # check wait flag #
        if not wait:
            return

        # wait for termination for all children #
        children = set(map(str, children))
        if not children:
            return

        while 1:
            # update child list #
            children = children & set(SysMgr.getPidList())
            if not children:
                break

            # wait for task termination #
            try:
                # set timer for force termination for abnormal child tasks #
                def _onAlarm(signum, frame):
                    SysMgr.termCnt += 1
                    SysMgr.sendSignalProcs(
                        signal.SIGINT
                        if SysMgr.termCnt < 10
                        else signal.SIGKILL,
                        children,
                        verb=False,
                    )

                # register kill timer #
                signal.signal(signal.SIGALRM, _onAlarm)
                signal.alarm(3)

                # wait for termination for child tasks #
                watchList = ["/proc/%s/comm" % tid for tid in children]
                SysMgr.inotify(watchList)
            except SystemExit:
                sys.exit(0)
            except:
                pass

            # remove zombie tasks #
            aliveChildren = []
            for pid in children:
                if SysMgr.isAlive(pid):
                    aliveChildren.append(pid)
            children = set(aliveChildren)

        # disable alarm #
        signal.alarm(0)

    @staticmethod
    def removeExitFunc(func, args=None):
        newList = []
        for handler in SysMgr.exitFuncList:
            if handler[0] == func and handler[1] == args:
                continue
            newList.append(handler)
        SysMgr.exitFuncList = newList

    @staticmethod
    def addExitFunc(func, args=None):
        SysMgr.exitFuncList.append([func, args])

    @staticmethod
    def doExit():
        if not hasattr(SysMgr, "exitFuncList"):
            return

        # clear exit handler list #
        exitList = SysMgr.exitFuncList
        SysMgr.exitFuncList = []

        # block signals #
        SysMgr.setIgnoreSignal()

        # call functions registered #
        for func, args in exitList:
            try:
                if args:
                    func(*args)
                else:
                    func()
            except SystemExit:
                sys.exit(0)
            except OSError:
                pass
            except:
                SysMgr.printErr("failed to execute %s" % func, True)

        # destroy termination hooks #
        del SysMgr.exitFuncList

        # release all resources #
        SysMgr.releaseResource()

        # reset terminal #
        SysMgr.resetTTY()

        os._exit(0)

    @staticmethod
    def releaseResource(sig=None):
        # kill child tasks #
        SysMgr.killChildren(sig)

        # close all files #
        SysMgr.closeAllForPrint()

    @staticmethod
    def flushAllForPrint():
        try:
            sys.stdout.flush()
        except:
            pass

        if SysMgr.pipeForPager:
            try:
                SysMgr.pipeForPager.flush()
            except:
                pass

        if SysMgr.printFd:
            try:
                SysMgr.printFd.flush()
            except:
                pass

    @staticmethod
    def closeAllForPrint():
        if SysMgr.pipeForPager:
            try:
                SysMgr.pipeForPager.close()
            except:
                pass
            finally:
                SysMgr.pipeForPager = None

        if not SysMgr.printFd:
            return

        try:
            try:
                SysMgr.printFd.flush()
            except SystemExit:
                sys.exit(0)
            except:
                pass

            fsize = UtilMgr.convSize2Unit(
                long(os.fstat(SysMgr.printFd.fileno()).st_size)
            )
            if fsize and fsize != "0":
                fsize = " [%s]" % fsize
            else:
                fsize = ""

            SysMgr.printInfo(
                "finish saving all results into '%s'%s successfully"
                % (os.path.realpath(SysMgr.printFd.name), fsize)
            )

            # close fd for output #
            SysMgr.closePrintFd()
        except SystemExit:
            sys.exit(0)
        except:
            pass

    @staticmethod
    def clearTraceBuffer():
        SysMgr.printInfo(r"clear trace buffer... ", suffix=False)
        SysMgr.writeTraceCmd("../trace", "")
        SysMgr.printInfo("[done]", prefix=False, title=False)

    @staticmethod
    def clearTraceFilter():
        SysMgr.writeTraceCmd("../set_ftrace_filter", "")
        SysMgr.writeTraceCmd("../set_ftrace_pid", "")
        SysMgr.writeTraceCmd("../set_ftrace_notrace", "")
        SysMgr.writeTraceCmd("../set_event", "")
        SysMgr.writeTraceCmd("../set_event_pid", "")
        SysMgr.writeTraceCmd("../set_graph_function", "")
        SysMgr.writeTraceCmd("../set_graph_notrace", "")
        SysMgr.writeTraceCmd("../tracing_max_latency", "0")
        SysMgr.writeTraceCmd("../tracing_thresh", "0")
        SysMgr.writeTraceCmd("../uprobe_events", "")
        SysMgr.writeTraceCmd("../kprobe_events", "")

    def initCmdList(self):
        sm = SysMgr

        # default #
        self.cmdList["sched/sched_process_fork"] = True
        self.cmdList["sched/sched_process_exit"] = True
        self.cmdList["sched/sched_process_wait"] = True
        self.cmdList["task"] = True
        self.cmdList["signal"] = True
        self.cmdList["printk"] = True
        self.cmdList["lowmemorykiller/lowmemory_kill"] = True
        self.cmdList["module/module_load"] = True
        self.cmdList["module/module_free"] = True
        self.cmdList["module/module_put"] = True
        self.cmdList["module/module_get"] = True

        # sched #
        schedFlag = sm.cpuEnable
        self.cmdList["sched/sched_switch"] = schedFlag
        self.cmdList["sched/sched_migrate_task"] = schedFlag
        wakeupFlag = (sm.cpuEnable and sm.latEnable) or sm.depEnable
        self.cmdList["sched/sched_wakeup"] = wakeupFlag
        self.cmdList["sched/sched_wakeup_new"] = wakeupFlag

        # irq #
        irqFlag = sm.irqEnable
        self.cmdList["irq/irq_handler_entry"] = irqFlag
        self.cmdList["irq/irq_handler_exit"] = irqFlag
        self.cmdList["irq/softirq_entry"] = irqFlag
        self.cmdList["irq/softirq_exit"] = irqFlag
        self.cmdList["irq/softirq_raise"] = False

        # syscall #
        syscallFlag = sm.sysEnable | sm.depEnable | sm.lockEnable
        self.cmdList["raw_syscalls"] = syscallFlag

        # mem #
        memFlag = sm.memEnable
        self.cmdList["kmem/mm_page_alloc"] = memFlag
        self.cmdList["kmem/mm_page_free"] = memFlag
        self.cmdList["kmem/kmalloc"] = memFlag
        self.cmdList["kmem/kfree"] = memFlag
        self.cmdList["filemap/mm_filemap_delete_from_page_cache"] = memFlag
        self.cmdList["vmscan/mm_vmscan_direct_reclaim_begin"] = memFlag
        self.cmdList["vmscan/mm_vmscan_direct_reclaim_end"] = memFlag
        self.cmdList["kmem/mm_page_free_direct"] = False
        self.cmdList["timer/hrtimer_start"] = False
        self.cmdList["vmscan/mm_vmscan_wakeup_kswapd"] = False
        self.cmdList["vmscan/mm_vmscan_kswapd_sleep"] = False

        # bio #
        bioFlag = sm.blockEnable
        self.cmdList["block/block_bio_queue"] = bioFlag
        """
        ignore block_bio_complete for redundant operations
        self.cmdList["block/block_bio_complete"] = bioFlag
        """
        self.cmdList["block/block_rq_complete"] = bioFlag
        self.cmdList["writeback/writeback_dirty_page"] = bioFlag
        self.cmdList["filemap/mm_filemap_add_to_page_cache"] = bioFlag
        # self.cmdList["writeback/wbc_writepage"] = bioFlag

        # fs #
        fsFlag = sm.fsEnable
        self.cmdList["fs"] = fsFlag  # file name support for open, exec, ... #
        self.cmdList["f2fs/f2fs_sync_file_enter"] = fsFlag
        self.cmdList["f2fs/f2fs_sync_file_exit"] = fsFlag
        self.cmdList["f2fs/f2fs_write_begin"] = fsFlag
        self.cmdList["f2fs/f2fs_write_end"] = fsFlag
        self.cmdList["ext4/ext4_da_write_begin"] = fsFlag
        self.cmdList["ext4/ext4_da_write_end"] = fsFlag
        self.cmdList["ext4/ext4_sync_file_enter"] = fsFlag
        self.cmdList["ext4/ext4_sync_file_exit"] = fsFlag
        self.cmdList["ext4/ext4_es_lookup_extent_enter"] = fsFlag
        self.cmdList["ext4/ext4_es_lookup_extent_exit"] = fsFlag
        self.cmdList["ext4/ext4_direct_IO_enter"] = fsFlag
        self.cmdList["ext4/ext4_direct_IO_exit"] = fsFlag
        self.cmdList["btrfs"] = fsFlag

        # network #
        netFlag = sm.networkEnable
        self.cmdList["net/net_dev_xmit"] = netFlag

        # probes #
        self.cmdList["uprobes"] = sm.ueventEnable
        self.cmdList["kprobes"] = sm.keventEnable

        # lock #
        self.cmdList["filelock/locks_get_lock_context"] = sm.lockEnable

        # power #
        powerFlag = sm.powerEnable
        self.cmdList["power/cpu_idle"] = powerFlag
        self.cmdList["power/cpu_frequency"] = powerFlag
        self.cmdList["power/suspend_resume"] = powerFlag

        # binder #
        binderFlag = sm.binderEnable
        self.cmdList["binder/binder_transaction"] = binderFlag
        self.cmdList["binder/binder_transaction_received"] = binderFlag
        """
        self.cmdList["binder/binder_lock"] = binderFlag
        self.cmdList["binder/binder_locked"] = binderFlag
        self.cmdList["binder/binder_unlock"] = binderFlag
        self.cmdList["binder/binder_set_priority"] = binderFlag
        """

        # workqueue #
        self.cmdList["workqueue/workqueue_queue_work"] = sm.wqEnable
        self.cmdList["workqueue/workqueue_execute_start"] = sm.wqEnable
        self.cmdList["workqueue/workqueue_execute_end"] = sm.wqEnable

        # TODO: implement analyzer for below events #

        # i2c #
        self.cmdList["i2c"] = sm.i2cEnable

        # io_uring #
        self.cmdList["io_uring"] = sm.iouringEnable

        # kvm #
        self.cmdList["kvm"] = sm.iouringEnable

    def runPeriodProc(self):
        pid = SysMgr.createProcess()

        if pid == 0:
            signal.signal(signal.SIGINT, 0)

            while 1:
                time.sleep(0.0001)

            sys.exit(0)

    def prepareForTracing(self):
        stat = SysMgr.readTraceFile("../tracing_on")
        if stat == "0":
            pass
        elif SysMgr.forceEnable:
            # write command to stop tracing #
            SysMgr.writeTraceCmd("../tracing_on", "0")
        elif stat == "1":
            # no running Guider process except for myself #
            if SysMgr.getBgProcCount(cache=True) <= 1:
                res = SysMgr.readTraceFile("enable")
                # default status #
                if res == "0":
                    pass
                # tracing status #
                else:
                    SysMgr.printErr(
                        "failed to start tracing because "
                        "tracing is already in progress on system\n"
                        "\tit would be stopped so that try to record again"
                    )
                    sys.exit(-1)
            else:
                SysMgr.printErr(
                    "failed to start tracing because "
                    "another Guider is already running"
                )
                os._exit(0)

        # check fast init condition #
        if "FASTINIT" in SysMgr.environList:
            return

        # clean up trace buffer #
        SysMgr.clearTraceBuffer()

        # clear trace filter #
        SysMgr.clearTraceFilter()

    def setPidFilter(self, targets):
        params = ", ".join(targets)

        # get thread ID #
        targetTasks = []
        for item in targets:
            targetTasks += SysMgr.getTids(item, sibling=SysMgr.findOption("P"))

        # check thread list #
        if not targetTasks:
            SysMgr.printErr("no task related to '%s'" % params)
            sys.exit(0)

        targetTasks = " ".join(list(map(str, targetTasks)))

        try:
            SysMgr.writeTraceCmd("../set_ftrace_pid", targetTasks, True)
            SysMgr.printInfo(
                "only specific processes [ %s ] are traced" % targetTasks
            )
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to add '%s' to PID filter" % params,
                True,
            )
            sys.exit(-1)

    def startTracing(self):
        # write command to start tracing #
        SysMgr.writeTraceCmd("../tracing_on", "1")

        # write start event #
        SysMgr.writeEvent("EVENT_START", False)

        # update start recording time #
        SysMgr.startRecTime = SysMgr.getUptime()

        # update status #
        SysMgr.recordStatus = True

        # register cleanup callback #
        if "FASTINIT" in SysMgr.environList:
            SysMgr.addExitFunc(SysMgr.clearTraceBuffer)
            SysMgr.addExitFunc(SysMgr.clearTraceFilter)

    def enableEvents(self):
        for cmd, value in self.cmdList.items():
            if value:
                SysMgr.writeTraceCmd("%s/enable" % cmd, "1")

    def startRecording(self):
        def _printStartLog():
            # write user command #
            SysMgr.runProfCmd("AFTER")

            SysMgr.printStat(
                r"start recording... [ STOP(Ctrl+c), MARK(Ctrl+\) ]"
            )

        def _writeCommonCmd():
            # enable dynamic events #
            SysMgr.writeCustomCmd()
            SysMgr.writeKernelCmd()
            SysMgr.writeUserCmd()

            # enable signal filter #
            if self.cmdList["signal"]:
                if SysMgr.filterGroup:
                    commonFilter = SysMgr.getPidFilter()
                    genFilter = commonFilter.replace("common_", "")
                    SysMgr.writeTraceCmd(
                        "signal/signal_deliver/filter", commonFilter
                    )
                    SysMgr.writeTraceCmd(
                        "signal/signal_generate/filter", genFilter
                    )

        def _startFuncGraph(self):
            # reset events #
            SysMgr.stopRecording()

            # set function_graph tracer #
            if SysMgr.writeTraceCmd("../current_tracer", "function_graph") < 0:
                SysMgr.printErr(
                    "enable CONFIG_FUNCTION_GRAPH_TRACER kernel option"
                )
                sys.exit(-1)

            # apply PID filter #
            if SysMgr.filterGroup:
                self.setPidFilter(SysMgr.filterGroup)

            # set function_graph options #
            optPath = "../trace_options"
            SysMgr.writeTraceCmd(optPath, "nofuncgraph-proc")
            SysMgr.writeTraceCmd(optPath, "funcgraph-abstime")
            SysMgr.writeTraceCmd(optPath, "funcgraph-overhead")
            SysMgr.writeTraceCmd(optPath, "funcgraph-duration")
            SysMgr.writeTraceCmd("../max_graph_depth", str(SysMgr.funcDepth))

            # apply function filter #
            if SysMgr.customCmd:
                params = " ".join(SysMgr.customCmd)
                SysMgr.printInfo(
                    "start setting function filter [ %s ]" % params
                )
                if SysMgr.writeTraceCmd("../set_ftrace_filter", params) < 0:
                    SysMgr.printErr("failed to set function filter")
                    sys.exit(-1)
                else:
                    SysMgr.printStat(
                        "finished applying function filter [ %s ]" % params
                    )
            else:
                SysMgr.writeTraceCmd("../set_ftrace_filter", "")

            # apply threshold (us) #
            if "ELAPSED" in SysMgr.environList:
                threshold = UtilMgr.getEnvironNum("ELAPSED")
                SysMgr.printInfo(
                    (
                        "only specific functions that took "
                        "at least '%s us' or longer are printed"
                    )
                    % UtilMgr.convNum(threshold)
                )
                if (
                    SysMgr.writeTraceCmd("../tracing_thresh", str(threshold))
                    < 0
                ):
                    SysMgr.printErr("failed to set threshold value")
                    sys.exit(-1)

            # start tracing #
            self.startTracing()

        # check root permission #
        SysMgr.checkRootPerm(msg="trace system")

        # mount debugfs #
        SysMgr.mountPath = SysMgr.getDebugfsPath()
        if not SysMgr.mountPath:
            SysMgr.mountDebugfs()

        # check permission #
        if not os.path.isdir(SysMgr.mountPath):
            cmd = "/boot/config-$(uname -r)"
            SysMgr.printErr(
                (
                    "check whether ftrace options are enabled in kernel "
                    "through %s"
                )
                % cmd
            )
            sys.exit(-1)

        # write user command #
        SysMgr.runProfCmd("BEFORE")

        # set size of trace buffer per core #
        if SysMgr.bufferSize < 0:
            SysMgr.bufferSize = "40960"  # 40MB #
        else:
            # Change from integer to string #
            SysMgr.bufferSize = str(SysMgr.bufferSize)

        # set system buffer size #
        SysMgr.setBufferSize(SysMgr.bufferSize)

        # get system buffer size #
        setBufferSize = SysMgr.getBufferSize()

        # check system buffer size #
        if long(SysMgr.bufferSize) != setBufferSize:
            SysMgr.printWarn(
                "failed to set buffer size to %s KB, now is %s KB"
                % (SysMgr.bufferSize, setBufferSize),
                True,
            )

        # initialize event list to enable #
        self.initCmdList()

        if SysMgr.disableAll:
            SysMgr.sysInstance.disableAllEvents()

        # set comm cache size #
        SysMgr.writeTraceCmd("../saved_cmdlines_size", "32767")

        # set log format #
        for opt in ("noirq-info", "noannotate", "print-tgid", "record-tgid"):
            SysMgr.writeTraceCmd("../trace_options", opt)
        SysMgr.writeTraceCmd("../current_tracer", "nop")

        SysMgr.printStat(
            r"prepare for recording... [ STOP(Ctrl+c), MARK(Ctrl+\) ]"
        )

        # prepare for tracing #
        self.prepareForTracing()

        # -------------------- FUNCTION MODE --------------------#
        if SysMgr.isFuncMode():
            # check conditions for kernel function_graph #
            if SysMgr.graphEnable:
                # start function graph #
                _startFuncGraph(self)

                _printStartLog()
                return

            # define initialized command variable #
            cmd = ""

            # make filter for function mode #
            if SysMgr.filterGroup:
                try:
                    try:
                        cmd += SysMgr.getPidFilter()
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass

                    if not cmd:
                        raise Exception("no command")
                except:
                    SysMgr.printErr("wrong TID %s" % SysMgr.filterGroup, True)
                    sys.exit(-1)

            # trace except for swapper threads #
            if cmd == "":
                cmd = "(common_pid != 0)"

            # set userstacktrace options #
            if SysMgr.userEnable:
                SysMgr.writeTraceCmd("../trace_options", "userstacktrace")
                SysMgr.writeTraceCmd("../trace_options", "sym-userobj")
            else:
                SysMgr.writeTraceCmd("../trace_options", "nouserstacktrace")
                SysMgr.writeTraceCmd("../trace_options", "nosym-userobj")

            SysMgr.writeTraceCmd("../trace_options", "sym-addr")
            SysMgr.writeTraceCmd("../options/stacktrace", "1")

            if SysMgr.disableAll:
                _printStartLog()
                return

            # segmentation fault events #
            elist = SysMgr.customCmd
            if elist:
                pass
            elif any([True for evt in elist if evt.startswith("signal")]):
                pass
            else:
                sigCmd = "sig == %d" % signal.SIGSEGV
                SysMgr.writeTraceCmd("signal/filter", sigCmd)

            # CPU events #
            if SysMgr.cpuEnable:
                addr = SysMgr.getKerAddr("tick_sched_timer")
                if addr:
                    SysMgr.writeTraceCmd(
                        "timer/hrtimer_start/filter",
                        "%s && function == 0x%s" % (cmd, addr),
                    )
                SysMgr.writeTraceCmd("timer/hrtimer_start/enable", "1")
            else:
                SysMgr.writeTraceCmd("timer/hrtimer_start/enable", "0")

            # page events #
            if SysMgr.memEnable:
                SysMgr.writeTraceCmd("kmem/mm_page_alloc/filter", cmd)

                if SysMgr.writeTraceCmd("kmem/mm_page_free/filter", cmd) < 0:
                    SysMgr.writeTraceCmd(
                        "kmem/mm_page_free_direct/filter", cmd
                    )

                SysMgr.writeTraceCmd("kmem/mm_page_alloc/enable", "1")

                if SysMgr.writeTraceCmd("kmem/mm_page_free/enable", "1") < 0:
                    SysMgr.writeTraceCmd(
                        "kmem/mm_page_free_direct/enable", "1"
                    )
            else:
                SysMgr.writeTraceCmd("kmem/mm_page_alloc/enable", "0")

                if SysMgr.writeTraceCmd("kmem/mm_page_free/enable", "0") < 0:
                    SysMgr.writeTraceCmd(
                        "kmem/mm_page_free_direct/enable", "0"
                    )

            # all syscall events #
            if SysMgr.sysEnable:
                if SysMgr.heapEnable or SysMgr.lockEnable:
                    SysMgr.printErr(
                        "failed to enable syscall events with other events"
                    )
                    sys.exit(-1)
                elif not SysMgr.syscallList:
                    pass
            else:
                # heap events #
                if SysMgr.heapEnable:
                    if SysMgr.arch == "arm":
                        mmapId = SysMgr.getNrSyscall("sys_mmap2")
                    else:
                        mmapId = SysMgr.getNrSyscall("sys_mmap")

                    brkId = SysMgr.getNrSyscall("sys_brk")

                    SysMgr.syscallList.append(mmapId)
                    SysMgr.syscallList.append(brkId)

                    self.cmdList["raw_syscalls"] = True

                # lock events #
                if SysMgr.lockEnable:
                    futexId = SysMgr.getNrSyscall("sys_futex")

                    SysMgr.syscallList.append(futexId)

                    self.cmdList["raw_syscalls"] = True

            # target syscall events #
            SysMgr.writeSyscallCmd(self.cmdList["raw_syscalls"])

            # block events #
            if SysMgr.blockEnable:
                blkCmd = cmd + (
                    """ && (rwbs == "R" || rwbs == "RA" || """
                    """rwbs == "RM" || rwbs == "WS")"""
                )
                SysMgr.writeTraceCmd("block/block_bio_queue/filter", blkCmd)
                SysMgr.writeTraceCmd("block/block_bio_queue/enable", "1")
                SysMgr.writeTraceCmd(
                    "writeback/writeback_dirty_page/filter", cmd
                )
                SysMgr.writeTraceCmd(
                    "writeback/writeback_dirty_page/enable", "1"
                )
                """
                SysMgr.writeTraceCmd('writeback/wbc_writepage/filter', cmd)
                SysMgr.writeTraceCmd('writeback/wbc_writepage/enable', '1')
                """
            else:
                SysMgr.writeTraceCmd("block/block_bio_queue/enable", "0")
                SysMgr.writeTraceCmd(
                    "writeback/writeback_dirty_page/enable", "0"
                )
                # SysMgr.writeTraceCmd('writeback/wbc_writepage/enable', '0')

            # special events #
            _writeCommonCmd()

            # write user command #
            SysMgr.runProfCmd("AFTER")

            # start tracing #
            self.startTracing()

            # print log #
            _printStartLog()
            return

        # -------------------- THREAD MODE --------------------#
        def _applySchedFilter():
            cmd = "prev_pid == 0 || next_pid == 0 || "

            # apply filter #
            for comm in list(SysMgr.filterGroup):
                # comm #
                cmd = (
                    """%sprev_comm == "*%s*" || next_comm == "*%s*" || """
                    % (cmd, comm, comm)
                )

                # tid #
                try:
                    # just TID #
                    if comm.isdigit():
                        pid = long(comm)
                        cmd = "%sprev_pid == %s || next_pid == %s || " % (
                            cmd,
                            pid,
                            pid,
                        )
                    # TID bigger or lesser #
                    elif comm.startswith(">") or comm.endswith("<"):
                        cmd += "prev_pid >= %s || " % long(comm.strip("<>"))
                        cmd += "next_pid >= %s || " % long(comm.strip("<>"))
                    # PID bigger or lesser #
                    elif comm.startswith("<") or comm.endswith(">"):
                        cmd += "prev_pid <= %s || " % long(comm.strip("<>"))
                        cmd += "next_pid <= %s || " % long(comm.strip("<>"))
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

            cmd = cmd[: cmd.rfind("||")].strip()
            if SysMgr.writeTraceCmd("sched/sched_switch/filter", cmd) < 0:
                SysMgr.printErr(
                    "failed to set filter [ %s ]"
                    % " ".join(SysMgr.filterGroup)
                )
                sys.exit(-1)

        # sched events #
        if self.cmdList["sched/sched_switch"]:
            if SysMgr.filterGroup:
                _applySchedFilter()
            else:
                SysMgr.writeTraceCmd("sched/sched_switch/filter", "0")

            if SysMgr.writeTraceCmd("sched/sched_switch/enable", "1") < 0:
                SysMgr.printErr("failed to enable sched events")
                sys.exit(-1)

        # build sched filter #
        if SysMgr.filterGroup:
            cmd = SysMgr.getPidFilter("pid", True, False)
        else:
            cmd = "0"

        # set sched filters #
        filterStr = " ".join(SysMgr.filterGroup)
        for schedItem in [
            "wakeup",
            "wakeup_new",
            "migrate_task",
            "process_wait",
        ]:
            name = "sched/sched_" + schedItem
            if not self.cmdList[name]:
                continue

            if SysMgr.writeTraceCmd(name + "/filter", cmd) < 0:
                SysMgr.printErr(
                    "failed to set '%s' filter to [ %s ]" % (name, filterStr)
                )
                sys.exit(-1)

        # events for dependency tracing #
        if SysMgr.depEnable:
            ecmd = "("
            rcmd = "(("

            for syscall in ("sys_write", "sys_futex"):
                ecmd += "id == %s || " % SysMgr.getNrSyscall(syscall)
                rcmd += "id == %s || " % SysMgr.getNrSyscall(syscall)

            if SysMgr.arch == "arm":
                syscallList = (
                    "sys_recv",
                    "sys_epoll_wait",
                    "sys_poll",
                    "sys_select",
                    "sys_recvfrom",
                    "sys_recvmmsg",
                    "sys_recvmsg",
                )
            elif SysMgr.arch == "aarch64":
                syscallList = ("sys_recvfrom", "sys_recvmmsg", "sys_recvmsg")
            else:
                syscallList = (
                    "sys_epoll_wait",
                    "sys_poll",
                    "sys_select",
                    "sys_recvfrom",
                    "sys_recvmmsg",
                    "sys_recvmsg",
                )

            for syscall in syscallList:
                ecmd += "id == %s || " % SysMgr.getNrSyscall(syscall)
                rcmd += "id == %s || " % SysMgr.getNrSyscall(syscall)

            ecmd = ecmd.rstrip(" |") + ")"
            rcmd = rcmd.rstrip(" |") + ") && ret > 0)"

            SysMgr.writeTraceCmd("raw_syscalls/sys_enter/filter", ecmd)
            SysMgr.writeTraceCmd("raw_syscalls/sys_exit/filter", rcmd)
        elif SysMgr.lockEnable:
            nrFutex = SysMgr.getNrSyscall("sys_futex")
            if nrFutex not in SysMgr.syscallList:
                SysMgr.syscallList.append(nrFutex)
        else:
            SysMgr.writeTraceCmd("raw_syscalls/sys_enter/filter", "0")
            SysMgr.writeTraceCmd("raw_syscalls/sys_enter/enable", "0")

        # syscall events #
        SysMgr.writeSyscallCmd(self.cmdList["raw_syscalls"])

        # memory events #
        if self.cmdList["kmem/mm_page_free"]:
            if SysMgr.writeTraceCmd("kmem/mm_page_free/enable", "1") < 0:
                SysMgr.writeTraceCmd("kmem/mm_page_free_direct/enable", "1")

        # block events #
        cmd = '''rwbs == "R" || rwbs == "RA" || rwbs == "RM" || rwbs == "WS"'''
        if self.cmdList["block/block_bio_queue"]:
            SysMgr.writeTraceCmd("block/block_bio_queue/filter", cmd)
        if self.cmdList["block/block_rq_complete"]:
            SysMgr.writeTraceCmd("block/block_rq_complete/filter", cmd)

        # special events #
        _writeCommonCmd()

        # enable events #
        self.enableEvents()

        # start tracing #
        self.startTracing()

        # print log #
        _printStartLog()

    @staticmethod
    def stopRecording():
        if not SysMgr.recordStatus or not (
            SysMgr.isRecordMode()
            and (SysMgr.isThreadMode() or SysMgr.isFuncMode())
        ):
            return

        # write command #
        if SysMgr.cmdEnable is not False and SysMgr.cmdFd:
            # write signal command #
            if SysMgr.signalCmd:
                try:
                    if SysMgr.intervalEnable > 0:
                        SysMgr.signalCmd += (
                            "sleep %s\n" % SysMgr.intervalEnable
                        )
                    else:
                        SysMgr.signalCmd += "sleep 32767\n"
                    SysMgr.cmdFd.write(SysMgr.signalCmd)
                    SysMgr.cmdFd.flush()
                    SysMgr.signalCmd = None
                    SysMgr.printInfo(
                        "write trace commands to '%s'" % SysMgr.cmdEnable
                    )
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr("failed to write signal commands", True)

            if SysMgr.outputFile:
                SysMgr.saveCmd = "cat %s_pipe >> %s\n" % (
                    SysMgr.inputFile,
                    os.path.realpath(SysMgr.outputFile),
                )

        # stop tracing #
        SysMgr.writeTraceCmd("../tracing_on", "0")
        SysMgr.recordStatus = False

        SysMgr.printStat(
            r"finished recording for %.3f sec"
            % (SysMgr.getUptime() - SysMgr.startRecTime)
        )

        # disable all ftrace options #
        for idx, val in SysMgr.cmdList.items():
            if val and SysMgr.writeTraceCmd(str(idx) + "/enable", "0") >= 0:
                SysMgr.writeTraceCmd(str(idx) + "/filter", "0")

        if not SysMgr.graphEnable and SysMgr.customCmd:
            for cmd in SysMgr.customCmd:
                event = cmd.split(":")[0]
                SysMgr.writeTraceCmd(event + "/enable", "0")
                SysMgr.writeTraceCmd(event + "/filter", "0")

        # reset stacktrace options #
        if SysMgr.isFuncMode():
            SysMgr.writeTraceCmd("../options/stacktrace", "0")
            SysMgr.writeTraceCmd("../trace_options", "nouserstacktrace")

        # write command #
        if SysMgr.cmdEnable is not False and SysMgr.cmdFd:
            outputPath = os.path.realpath(SysMgr.outputFile)

            # remove exist file #
            try:
                SysMgr.cmdFd.write("rm -f %s 2> /dev/null\n" % outputPath)
            except SystemExit:
                sys.exit(0)
            except:
                pass

            # write system info #
            try:
                SysMgr.sysInstance.printResourceInfo(tree=False)
                infoStr = 'echo "%s\n%s\n%s\n" >> %s\n' % (
                    SysMgr.magicStr,
                    SysMgr.systemInfoBuffer,
                    SysMgr.magicStr,
                    outputPath,
                )
                SysMgr.clearInfoBuffer()
                SysMgr.cmdFd.write(infoStr)
                SysMgr.cmdFd.flush()
            except SystemExit:
                sys.exit(0)
            except:
                pass

            # write save command #
            if SysMgr.saveCmd:
                try:
                    SysMgr.cmdFd.write(SysMgr.saveCmd)
                    SysMgr.cmdFd.write(
                        (
                            "echo '\n[Info] saved commands "
                            "for tracing into %s\n'\n"
                        )
                        % outputPath
                    )
                    SysMgr.cmdFd.flush()
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr("failed to write command", True)

    def printResourceInfo(self, tree=True):
        if not SysMgr.generalEnable:
            return

        self.printSystemInfo()

        self.printOSInfo()

        self.printCpuInfo()

        self.printCpuCacheInfo()

        self.printMemInfo()

        self.printStorageInfo()

        self.printBlockInfo()

        self.printNetworkInfo()

        self.printGpuInfo()

        self.printGpuMemInfo()

        self.printIPCInfo()

        self.printCgroupInfo()

        self.printLimitInfo()

        self.printSchedInfo()

        self.printMmapInfo()

        self.printUSBInfo()

        if not tree:
            return

        if SysMgr.isRecordMode():
            TaskAnalyzer.printThreadTree()

        # keep last position for parser #
        self.printProcTreeInfo()

    def printProcTreeInfo(self):
        if self.procData:
            SysMgr.infoBufferPrint(self.procData)

    def printOSInfo(self):
        if not self.osData and not self.devData:
            return

        # add JSON stats #
        if SysMgr.jsonEnable:
            SysMgr.jsonData.setdefault("general", {})
            SysMgr.jsonData["general"]["os"] = {}
            jsonData = SysMgr.jsonData["general"]["os"]

        SysMgr.infoBufferPrint("\n[System OS Info]")
        SysMgr.infoBufferPrint(twoLine)
        SysMgr.infoBufferPrint("{0:^35} {1:100}".format("Type", "Information"))
        SysMgr.infoBufferPrint(twoLine)

        # save os data #
        try:
            for data in self.osData:
                val = data.split("=")
                if len(val) < 2:
                    val = data.split(":")
                if len(val) < 2:
                    continue

                name = val[0].replace('"', "")
                value = (
                    val[1].replace('"', "").replace("\n", "").replace(",", "")
                )
                SysMgr.infoBufferPrint("{0:35} {1:<100}".format(name, value))

                if SysMgr.jsonEnable:
                    jsonData[name] = value
        except:
            SysMgr.printWarn("failed to parse osData")

        # save device data #
        try:
            for val in self.devData:
                val = data.split("=")
                if len(val) < 2:
                    val = data.split(":")
                if len(val) < 2:
                    continue

                name = val[0].replace('"', "")
                value = (
                    val[1].replace('"', "").replace("\n", "").replace(",", "")
                )
                SysMgr.infoBufferPrint("{0:35} {1:<100}".format(name, value))

                if SysMgr.jsonEnable:
                    jsonData[name] = value
        except:
            pass

        SysMgr.infoBufferPrint(twoLine)

    def printUSBInfo(self):
        SysMgr.infoBufferPrint("\n[System USB Info]")
        SysMgr.infoBufferPrint(twoLine)

        # read USB info #
        try:
            with open("/sys/kernel/debug/usb/devices", "r") as fd:
                data = fd.readlines()
        except SystemExit:
            sys.exit(0)
        except:
            data = None

        # check result #
        if not data:
            SysMgr.infoBufferPrint("\tNone")
            SysMgr.infoBufferPrint(twoLine)
            return

        for idx, line in enumerate(data):
            line = line.strip()
            if line:
                SysMgr.infoBufferPrint(line)
            elif idx == 0 or idx == len(data) - 1:
                pass
            else:
                SysMgr.infoBufferPrint(oneLine)

        SysMgr.infoBufferPrint(twoLine)

    def printMmapInfo(self):
        SysMgr.infoBufferPrint("\n[Memory Map Info]\n%s" % twoLine)
        SysMgr.infoBufferPrint(
            "{0:^35} | {1:^32} | {2:<1}\n{3:1}".format(
                "ADDR", "SIZE", "NAME", twoLine
            )
        )

        # get memory map #
        maps = SysMgr.readMemoryMap()
        if not maps:
            SysMgr.infoBufferPrint("\tNone")
            SysMgr.infoBufferPrint(twoLine)
            return

        # print memory map #
        for start, value in sorted(maps.items(), key=lambda e: long(e[0])):
            addr = "%16s - %16s" % (value["start"], value["end"])
            SysMgr.infoBufferPrint(
                "{0:>35} | {1:>32} | {2:<1}".format(
                    addr, value["sizeUnit"], value["name"]
                )
            )

        SysMgr.infoBufferPrint(twoLine)

    def printSchedInfo(self):
        def _printItems(status, items):
            indentStr = " " * 11
            enableStr = "{0:^10} ".format(status)

            if SysMgr.ttyCols < len(oneLine):
                maxLen = SysMgr.ttyCols
            else:
                maxLen = len(oneLine)

            for item in items:
                curLineLen = len(enableStr.split("\n")[-1]) + len(item) + 3
                if curLineLen > maxLen:
                    enableStr += "\n%s" % indentStr
                enableStr += " | %s" % item
            SysMgr.infoBufferPrint(enableStr)

        SysMgr.infoBufferPrint("\n[Sched Feature Info]")
        SysMgr.infoBufferPrint(twoLine)
        SysMgr.infoBufferPrint(
            "{0:^10} {1:<1}".format("STATUS", " | FEATURES")
        )
        SysMgr.infoBufferPrint(twoLine)

        # get sched features #
        features = SysMgr.readSchedFeatures()
        if not features:
            SysMgr.infoBufferPrint("\tNone")
            SysMgr.infoBufferPrint(twoLine)
            return

        # distinguish items #
        enabled = []
        disabled = []
        for item in features:
            if item.startswith("NO_"):
                disabled.append(item)
            else:
                enabled.append(item)

        # print enabled items #
        if enabled:
            _printItems("ENABLE", enabled)

        # print disabled items #
        if enabled:
            _printItems("DISABLE", disabled)

        SysMgr.infoBufferPrint(twoLine)

    def printLimitInfo(self):
        if not self.limitData:
            return

        # add JSON stats #
        if SysMgr.jsonEnable:
            SysMgr.jsonData.setdefault("general", {})
            SysMgr.jsonData["general"].setdefault("limit", {})
            jsonData = SysMgr.jsonData["general"]["limit"]

        limitData = self.limitData
        title = limitData.pop(0)

        SysMgr.infoBufferPrint("\n[Task Limit Info]")
        SysMgr.infoBufferPrint(twoLine)
        SysMgr.infoBufferPrint(title.rstrip())
        SysMgr.infoBufferPrint(twoLine)

        for line in self.limitData[1:]:
            limit = line.rstrip()
            SysMgr.infoBufferPrint(limit)

            if not SysMgr.jsonEnable:
                continue

            try:
                items = limit.split()
                name = " ".join(items[:-4])
                jsonData.setdefault(name, {})
                jsonData[name]["soft"] = items[-3]
                jsonData[name]["hard"] = items[-2]
                jsonData[name]["unit"] = items[-1]
            except SystemExit:
                sys.exit(0)
            except:
                pass

        SysMgr.infoBufferPrint(twoLine)

    def printSystemInfo(self):
        # add JSON stats #
        if SysMgr.jsonEnable:
            SysMgr.jsonData.setdefault("general", {})
            jsonData = SysMgr.jsonData["general"]

        SysMgr.infoBufferPrint("\n\n[System General Info]")
        SysMgr.infoBufferPrint(twoLine)
        SysMgr.infoBufferPrint("{0:^20} {1:<1}".format("Type", "Information"))
        SysMgr.infoBufferPrint(twoLine)

        # launch option #
        try:
            launchOption = " ".join(sys.argv) + " -"
            SysMgr.infoBufferPrint(
                "{0:20} # {1:<1}".format("Launch", launchOption)
            )

            if SysMgr.jsonEnable:
                jsonData["launch"] = launchOption
        except:
            pass

        # version #
        try:
            SysMgr.infoBufferPrint(
                "{0:20} {1:<1}".format("Version", "%s" % __version__)
            )

            if SysMgr.jsonEnable:
                jsonData["version"] = __version__
        except:
            pass

        # python #
        try:
            pv = ".".join(list(map(str, sys.version_info)))
            SysMgr.infoBufferPrint("{0:20} {1:<1}".format("Python", pv))

            if SysMgr.jsonEnable:
                jsonData["python"] = pv
        except:
            pass

        # hostname #
        try:
            hostname = self.uname[1]
            SysMgr.infoBufferPrint("{0:20} {1:<1}".format("Host", hostname))

            if SysMgr.jsonEnable:
                jsonData["host"] = hostname
        except:
            pass

        # IP #
        try:
            ip = NetworkMgr.getPublicIp()
            SysMgr.infoBufferPrint("{0:20} {1:<1}".format("IP", ip))

            if SysMgr.jsonEnable:
                jsonData["ip"] = ip
        except:
            pass

        # MAC #
        try:
            if not self.macAddr:
                raise Exception("no MAC")

            macStr = "%s_%s" % (self.macAddr[0], self.macAddr[1])
            SysMgr.infoBufferPrint("{0:20} {1:<10}".format("Mac", macStr))

            if SysMgr.jsonEnable:
                jsonData["mac"] = macStr
        except:
            pass

        # CPU #
        try:
            SysMgr.infoBufferPrint("{0:20} {1:<1}".format("CPU", SysMgr.arch))

            if SysMgr.jsonEnable:
                jsonData["arch"] = SysMgr.arch
        except:
            pass

        # GPU #
        try:
            gpuList = SysMgr.getGpuList()
            if not gpuList:
                raise Exception("no GPU")

            name = "GPU"
            for item in gpuList:
                SysMgr.infoBufferPrint("{0:20} {1:<1}".format(name, item))
                name = " "

            if SysMgr.jsonEnable:
                jsonData["gpu"] = gpuList
        except:
            pass

        # OS #
        try:
            osInfo = self.uname[0]
            SysMgr.infoBufferPrint("{0:20} {1:<1}".format("OS", osInfo))

            if SysMgr.jsonEnable:
                jsonData["os"] = osInfo
        except:
            pass

        # kernel #
        try:
            kernelInfo = self.uname[2]
            SysMgr.infoBufferPrint(
                "{0:20} {1:<1}".format("Kernel", kernelInfo)
            )

            if SysMgr.jsonEnable:
                jsonData["kernel"] = kernelInfo
        except:
            pass

        # release #
        try:
            releaseInfo = self.uname[3]
            SysMgr.infoBufferPrint(
                "{0:20} {1:<1}".format("Release", releaseInfo)
            )

            if SysMgr.jsonEnable:
                jsonData["release"] = releaseInfo
        except:
            pass

        # user #
        try:
            uid = str(SysMgr.getUid("self"))

            SysMgr.infoBufferPrint(
                "{0:20} {1:<1}".format("User", self.userData[uid]["name"])
            )

            if SysMgr.jsonEnable:
                jsonData["user"] = self.userData[uid]["name"]
        except:
            pass

        # datetime #
        try:
            timeInfo = "%s %s" % (
                self.systemInfo["date"],
                self.systemInfo["time"],
            )
            SysMgr.infoBufferPrint("{0:20} {1:<1}".format("Date", timeInfo))

            if SysMgr.jsonEnable:
                jsonData["date"] = self.systemInfo["date"]
                jsonData["time"] = self.systemInfo["time"]
        except:
            pass

        # starttime #
        try:
            startTimeNum = long(str(SysMgr.startTime).split(".")[0])
            startTime = UtilMgr.convTime(startTimeNum)
            startTimeSec = UtilMgr.convNum(startTimeNum)
            startTimeStr = "%s (%s sec)" % (startTime, startTimeSec)
            SysMgr.infoBufferPrint(
                "{0:20} {1:<1}".format("StartTime", startTimeStr)
            )

            if SysMgr.jsonEnable:
                jsonData["starttime"] = startTime
        except:
            pass

        # endtime #
        try:
            endTime = UtilMgr.convTime(SysMgr.uptime)
            endTimeSec = UtilMgr.convNum(SysMgr.uptime)
            endTimeStr = "%s (%s sec)" % (endTime, endTimeSec)
            SysMgr.infoBufferPrint(
                "{0:20} {1:<1}".format("EndTime", endTimeStr)
            )

            if SysMgr.jsonEnable:
                jsonData["endTime"] = endTime
                jsonData["uptime"] = endTime
        except:
            pass

        # runtime #
        try:
            runtime = SysMgr.getRuntime(sec=True)
            runtimeSec = UtilMgr.convNum(runtime)
            runtime = UtilMgr.convTime(runtime)
            runtimeStr = "%s (%s sec)" % (runtime, runtimeSec)
            SysMgr.infoBufferPrint(
                "{0:20} {1:<1}".format("Runtime", runtimeStr)
            )

            if SysMgr.jsonEnable:
                jsonData["runtime"] = runtime
        except:
            pass

        # init overhead for python #
        try:
            if SysMgr.startOverheadTime == 0:
                overhead = SysMgr.startInitTime - SysMgr.startRunTime
            else:
                overhead = SysMgr.startOverheadTime
            overhead = "%.3f sec" % overhead
            SysMgr.infoBufferPrint(
                "{0:20} {1:<1}".format("InitOverhead", overhead)
            )

            if SysMgr.jsonEnable:
                jsonData["initOverhead"] = overhead
        except:
            pass

        # recording overhead #
        try:
            if SysMgr.startRecTime > 0:
                overhead = "%.3f sec" % (
                    SysMgr.startRecTime - SysMgr.startInitTime
                )
                SysMgr.infoBufferPrint(
                    "{0:20} {1:<1}".format("RecOverhead", overhead)
                )

                if SysMgr.jsonEnable:
                    jsonData["recOverhead"] = overhead
        except:
            pass

        # load #
        try:
            SysMgr.infoBufferPrint(
                "{0:20} {1:<1} / {2:<1} / {3:<1}".format(
                    "Load",
                    "%s(1m)" % self.loadData[0],
                    "%s(5m)" % self.loadData[1],
                    "%s(15m)" % self.loadData[2],
                )
            )

            if SysMgr.jsonEnable:
                jsonData["load1m"] = self.loadData[0]
                jsonData["load5m"] = self.loadData[1]
                jsonData["load15m"] = self.loadData[2]
        except:
            pass

        # task #
        try:
            convNum = UtilMgr.convNum

            try:
                maxThd = " / %s(max)" % convNum(self.nrMaxThread)
            except:
                maxThd = ""

            running, total = self.loadData[3].split("/")
            SysMgr.infoBufferPrint(
                "{0:20} {1:<10}".format(
                    "Threads",
                    "%s(running) / %s(total)%s"
                    % (convNum(running), convNum(total), maxThd),
                )
            )

            if SysMgr.jsonEnable:
                jsonData["nrRunTask"] = running
                jsonData["nrTotalTask"] = total
        except:
            pass

        # last PID #
        try:
            SysMgr.infoBufferPrint(
                "{0:20} {1:<10}".format("LastPid", self.loadData[4])
            )

            if SysMgr.jsonEnable:
                jsonData["lastPid"] = self.loadData[4]
        except:
            pass

        # open files #
        try:
            SysMgr.infoBufferPrint(
                "{0:20} {1:<1}(cur) / {2:<1}(max)".format(
                    "OpenFile",
                    convNum(self.openFileData["cur"]),
                    convNum(self.openFileData["max"]),
                )
            )

            if SysMgr.jsonEnable:
                jsonData["nrCurOpenFile"] = self.openFileData["cur"]
                jsonData["nrMaxOpenFile"] = self.openFileData["max"]
        except:
            pass

        # kernel args #
        try:
            title = "Cmdline"
            splitLen = SysMgr.lineLength - 21
            cmdlineList = [
                self.cmdlineData[i : i + splitLen]
                for i in xrange(0, len(self.cmdlineData), splitLen)
            ]
            for string in cmdlineList:
                SysMgr.infoBufferPrint("{0:20} {1:<1}".format(title, string))
                title = ""

            if SysMgr.jsonEnable:
                jsonData["cmdline"] = self.cmdlineData
        except:
            pass

        # memo #
        try:
            if not "MEMO" in SysMgr.environList:
                raise Exception("no memo")

            memo = SysMgr.environList["MEMO"][0]

            SysMgr.infoBufferPrint("{0:20} {1:<1}".format("Memo", memo))

            if SysMgr.jsonEnable:
                jsonData["memo"] = memo
        except:
            pass

        SysMgr.infoBufferPrint(twoLine)

    def printCpuCacheInfo(self):
        if not self.cpuCacheInfo:
            return

        # add JSON stats #
        if SysMgr.jsonEnable:
            SysMgr.jsonData.setdefault("general", {})
            SysMgr.jsonData["general"]["cache"] = {}
            jsonData = SysMgr.jsonData["general"]["cache"]

        SysMgr.infoBufferPrint("\n[System CPU Cache Info]")
        SysMgr.infoBufferPrint(twoLine)
        SysMgr.infoBufferPrint("{0:^20} {1:100}".format("Core", "Information"))
        SysMgr.infoBufferPrint(twoLine)

        cnt = 0
        try:
            for core, info in sorted(
                self.cpuCacheInfo.items(), key=lambda e: long(e[0][3:])
            ):
                try:
                    SysMgr.infoBufferPrint(
                        "{0:^20} {1:<100}".format(core[3:], info.strip())
                    )
                    cnt += 1

                    if SysMgr.jsonEnable:
                        jsonData[core[3:]] = info.strip()
                except:
                    pass
        except:
            pass

        if cnt == 0:
            SysMgr.infoBufferPrint("{0:^16}".format("None"))

        SysMgr.infoBufferPrint(twoLine)

    def printCpuInfo(self):
        if not self.cpuData:
            return

        # parse data #
        for l in self.cpuData:
            m = re.match(r"(?P<type>.*):\s+(?P<val>.*)", l)
            if not m:
                continue

            d = m.groupdict()
            self.cpuInfo[d["type"][0 : len(d["type"]) - 1]] = d["val"]

        # add JSON stats #
        if SysMgr.jsonEnable:
            SysMgr.jsonData.setdefault("general", {})
            SysMgr.jsonData["general"]["cpu"] = {}
            jsonData = SysMgr.jsonData["general"]["cpu"]

        SysMgr.infoBufferPrint("\n[System CPU Info]")
        SysMgr.infoBufferPrint(twoLine)
        SysMgr.infoBufferPrint("{0:^20} {1:100}".format("Type", "Information"))
        SysMgr.infoBufferPrint(twoLine)

        try:
            physical = long(self.cpuInfo["physical id"]) + 1
            SysMgr.infoBufferPrint(
                "{0:20} {1:<100}".format("Physical", physical)
            )

            if SysMgr.jsonEnable:
                jsonData["physical"] = physical
        except:
            pass

        try:
            SysMgr.infoBufferPrint(
                "{0:20} {1:<100}".format(
                    "CoresPerCPU", self.cpuInfo["cpu cores"]
                )
            )

            if SysMgr.jsonEnable:
                jsonData["corePerCPU"] = self.cpuInfo["cpu cores"]
        except:
            pass

        try:
            logical = long(self.cpuInfo["processor"]) + 1
            SysMgr.infoBufferPrint(
                "{0:20} {1:<100}".format("Logical", logical)
            )

            if SysMgr.jsonEnable:
                jsonData["logical"] = logical
        except:
            pass

        try:
            SysMgr.infoBufferPrint(
                "{0:20} {1:<100}".format("Vendor", self.cpuInfo["vendor_id"])
            )

            if SysMgr.jsonEnable:
                jsonData["vendor"] = self.cpuInfo["vendor_id"]
        except:
            pass

        try:
            SysMgr.infoBufferPrint(
                "{0:20} {1:<100}".format("Model", self.cpuInfo["model name"])
            )

            if SysMgr.jsonEnable:
                jsonData["model"] = self.cpuInfo["model name"]
        except:
            pass

        try:
            SysMgr.infoBufferPrint(
                "{0:20} {1:<100}".format(
                    "Cache(L2)", self.cpuInfo["cache size"]
                )
            )

            if SysMgr.jsonEnable:
                jsonData["cacheL2"] = self.cpuInfo["cache size"]
        except:
            pass

        try:
            SysMgr.infoBufferPrint(
                "{0:20} {1:<100}".format("Perf", self.cpuInfo["bogomips"])
            )

            if SysMgr.jsonEnable:
                jsonData["perf"] = self.cpuInfo["bogomips"]
        except:
            pass

        try:
            SysMgr.infoBufferPrint(
                "{0:20} {1:<100}".format(
                    "Address", self.cpuInfo["address sizes"]
                )
            )

            if SysMgr.jsonEnable:
                jsonData["address"] = self.cpuInfo["address sizes"]
        except:
            pass

        # oneline #
        for item in ["online", "possible", "present"]:
            try:
                with open("/sys/devices/system/cpu/%s" % item, "r") as fd:
                    data = fd.readline().strip()

                SysMgr.infoBufferPrint(
                    "{0:20} {1:<100}".format(item.title(), data)
                )

                if SysMgr.jsonEnable:
                    jsonData[item] = data
            except:
                pass

        SysMgr.infoBufferPrint(twoLine)

    def updateDiskInfo(self, time, data):
        self.diskInfo[time] = {}

        if not SysMgr.isLinux:
            return
        elif not data:
            return

        for l in data:
            values = l.split()

            diskStat = {}
            for idx, item in enumerate(list(l.split())):
                if len(ConfigMgr.DISKSTAT) <= idx:
                    SysMgr.printWarn(
                        "failed to parse all diskstat because of overflow"
                    )
                    break
                else:
                    diskStat[ConfigMgr.DISKSTAT[idx]] = item

            self.diskInfo[time][diskStat["name"]] = {}
            diskInfoBuf = self.diskInfo[time][diskStat["name"]]

            # save recent stat #
            diskInfoBuf["major"] = diskStat["major"]
            diskInfoBuf["minor"] = diskStat["minor"]
            diskInfoBuf["sectorRead"] = diskStat["sectorRead"]
            diskInfoBuf["readTime"] = diskStat["readTime"]
            diskInfoBuf["sectorWrite"] = diskStat["sectorWrite"]
            diskInfoBuf["writeTime"] = diskStat["writeTime"]
            diskInfoBuf["currentIO"] = diskStat["currentIO"]
            diskInfoBuf["ioTime"] = diskStat["ioTime"]
            diskInfoBuf["ioWTime"] = diskStat["ioWTime"]

    def updateMountInfo(self):
        if not SysMgr.isLinux:
            return
        elif not self.mountData:
            return

        class MountException(Exception):
            pass

        rootdevPath = SysMgr.getRootDevice()

        if self.mountUpdated:
            # parse mount info #
            for l in self.mountData:
                # leave for /proc/mounts #
                # dev, path, fs, option, etc1, etc2 = l.split()

                # split mount info #
                values = l.split(" - ")
                if len(values) != 2:
                    continue
                left = values[0]
                right = values[1]

                # split left-side part #
                left = left.split()
                mountid, parentid, devid, root, path = left[:5]
                major, minor = devid.split(":")
                option = " ".join(left[5:-1])

                # split right-side part #
                right = right.split()
                fs, dev = right[0:2]
                soption = " ".join(right[2:])

                # convert root device path #
                if dev == "/dev/root" and rootdevPath:
                    dev = rootdevPath

                # check skip condition #
                try:
                    # special device #
                    if not dev.startswith("/"):
                        rpath = path
                    else:
                        rpath = os.path.realpath(dev)
                        dev = os.path.basename(rpath)

                    if fs == "tmpfs":
                        raise MountException
                        continue

                    if ":" in dev:
                        major, minor = dev.split(":")
                        for mp in self.diskInfo["prev"].values():
                            if mp["major"] == major and mp["minor"] == minor:
                                raise MountException

                    # check nodes by device ID #
                    if not dev in self.diskInfo["prev"]:
                        for node, attr in self.diskInfo["prev"].items():
                            if (
                                attr["major"] == major
                                and attr["minor"] == minor
                            ):
                                raise MountException
                        continue
                except MountException:
                    pass
                except:
                    continue

                # save mount info #
                self.mountInfo[rpath] = {
                    "major": major,
                    "minor": minor,
                    "mountid": mountid,
                    "path": path,
                    "fs": fs,
                    "option": option,
                    "soption": soption,
                }

        for name, subdir in self.devArchInfo.items():
            for node, devid in subdir.items():
                if node in self.mountInfo:
                    continue

                major, minor = devid.strip().split(":")

                # save mount info #
                self.mountInfo[node] = {
                    "major": major,
                    "minor": minor,
                    "mountid": "-1",
                    "path": "-",
                    "fs": "-",
                    "option": "",
                    "soption": "",
                }

    def updateShmInfo(self):
        if not SysMgr.isLinux:
            return

        # read shm buf #
        try:
            data = SysMgr.readProcStat(
                SysMgr.shmFd, "sysvipc/shm", SysMgr, "shmFd"
            )[1:]
        except SystemExit:
            sys.exit(0)
        except:
            return

        # backup shm data #
        try:
            self.prevIpcData["shm"] = self.ipcData["shm"]
        except:
            pass

        # initialize shm variable #
        self.ipcData["shm"] = {}

        # parse new shm data #
        for line in data:
            try:
                (
                    key,
                    shmid,
                    perms,
                    size,
                    cpid,
                    lpid,
                    nattch,
                    uid,
                    gid,
                    cuid,
                    cgid,
                    atime,
                    dtime,
                    ctime,
                    rss,
                    swap,
                ) = line.split()[:16]
            except SystemExit:
                sys.exit(0)
            except:
                continue

            if key == "key":
                continue

            shmData = self.ipcData["shm"][shmid] = {}
            shmData["key"] = key
            shmData["perms"] = perms
            shmData["size"] = long(size)
            shmData["rss"] = long(rss)
            shmData["swap"] = long(swap)
            shmData["uid"] = uid
            shmData["gid"] = gid
            shmData["cpid"] = cpid
            shmData["lpid"] = lpid
            shmData["nattch"] = nattch
            shmData["atime"] = dtime
            shmData["dtime"] = dtime
            shmData["ctime"] = ctime

    def updateMsgqInfo(self):
        if not SysMgr.isLinux:
            return

        # read msgq buf #
        try:
            data = SysMgr.readProcStat(
                SysMgr.msgqFd, "sysvipc/msg", SysMgr, "msgqFd"
            )[1:]
        except SystemExit:
            sys.exit(0)
        except:
            return

        # backup msgq data #
        try:
            self.prevIpcData["msgq"] = self.ipcData["msgq"]
        except:
            pass

        # initialize msgq variable #
        self.ipcData["msgq"] = {}

        # parse new msgq data #
        for line in data:
            try:
                (
                    key,
                    msgqid,
                    perms,
                    cbytes,
                    qnum,
                    lspid,
                    lrpid,
                    uid,
                    gid,
                    cuid,
                    cgid,
                    stime,
                    rtime,
                    ctime,
                ) = line.split()
            except:
                pass

            msgqData = self.ipcData["msgq"][msgqid] = {}
            msgqData["key"] = key
            msgqData["perms"] = perms
            msgqData["cbytes"] = cbytes
            msgqData["qnum"] = qnum
            msgqData["lspid"] = lspid
            msgqData["lrpid"] = lrpid
            msgqData["uid"] = uid
            msgqData["gid"] = gid
            msgqData["cuid"] = cuid
            msgqData["cgid"] = cgid
            msgqData["stime"] = stime
            msgqData["rtime"] = rtime
            msgqData["ctime"] = ctime

    def updateSemInfo(self):
        if not SysMgr.isLinux:
            return

        # read sem buf #
        try:
            data = SysMgr.readProcStat(
                SysMgr.semFd, "sysvipc/sem", SysMgr, "semFd"
            )[1:]
        except SystemExit:
            sys.exit(0)
        except:
            return

        # backup sem data #
        try:
            self.prevIpcData["sem"] = self.ipcData["sem"]
        except:
            pass

        # initialize sem variable #
        self.ipcData["sem"] = {}

        # parse new sem data #
        for line in data:
            try:
                (
                    key,
                    semid,
                    perms,
                    nsems,
                    uid,
                    gid,
                    cuid,
                    cgid,
                    otime,
                    ctime,
                ) = line.split()
            except:
                pass

            semData = self.ipcData["sem"][semid] = {}
            semData["key"] = key
            semData["perms"] = perms
            semData["nsems"] = nsems
            semData["uid"] = uid
            semData["gid"] = gid
            semData["cuid"] = cuid
            semData["cgid"] = cgid
            semData["otime"] = otime
            semData["ctime"] = ctime

    def saveMacAddr(self):
        if not SysMgr.isLinux:
            return
        elif self.macAddr:
            return

        # mac address #
        try:
            self.macAddr = NetworkMgr.getMainMacAddr()
        except SystemExit:
            sys.exit(0)
        except:
            pass

    def updateIPCInfo(self):
        if not SysMgr.isLinux:
            return

        # check update time #
        if self.ipcUpdate == SysMgr.uptime:
            return
        else:
            self.ipcUpdate = SysMgr.uptime

        # shared memory #
        self.updateShmInfo()

        # message queue #
        self.updateMsgqInfo()

        # semaphore #
        self.updateSemInfo()

    def updateNetworkInfoGen(self):
        # get psutil object #
        psutil = SysMgr.getPkg("psutil")

        try:
            # netConn = psutil.net_connections(kind='inet')
            # nicStat = psutil.net_if_stats()

            # define new device list #
            devList = []

            # get IP address for device #
            addrList = psutil.net_if_addrs()
            for dev, addrItems in addrList.items():
                for item in addrItems:
                    if not item or not item[0]:
                        continue
                    elif len(addrItems) > 1 and not "AF_INET" in str(item[0]):
                        continue
                    elif dev in devList:
                        continue

                    # update ip address #
                    devList.append(dev)
                    self.networkInfo.setdefault(dev, {})
                    family, addr, mask, broadcast, ptp = item
                    self.networkInfo[dev]["ipaddr"] = addr

            # remove devices #
            for dev in list(self.networkInfo):
                if not dev in devList:
                    self.networkInfo.pop(dev, None)

            statData = [0, 0, 0, 0, 0, 0, 0, 0]

            # get stats for device #
            statList = psutil.net_io_counters(pernic=True, nowrap=True)
            for dev, value in statList.items():
                if not dev in self.networkInfo:
                    continue

                (
                    tsize,
                    rsize,
                    tpacket,
                    rpacket,
                    rerr,
                    terr,
                    rdrop,
                    tdrop,
                ) = value

                # update recv #
                if "recv" in self.networkInfo[dev]:
                    rvalue = self.networkInfo[dev]["recv"]
                    self.networkInfo[dev]["rdiff"] = [
                        rsize - rvalue[0],
                        rpacket - rvalue[1],
                        rerr - rvalue[2],
                        rdrop - rvalue[3],
                        0,
                        0,
                        0,
                        0,
                    ]
                else:
                    self.networkInfo[dev]["rdiff"] = statData

                self.networkInfo[dev]["recv"] = [
                    rsize,
                    rpacket,
                    rerr,
                    rdrop,
                    0,
                    0,
                    0,
                    0,
                ]

                # update tran #
                if "tran" in self.networkInfo[dev]:
                    tvalue = self.networkInfo[dev]["tran"]
                    self.networkInfo[dev]["tdiff"] = [
                        tsize - tvalue[0],
                        tpacket - tvalue[1],
                        terr - tvalue[2],
                        tdrop - tvalue[3],
                        0,
                        0,
                        0,
                        0,
                    ]
                else:
                    self.networkInfo[dev]["tdiff"] = statData

                self.networkInfo[dev]["tran"] = [
                    tsize,
                    tpacket,
                    terr,
                    tdrop,
                    0,
                    0,
                    0,
                    0,
                ]
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("failed to get general network info", reason=True)
            return

    def updateNetworkInfo(self):
        if not SysMgr.isLinux:
            return

        # check update time #
        if (
            self.netUpdate
            and SysMgr.uptime - self.netUpdate < SysMgr.intervalEnable
        ):
            return
        else:
            self.netUpdate = SysMgr.uptime

        # get device data #
        data = SysMgr.getNetDevData()
        if not data:
            return

        # import packages #
        try:
            socket = SysMgr.getPkg("socket", False)
            fcntl = SysMgr.getPkg("fcntl", False)
        except SystemExit:
            sys.exit(0)
        except:
            socket = fcntl = None

        try:
            for line in data:
                dev, stats = line.split(":")

                dev = dev.strip()

                self.networkInfo.setdefault(dev, {})

                # set IP addr #
                try:
                    if not SysMgr.localServObj:
                        NetworkMgr.setServerNetwork(
                            None, None, reuse=False, weakPort=True
                        )

                    sockObj = SysMgr.localServObj

                    res = fcntl.ioctl(
                        sockObj.socket.fileno(),
                        0x8915,  # SIOCGIFADDR
                        struct.pack("256s", dev[:15].encode("utf-8")),
                    )
                    ipaddr = socket.inet_ntoa(res[20:24])
                except SystemExit:
                    sys.exit(0)
                except:
                    ipaddr = ""

                self.networkInfo[dev]["ipaddr"] = ipaddr

                stats = stats.split()
                """
                bytes, packets, errs, drop, fifo,
                    frame, compressed, multicast
                """

                nrdvd = long(len(stats) / 2)

                # Receive #
                rlist = list(map(long, stats[:nrdvd]))

                if "recv" in self.networkInfo[dev]:
                    self.networkInfo[dev]["rdiff"] = []

                    for idx, val in enumerate(rlist):
                        if SysMgr.totalEnable:
                            rdiff = val
                        else:
                            rdiff = val - self.networkInfo[dev]["recv"][idx]
                        self.networkInfo[dev]["rdiff"].append(rdiff)
                else:
                    self.networkInfo[dev]["initrecv"] = rlist

                self.networkInfo[dev]["recv"] = rlist

                # Transmit #
                tlist = list(map(long, stats[nrdvd:]))

                if "tran" in self.networkInfo[dev]:
                    self.networkInfo[dev]["tdiff"] = []

                    for idx, val in enumerate(tlist):
                        if SysMgr.totalEnable:
                            tdiff = val
                        else:
                            tdiff = val - self.networkInfo[dev]["tran"][idx]
                        self.networkInfo[dev]["tdiff"].append(tdiff)
                else:
                    self.networkInfo[dev]["inittran"] = tlist

                self.networkInfo[dev]["tran"] = tlist
        except SystemExit:
            sys.exit(0)
        except:
            return

    def saveLimitInfo(self):
        if self.limitData:
            return
        else:
            self.limitData = SysMgr.readProcData("self", "limits")

    def saveOpenFileInfo(self):
        if self.openFileData:
            return

        # get fd status #
        stats = SysMgr.getNrSysFdHandle()
        if not stats:
            return

        self.openFileData["cur"] = stats[0]
        self.openFileData["max"] = stats[2]

    def saveUnameInfo(self):
        if self.uname:
            return

        try:
            self.uname = os.uname()
        except:
            pass

    def saveUserInfo(self):
        # check user data #
        if self.userData or SysMgr.isAndroid:
            return

        # get data #
        try:
            path = "/etc/passwd"
            with open(path, "rb") as fd:
                data = fd.readlines()
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenWarn(path)
            return

        # parse data #
        for line in data:
            try:
                user, passwd, uid, gid, info, home, shell = (
                    line.rstrip().decode().split(":")[:7]
                )

                self.userData[uid] = {
                    "name": user,
                    "gid": gid,
                    "info": info,
                    "home": home,
                    "shell": shell,
                }
            except SystemExit:
                sys.exit(0)
            except:
                pass

    def getStorageMapInfo(self):
        if not SysMgr.isDarwin and not SysMgr.isWindows:
            return {}

        # get subprocess object #
        subprocess = SysMgr.getPkg("subprocess")

        if SysMgr.isDarwin:
            command = ["diskutil", "list"]
            shell = False
        elif "PATH" in os.environ:
            # find powershell path #
            powershellPath = None
            for item in os.environ["PATH"].split(";"):
                if "WindowsPowerShell" in item:
                    powershellPath = "%s/powershell.exe" % item
                    break
            if not powershellPath:
                return

            command = [powershellPath, "get-partition"]
            shell = True
        else:
            shell = False

        # start diskutil process #
        try:
            proc = subprocess.Popen(
                command,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                bufsize=-1,
                shell=shell,
            )
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to execute '%s'" % " ".join(command), reason=True
            )
            sys.exit(-1)

        mapTable = {}
        path = None
        node = None
        prev = None
        devnum = -1

        while 1:
            try:
                # read a line from diskutil process #
                line = proc.stdout.readline()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "failed to read from '%s'" % " ".join(command), reason=True
                )
                sys.exit(-1)

            # handle error #
            if not line:
                err = proc.stderr.read()
                if err:
                    try:
                        proc.terminate()
                    except:
                        pass

                    SysMgr.printErr(err[err.find(":") + 2 :])
                    sys.exit(-1)
                break

            # decode data #
            try:
                line = line.decode()
            except SystemExit:
                sys.exit(0)
            except:
                pass

            # MacOS #
            if SysMgr.isDarwin:
                # disk node #
                if line.startswith("/"):
                    path, attr = line.split(" ", 1)
                    continue

                line = line.strip()
                if not line:
                    continue
                elif line[0].isdigit():
                    prev = node
                    node = "/dev/%s" % line.split()[-1]
                    mapTable[node] = path
                elif line.startswith("Physical Store "):
                    # change previous map info #
                    prevValue = mapTable[node]
                    mapTable.pop(node, None)
                    path = "/dev/%s" % line.split()[-1]
                    mapTable[node] = path
                    path = node

                    # update new physical path #
                    while 1:
                        try:
                            if path == mapTable[path]:
                                break
                            else:
                                path = mapTable[path]
                        except:
                            break
                else:
                    continue
            # Windows #
            else:
                line = line.strip()
                if not line:
                    continue
                elif line.startswith("PartitionNumber"):
                    devnum += 1
                    continue
                elif line[0].isdigit():
                    items = line.split()
                    # drive #
                    if items[1].isalpha():
                        node = "%s:\\" % items[1]
                        path = "PhysicalDrive%s" % devnum
                    else:
                        continue

            # check values #
            if not node or not path:
                continue

            mapTable[node] = path

        return mapTable

    def updateStorageInfoGen(self):
        # get psutil object #
        psutil = SysMgr.getPkg("psutil")

        self.prevStorageData = self.storageData
        self.storageData = {}

        try:
            # mount #
            partition = psutil.disk_partitions(all=True)
            for item in partition:
                dev, path, fs, opts, maxfile, maxpath = item
                self.storageData.setdefault(dev, {})
                self.storageData[dev]["mount"] = {
                    "fs": fs,
                    "path": path,
                    "option": opts,
                }

            # usage #
            for dev in list(self.storageData):
                try:
                    target = self.storageData[dev]
                    path = target["mount"]["path"]
                    total, used, free, per = psutil.disk_usage(path=path)
                    target["total"] = total >> 20
                    target["free"] = free >> 20
                    target["usagePer"] = long(per)
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printWarn(
                        "failed to get disk usage for '%s'" % path, reason=True
                    )

            # stat #
            stats = psutil.disk_io_counters(perdisk=True, nowrap=True)
            if not stats:
                SysMgr.printWarn("failed to get disk stats")
                return

            # get logical to physical disk map table #
            if not self.storageMapData:
                self.storageMapData = self.getStorageMapInfo()
            mapTable = self.storageMapData

            for dev in list(self.storageData):
                try:
                    # get physical device path #
                    if dev in mapTable:
                        if SysMgr.isWindows:
                            rpath = mapTable[dev]
                        else:
                            rpath = mapTable[dev].split("/")[-1]
                    else:
                        continue

                    # apply stat #
                    value = stats[rpath]
                    target = self.storageData[dev]
                    target["read"] = value[2] >> 20
                    target["write"] = value[3] >> 20
                    target["readtime"] = value[4]
                    target["writetime"] = value[5]
                except SystemExit:
                    sys.exit(0)
                except:
                    # reset map table #
                    self.storageMapData = {}

                    SysMgr.printWarn(
                        "failed to get disk stat for '%s'" % dev, reason=True
                    )
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("failed to get general storage info", reason=True)
            return

    def updateStorageInfo(self, isGeneral=False):
        if not SysMgr.isLinux:
            return

        # check update time #
        if (
            self.storageUpdate
            and SysMgr.uptime - self.storageUpdate < SysMgr.intervalEnable
        ):
            return
        else:
            self.storageUpdate = SysMgr.uptime

        # get device type #
        self.saveDevInfo()

        # get storage info and update stat #
        self.saveStorageInfo(isGeneral)

        # get mount info #
        self.updateMountInfo()

        # get storage stat #
        self.prevStorageData = self.storageData
        self.storageData = self.getStorageInfo()

    def getStorageInfo(self):
        storageData = {}
        init_storageData = {
            "total": 0,
            "free": 0,
            "favail": 0,
            "read": 0,
            "write": 0,
            "usage": 0,
            "usagePer": 0,
            "mount": None,
        }

        storageData["total"] = dict(init_storageData)

        # make block device table #
        for key, val in sorted(self.mountInfo.items(), key=lambda e: e[0]):
            # check device node path #
            if key[0] != "/":
                continue

            storageData[key] = dict(init_storageData)
            storageData[key]["mount"] = val

            # calculate read & write load of devices #
            try:
                # get node name from full-path #
                dev = key[key.rfind("/") + 1 :]

                # update node name #
                if ":" in dev:
                    major, minor = dev.split(":")
                    for name, mp in self.diskInfo["prev"].items():
                        if mp["major"] == major and mp["minor"] == minor:
                            dev = name

                # define shortcut variables for this device info #
                beforeInfo = self.diskInfo["prev"][dev]
                afterInfo = self.diskInfo["next"][dev]

                # get interval I/O of this device #
                if SysMgr.totalEnable:
                    read = long(afterInfo["sectorRead"]) >> 11

                    write = long(afterInfo["sectorWrite"]) >> 11
                else:
                    read = (
                        long(afterInfo["sectorRead"])
                        - long(beforeInfo["sectorRead"])
                    ) >> 11

                    write = (
                        long(afterInfo["sectorWrite"])
                        - long(beforeInfo["sectorWrite"])
                    ) >> 11

                load = long(afterInfo["sectorRead"]) + long(
                    afterInfo["sectorWrite"]
                )

                readtime = long(afterInfo["readTime"])
                writetime = long(afterInfo["writeTime"])
                iotime = long(afterInfo["ioTime"])
                iowtime = long(afterInfo["ioWTime"])

                # save recent stats #
                storageData[key]["read"] = read
                storageData[key]["write"] = write
                storageData[key]["load"] = load
                storageData[key]["readtime"] = readtime
                storageData[key]["writetime"] = writetime
                storageData[key]["iotime"] = iotime
                storageData[key]["iowtime"] = iowtime

                if val["fs"] != "tmpfs":
                    storageData["total"]["read"] += read
                    storageData["total"]["write"] += write
            except:
                pass

            # get device stats #
            try:
                if hasattr(os, "statvfs"):
                    stat = os.statvfs(val["path"])
                else:
                    stat = SysMgr.statvfs(val["path"])

                total = (stat.f_bsize * stat.f_blocks) >> 20
                free = (stat.f_bsize * stat.f_bavail) >> 20

                if hasattr(stat, "f_favail"):
                    avail = stat.f_favail
                else:
                    avail = 0

                usage = long((total - free) / float(total) * 100)

                storageData[key]["total"] = total
                storageData[key]["free"] = free
                storageData[key]["usage"] = total - free
                storageData[key]["usagePer"] = usage
                storageData[key]["favail"] = avail

                if val["fs"] != "tmpfs":
                    storageData["total"]["total"] += total
                    storageData["total"]["free"] += free
                    storageData["total"]["favail"] += avail
            except:
                pass

        # set total storage stat #
        try:
            total = storageData["total"]
            storageData["total"]["usage"] = total["total"] - total["free"]
            storageData["total"]["usagePer"] = long(
                (total["total"] - total["free"]) / float(total["total"]) * 100
            )
        except:
            pass

        return storageData

    def getCgroupPath(self):
        if SysMgr.cgroupPath:
            return SysMgr.cgroupPath

        if not self.mountData:
            # update mount data #
            self.mountData = SysMgr.getMountData()

        # check mount path again #
        if not self.mountData:
            return None

        # search cgroup mount point #
        for mount in self.mountData:
            mountList = mount.split(" - ")

            if not mountList[1].startswith("cgroup"):
                continue

            mountpath = mountList[0].split()[4]

            # return cgroup mount point #
            path = mountpath[: mountpath.rfind("/")]
            SysMgr.cgroupPath = path
            return path

        return None

    def getCgroupTree(self):
        def _updateValues(dirpath, subfiles, item):
            for target in subfiles:
                if not target in ConfigMgr.CGROUP_VALUE:
                    continue

                try:
                    path = "%s/%s" % (dirpath, target)
                    with open(path, "r") as fd:
                        if target == "tasks" or target == "cgroup.procs":
                            taskList = fd.read().splitlines()
                            item[target] = UtilMgr.convNum(len(taskList))
                            if (
                                SysMgr.showAll
                                and len(taskList) > 0
                                and target == "cgroup.procs"
                            ):
                                item["PROCS"] = dict.fromkeys(taskList, {})
                        else:
                            cval = fd.readline()[:-1]
                            if cval.isdigit():
                                cval = UtilMgr.convNum(long(cval))
                            elif cval == "":
                                cval = "none"
                            item[target] = cval
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

        def _getPaths(root, path):
            for dirpath, subdirs, subfiles in path:
                # update subdir #
                for item in subdirs:
                    subdir = os.path.join(dirpath, item)
                    root[subdir] = {}

                # update subfiles #
                for item in subfiles:
                    subfile = os.path.join(dirpath, item)

                    # check value file #
                    if not item in ConfigMgr.CGROUP_VALUE:
                        continue

                    root.setdefault(dirpath, {})
                    _updateValues(dirpath, subfiles, root[dirpath])

        # get cgroup path #
        cgroupPath = self.getCgroupPath()
        if not cgroupPath:
            return None

        # get full path list #
        dirList = {}
        _getPaths(dirList, os.walk(cgroupPath))

        # split a path to multiple tokens #
        dirDict = {}
        for item, val in dirList.items():
            # skip symbolic link #
            if os.path.islink(item):
                continue

            p = dirDict
            tokList = item[len(cgroupPath) :].split("/")[1:]
            for x in tokList:
                p = p.setdefault(x, {})

            # merge with a value #
            p.update(val)

        return dirDict

    def printCgroupInfo(self, printTitle=True):
        commList = {}

        def _printDirTree(root, depth, total=0):
            # check depth #
            if SysMgr.funcDepth > 0 and SysMgr.funcDepth <= depth:
                return

            # check type #
            if type(root) is not dict:
                return

            tempRoot = UtilMgr.deepcopy(root)

            # calculate sum for subdirs #
            newTotal = 0
            for curdir, subdir in tempRoot.items():
                if not "cpu.shares" in subdir:
                    continue

                for parent, children in subdir.items():
                    if type(children) is not dict:
                        continue
                    if "cpu.shares" in children:
                        value = children["cpu.shares"].replace(",", "")
                        newTotal += long(value)

            # traverse subdir #
            for curdir, subdir in sorted(
                tempRoot.items(),
                key=lambda e: long(e[0]) if e[0].isdigit() else 0,
            ):
                cstr = ""
                nrProcs = 0
                nrTasks = 0

                # check subdir type #
                if type(subdir) is not dict:
                    continue

                tempSubdir = UtilMgr.deepcopy(subdir)
                for val in list(subdir):
                    if not val in ConfigMgr.CGROUP_VALUE:
                        continue
                    elif val == "tasks":
                        nrTasks = subdir[val]
                        tempSubdir.pop(val, None)
                        continue
                    elif val == "cgroup.procs":
                        nrProcs = subdir[val]
                        tempSubdir.pop(val, None)
                        continue
                    elif val == "cpu.shares" and total > 0:
                        num = long(subdir[val].replace(",", ""))
                        per = "%.1f" % (num / float(total) * 100)
                        if num > 0:
                            per = UtilMgr.convColor(per, "RED")
                        value = "%s/%s%%" % (subdir[val], per)
                    elif val.endswith("limit_in_bytes"):
                        num = long(subdir[val].replace(",", ""))
                        value = UtilMgr.convSize2Unit(num)
                        if num < 9223372036854771712:
                            value = UtilMgr.convColor(value, "RED")
                    else:
                        value = subdir[val]

                    cname = ".".join(val.split(".")[1:])
                    cstr = "%s%s:%s, " % (cstr, cname, value)
                    tempSubdir.pop(val, None)

                indent = ""
                if depth == 0:
                    indent = "\n"

                for _ in xrange(depth):
                    indent = "%s%s|" % (indent, "     ")

                if cstr:
                    cstr = " <%s>" % cstr[:-2]

                # define worker info #
                if not nrProcs in ("0", 0):
                    procstr = UtilMgr.convColor(nrProcs, "YELLOW")
                else:
                    procstr = nrProcs
                if not nrTasks in ("0", 0):
                    taskstr = UtilMgr.convColor(nrTasks, "CYAN")
                else:
                    taskstr = nrTasks
                nrWorker = " (proc:%s/task:%s)" % (procstr, taskstr)

                # highlight subsystem name #
                if depth == 0:
                    curdir = UtilMgr.convColor(curdir, "GREEN")

                # parent node #
                if tempSubdir:
                    nrChild = "[sub:%s]" % len(tempSubdir)

                    if curdir == "PROCS":
                        nrWorker = ""

                    SysMgr.infoBufferPrint(
                        "%s- %s%s%s%s"
                        % (indent, curdir, nrChild, nrWorker, cstr)
                    )
                # process node #
                elif depth > 0 and nrProcs == nrTasks == 0:
                    if curdir in commList:
                        comm = commList[curdir]
                    else:
                        comm = commList[curdir] = SysMgr.getComm(
                            curdir, save=True
                        )

                    # filter process #
                    if UtilMgr.isValidStr(comm, ignCap=True):
                        SysMgr.infoBufferPrint(
                            "%s- %s(%s)" % (indent, comm, curdir)
                        )
                # leap node #
                else:
                    SysMgr.infoBufferPrint(
                        "%s- %s%s%s" % (indent, curdir, nrWorker, cstr)
                    )

                _printDirTree(tempSubdir, depth + 1, newTotal)

            if depth == 0:
                SysMgr.infoBufferPrint(" ")

        # check cgroup option #
        if not SysMgr.cgroupEnable:
            return

        try:
            cgroupTree = self.getCgroupTree()
            if not cgroupTree:
                return
        except SystemExit:
            sys.exit(0)
        except:
            return

        # print cgroup info #
        if printTitle:
            SysMgr.infoBufferPrint("\n[System Cgroup Info]")
            SysMgr.infoBufferPrint(twoLine)

        # filter cgroup subsystem #
        if SysMgr.hasMainArg():
            # get filter for subsystems #
            items = SysMgr.getMainArgs()

            # remove subsystems from tree #
            for subsystem in list(cgroupTree):
                if not UtilMgr.isValidStr(subsystem, key=items, ignCap=True):
                    cgroupTree.pop(subsystem, None)

        # print cgroup tree #
        _printDirTree(cgroupTree, 0)

        # check result #
        if not SysMgr.systemInfoBuffer.strip():
            SysMgr.printErr("no cgroup info")
            sys.exit(-1)

        # append last line #
        if printTitle:
            SysMgr.infoBufferPrint(twoLine)

        # add JSON stats #
        if SysMgr.jsonEnable:
            SysMgr.jsonData.setdefault("general", {})
            SysMgr.jsonData["general"]["cgroup"] = cgroupTree

    def printIPCInfo(self):
        self.printShmInfo()
        self.printMsgqInfo()
        self.printSemInfo()

    def printShmInfo(self):
        # check shm data #
        if not "shm" in self.ipcData:
            return

        # print IPC info #
        SysMgr.infoBufferPrint("\n[System SHM Info]")
        SysMgr.infoBufferPrint(twoLine)
        SysMgr.infoBufferPrint(
            "{0:^66} | {1:^24} | {2:^15} | {3:^36} ".format(
                "ID", "Segment", "Attr", "Time"
            )
        )
        SysMgr.infoBufferPrint(oneLine)
        SysMgr.infoBufferPrint(
            (
                "{0:^26}   {1:^8}   {2:^26} | "
                "{3:>6}   {4:>6}   {5:>6} | "
                "{6:>6}   {7:>6} | {8:>11}   {9:>11}   {10:>11}".format(
                    "OWNER",
                    "SHM",
                    "USER",
                    "SIZE",
                    "RSS",
                    "SWAP",
                    "REF",
                    "PERM",
                    "ATIME",
                    "DTIME",
                    "CTIME",
                )
            )
        )
        SysMgr.infoBufferPrint(twoLine)

        # get attr #
        cnt = 0
        prevOwner = None
        now = time.mktime(time.gmtime())
        convertSizeFunc = UtilMgr.convSize2Unit
        convTimeFunc = UtilMgr.convTime

        # merge stats per-owner #
        ownerData = {}
        for shmid, stats in self.ipcData["shm"].items():
            try:
                owner = stats["cpid"]

                ownerData[owner]["count"] += 1
                ownerData[owner]["size"] += stats["size"]
                ownerData[owner]["rss"] += stats["rss"]
                ownerData[owner]["swap"] += stats["swap"]
            except:
                ownerData[owner] = {}
                ownerData[owner]["uid"] = stats["uid"]
                ownerData[owner]["count"] = 1
                ownerData[owner]["size"] = stats["size"]
                ownerData[owner]["rss"] = stats["rss"]
                ownerData[owner]["swap"] = stats["swap"]

        # print stats #
        for shmid, stats in sorted(
            self.ipcData["shm"].items(), key=lambda e: e[1]["cpid"]
        ):

            # get owner name #
            try:
                pid = stats["cpid"]

                if pid != prevOwner:
                    prevOwner = pid

                    comm = SysMgr.getComm(pid, save=True)
                    if not comm:
                        raise Exception("no comm")

                    owner = "%s(%s)" % (comm[:16], pid)
                else:
                    owner = ""
            except:
                owner = "? (%s)" % pid

            # print total stat #
            try:
                if not owner:
                    raise Exception("no owner")

                try:
                    user = self.userData[stats["uid"]]["name"]
                    owner = "%s[%s]" % (owner, user)
                except:
                    pass

                if cnt > 0:
                    SysMgr.infoBufferPrint(oneLine)

                totalStat = "[ TOTAL: %s ]" % ownerData[pid]["count"]
                space = 66 - len(owner) - len(totalStat)
                totalStr = "%s%s%s" % (owner, " " * space, totalStat)
                SysMgr.infoBufferPrint(
                    "{0:>40}   {1:>6}   {2:>6}   {3:>6}   {4:>15}".format(
                        totalStr,
                        convertSizeFunc(ownerData[pid]["size"], True),
                        convertSizeFunc(ownerData[pid]["rss"], True),
                        convertSizeFunc(ownerData[pid]["swap"], True),
                        " ",
                    )
                )
            except:
                pass

            # key #
            key = hex(long(stats["key"]))
            shmids = "%s(%s)" % (key, shmid)

            try:
                pid = stats["lpid"]
                comm = SysMgr.getComm(pid)
                if not comm:
                    raise Exception("no comm")

                access = "%s (%s)" % (comm[:16], pid)
            except:
                access = "? (%s)" % stats["lpid"]

            # get time #
            atime = now - time.mktime(time.gmtime(long(stats["atime"])))
            if atime < 0:
                atime = "?"
            dtime = now - time.mktime(time.gmtime(long(stats["dtime"])))
            if dtime < 0:
                dtime = "?"
            ctime = now - time.mktime(time.gmtime(long(stats["ctime"])))
            if ctime < 0:
                ctime = "?"

            # print stats #
            try:
                SysMgr.infoBufferPrint(
                    (
                        "{0:>37}   {1:>26}   {2:>6}   {3:>6}   "
                        "{4:>6}   {5:>6}   {6:>6}   {7:>11}   {8:>11}   "
                        "{9:>11}"
                    ).format(
                        shmids,
                        access,
                        convertSizeFunc(stats["size"], True),
                        convertSizeFunc(stats["rss"], True),
                        convertSizeFunc(stats["swap"], True),
                        stats["nattch"],
                        stats["perms"],
                        convTimeFunc(atime)[:10],
                        convTimeFunc(dtime)[:10],
                        convTimeFunc(ctime)[:10],
                    )
                )

                cnt += 1
            except:
                pass

        # check output count #
        if cnt == 0:
            SysMgr.infoBufferPrint("\tNone")

        SysMgr.infoBufferPrint(twoLine)

    def printSemInfo(self):
        pass

    def printMsgqInfo(self):
        pass

    def printGpuInfo(self):
        try:
            gpuInfo = SysMgr.getGpuInfo()
            if not gpuInfo:
                return None
        except:
            return None

        # add JSON stats #
        if SysMgr.jsonEnable:
            SysMgr.jsonData.setdefault("general", {})
            SysMgr.jsonData["general"]["gpu"] = {}
            jsonData = SysMgr.jsonData["general"]["gpu"]

        # print GPU info #
        SysMgr.infoBufferPrint("\n[System GPU Info]")
        SysMgr.infoBufferPrint(twoLine)
        SysMgr.infoBufferPrint(
            "{0:^32} | {1:^16} | {2:^32} |\n{3:1}".format(
                "Name", "Stat", "Value", oneLine
            )
        )

        for item in gpuInfo.values():
            name = item["name"]
            if SysMgr.jsonEnable:
                origName = name
                jsonData.setdefault(origName, {})

            for key, value in sorted(item.items()):
                if key == "name":
                    continue

                SysMgr.infoBufferPrint(
                    "{0:^32} | {1:>16} | {2:>32} |".format(name, key, value)
                )

                if SysMgr.jsonEnable:
                    jsonData[origName].setdefault(key, value)

                name = ""

            SysMgr.infoBufferPrint(oneLine)

    def printGpuMemInfo(self):
        # get per-process GPU memory info #
        gpuInfo = SysMgr.getGpuMem()
        if not gpuInfo:
            return

        # add JSON stats #
        if SysMgr.jsonEnable:
            SysMgr.jsonData.setdefault("general", {})
            SysMgr.jsonData["general"].setdefault("gpu", {})
            SysMgr.jsonData["general"].setdefault("gpumem", {})
            jsonData = SysMgr.jsonData["general"]["gpumem"]

        # print GPU Memory info #
        SysMgr.infoBufferPrint("\n[System GPU Memory Info]")
        SysMgr.infoBufferPrint(twoLine)
        SysMgr.infoBufferPrint(
            "{0:^32} | {1:^16} |\n{2:1}".format("Process", "Size", oneLine)
        )

        total = 0
        for pid, item in sorted(
            gpuInfo.items(), key=lambda e: e[1]["size"], reverse=True
        ):
            if pid == "0":
                continue

            # get size #
            size = item["size"]
            total += size

            # reconvert size to unit #
            size = UtilMgr.convSize2Unit(size)

            proc = "%s(%s)" % (item["comm"], pid)

            if SysMgr.jsonEnable:
                jsonData.setdefault(proc, size)

            SysMgr.infoBufferPrint("{0:>32} | {1:>16} |".format(proc, size))

        SysMgr.infoBufferPrint(
            "{2:1}\n{0:^32} | {1:>16} |".format(
                "TOTAL", UtilMgr.convSize2Unit(total), oneLine
            )
        )

        SysMgr.infoBufferPrint(oneLine)

    def printNetworkInfo(self):
        # add JSON stats #
        if SysMgr.jsonEnable:
            SysMgr.jsonData.setdefault("general", {})
            SysMgr.jsonData["general"]["network"] = {}
            jsonData = SysMgr.jsonData["general"]["network"]

        # print network info #
        SysMgr.infoBufferPrint("\n[System Network Info]")
        SysMgr.infoBufferPrint(twoLine)
        SysMgr.infoBufferPrint(
            "{0:^38} | {1:^45} | {2:^45}\n{3:1}".format(
                "Network", "Receive", "Transfer", oneLine
            )
        )
        SysMgr.infoBufferPrint(
            (
                "{0:^16} {1:^21} | "
                "{2:^8} {3:^8} {4:^8} {5:^8} {6:^9} | "
                "{2:^8} {3:^8} {4:^8} {5:^8} {6:^9}"
            ).format(
                "Dev", "TYPE", "Size", "Packet", "Error", "Drop", "Multicast"
            )
        )
        SysMgr.infoBufferPrint(twoLine)

        convSize = UtilMgr.convSize2Unit

        cnt = 1
        totalStat = {
            "rdiff": [0] * 5,
            "tdiff": [0] * 5,
            "rtotal": [0] * 5,
            "ttotal": [0] * 5,
        }

        for dev, val in sorted(self.networkInfo.items(), key=lambda e: e[0]):
            try:
                """
                [ network stat sequence ]
                bytes, packets, errs, drop, fifo,
                    frame, compressed, multicast
                """

                # recv diff #
                rdiff = []
                for idx, stat in enumerate(val["recv"]):
                    rdiff.append(stat - val["initrecv"][idx])

                # tran diff #
                tdiff = []
                for idx, stat in enumerate(val["tran"]):
                    tdiff.append(stat - val["inittran"][idx])

                # sum diff stats #
                totalStat["rdiff"][0] += rdiff[0]
                totalStat["rdiff"][1] += rdiff[1]
                totalStat["rdiff"][2] += rdiff[2]
                totalStat["rdiff"][3] += rdiff[3]
                totalStat["rdiff"][4] += rdiff[-1]
                totalStat["tdiff"][0] += tdiff[0]
                totalStat["tdiff"][1] += tdiff[1]
                totalStat["tdiff"][2] += tdiff[2]
                totalStat["tdiff"][3] += tdiff[3]
                totalStat["tdiff"][4] += tdiff[-1]

                SysMgr.infoBufferPrint(
                    (
                        "{0:>16} {1:^21}   "
                        "{2:>8} {3:>8} {4:>8} {5:>8} {6:>9}   "
                        "{7:>8} {8:>8} {9:>8} {10:>8} {11:>9}"
                    ).format(
                        dev[-16:],
                        "DIFF",
                        convSize(rdiff[0]),
                        convSize(rdiff[1]),
                        convSize(rdiff[2]),
                        convSize(rdiff[3]),
                        convSize(rdiff[-1]),
                        convSize(tdiff[0]),
                        convSize(tdiff[1]),
                        convSize(tdiff[2]),
                        convSize(tdiff[3]),
                        convSize(tdiff[-1]),
                    )
                )

                # per-device total stats #
                rlist = val["recv"]
                tlist = val["tran"]

                # sum total stats #
                totalStat["rtotal"][0] += rlist[0]
                totalStat["rtotal"][1] += rlist[1]
                totalStat["rtotal"][2] += rlist[2]
                totalStat["rtotal"][3] += rlist[3]
                totalStat["rtotal"][4] += rlist[-1]
                totalStat["ttotal"][0] += tlist[0]
                totalStat["ttotal"][1] += tlist[1]
                totalStat["ttotal"][2] += tlist[2]
                totalStat["ttotal"][3] += tlist[3]
                totalStat["ttotal"][4] += tlist[-1]

                SysMgr.infoBufferPrint(
                    (
                        "{0:>16} {1:^21}   "
                        "{2:>8} {3:>8} {4:>8} {5:>8} {6:>9}   "
                        "{7:>8} {8:>8} {9:>8} {10:>8} {11:>9}"
                    ).format(
                        " ",
                        "TOTAL",
                        convSize(rlist[0]),
                        convSize(rlist[1]),
                        convSize(rlist[2]),
                        convSize(rlist[3]),
                        convSize(rlist[-1]),
                        convSize(tlist[0]),
                        convSize(tlist[1]),
                        convSize(tlist[2]),
                        convSize(tlist[3]),
                        convSize(tlist[-1]),
                    )
                )

                if cnt < len(self.networkInfo):
                    SysMgr.infoBufferPrint("{0:1}".format(oneLine))

                cnt += 1

                if SysMgr.jsonEnable:
                    jsonData[dev] = {}

                    jsonData[dev]["ipaddr"] = val["ipaddr"]

                    jsonData[dev]["recv"] = {
                        "bytes": convSize(rlist[0]),
                        "packets": convSize(rlist[1]),
                        "errs": convSize(rlist[2]),
                        "drop": convSize(rlist[3]),
                        "fifo": convSize(rlist[4]),
                        "frame": convSize(rlist[5]),
                        "compressed": convSize(rlist[6]),
                        "multicast": convSize(rlist[7]),
                    }

                    jsonData[dev]["trans"] = {
                        "bytes": convSize(tlist[0]),
                        "packets": convSize(tlist[1]),
                        "errs": convSize(tlist[2]),
                        "drop": convSize(tlist[3]),
                        "fifo": convSize(tlist[4]),
                        "frame": convSize(tlist[5]),
                        "compressed": convSize(tlist[6]),
                        "multicast": convSize(tlist[7]),
                    }
            except SystemExit:
                sys.exit(0)
            except:
                pass

        if cnt == 1:
            SysMgr.infoBufferPrint("\tNone")
        else:
            rdiff = totalStat["rdiff"]
            tdiff = totalStat["tdiff"]
            SysMgr.infoBufferPrint(
                (
                    "{12:1}\n{0:>16} {1:^21}   "
                    "{2:>8} {3:>8} {4:>8} {5:>8} {6:>9}   "
                    "{7:>8} {8:>8} {9:>8} {10:>8} {11:>9}"
                ).format(
                    "[ TOTAL ]",
                    "DIFF",
                    convSize(rdiff[0]),
                    convSize(rdiff[1]),
                    convSize(rdiff[2]),
                    convSize(rdiff[3]),
                    convSize(rdiff[-1]),
                    convSize(tdiff[0]),
                    convSize(tdiff[1]),
                    convSize(tdiff[2]),
                    convSize(tdiff[3]),
                    convSize(tdiff[-1]),
                    oneLine,
                )
            )

            rtotal = totalStat["rtotal"]
            ttotal = totalStat["ttotal"]
            SysMgr.infoBufferPrint(
                (
                    "{0:>16} {1:^21}   "
                    "{2:>8} {3:>8} {4:>8} {5:>8} {6:>9}   "
                    "{7:>8} {8:>8} {9:>8} {10:>8} {11:>9}"
                ).format(
                    " ",
                    "TOTAL",
                    convSize(rtotal[0]),
                    convSize(rtotal[1]),
                    convSize(rtotal[2]),
                    convSize(rtotal[3]),
                    convSize(rtotal[-1]),
                    convSize(ttotal[0]),
                    convSize(ttotal[1]),
                    convSize(ttotal[2]),
                    convSize(ttotal[3]),
                    convSize(ttotal[-1]),
                )
            )

        SysMgr.infoBufferPrint("%s" % twoLine)

    def printBlockInfo(self):
        # add JSON stats #
        if SysMgr.jsonEnable:
            SysMgr.jsonData.setdefault("general", {})
            SysMgr.jsonData["general"]["block"] = self.blockData

        # print block info #
        SysMgr.infoBufferPrint("\n[System Block Info]")
        SysMgr.infoBufferPrint(twoLine)
        SysMgr.infoBufferPrint(
            (
                "{0:>16} {1:>8} {2:>8} {3:>8} {4:>10} "
                "{5:>8} {6:>8} {7:>8} {8:>1}"
            ).format(
                "DEV",
                "BlkSize",
                "MinSize",
                "OptSize",
                "Readahead",
                "Affinity",
                "Poll",
                "WrCache",
                "Sched",
            )
        )
        SysMgr.infoBufferPrint(twoLine)

        # print block device info #
        for dev, data in sorted(self.blockData.items()):
            try:
                SysMgr.infoBufferPrint(
                    (
                        "{0:>16} {1:>8} {2:>8} {3:>8} {4:>10} "
                        "{5:>8} {6:>8} {7:>8} {8:>1}"
                    ).format(
                        dev,
                        data["size"],
                        data["minSize"],
                        data["optSize"],
                        data["readahead"],
                        data["affinity"],
                        data["poll"],
                        data["wrCache"],
                        " ".join(data["schedList"]),
                    )
                )
            except SystemExit:
                sys.exit(0)
            except:
                pass

        if self.blockData:
            SysMgr.infoBufferPrint(oneLine)
        else:
            SysMgr.infoBufferPrint("\tNone\n%s" % oneLine)

    def printStorageInfo(self):
        # add JSON stats #
        if SysMgr.jsonEnable:
            SysMgr.jsonData.setdefault("general", {})
            SysMgr.jsonData["general"]["storage"] = {}
            jsonData = SysMgr.jsonData["general"]["storage"]

        # print storage info #
        SysMgr.infoBufferPrint("\n[System Storage Info]")
        SysMgr.infoBufferPrint(twoLine)
        SysMgr.infoBufferPrint(
            (
                "{0:^16} {1:>7} {2:>8} {3:>8} {4:>8} "
                "{5:>8} {6:>6} {7:>7} {8:>8} {9:>40}"
            ).format(
                "DEV",
                "NUM",
                "READ",
                "WRITE",
                "TOTAL",
                "FREE",
                "USAGE",
                "NrAVF",
                "FS",
                "MountPoint <Option>",
            )
        )
        SysMgr.infoBufferPrint(twoLine)

        outputCnt = 0
        devInfo = {}
        totalInfo = {"total": 0, "free": 0, "favail": 0, "read": 0, "write": 0}

        # create block device table #
        for key, val in sorted(self.mountInfo.items(), key=lambda e: e[0]):
            # check device node path #
            if val["fs"] == "tmpfs":
                key = val["path"]

            if key[0] == "/":
                devInfo[key] = {}
                outputCnt += 1
            else:
                continue

            # calculate read & write size of devices #
            try:
                # initialize device data #
                dev = key[key.rfind("/") + 1 :]
                readSize = readTime = writeSize = writeTime = "?"

                # get real device node #
                if ":" in dev:
                    major, minor = dev.split(":")
                    for name, mp in self.diskInfo["prev"].items():
                        if mp["major"] == major and mp["minor"] == minor:
                            dev = name
                elif (
                    not dev in self.diskInfo["prev"]
                    and not dev in self.diskInfo["next"]
                ):
                    for k, v in self.diskInfo["next"].items():
                        if (
                            val["major"] == v["major"]
                            and val["minor"] == v["minor"]
                        ):
                            dev = k
                            break

                beforeInfo = self.diskInfo["prev"][dev]
                afterInfo = self.diskInfo["next"][dev]

                # read #
                read = readSize = (
                    long(afterInfo["sectorRead"])
                    - long(beforeInfo["sectorRead"])
                ) << 9
                readSize = UtilMgr.convSize2Unit(readSize)

                # write #
                write = writeSize = (
                    long(afterInfo["sectorWrite"])
                    - long(beforeInfo["sectorWrite"])
                ) << 9
                writeSize = UtilMgr.convSize2Unit(writeSize)

                if val["fs"] != "tmpfs" and val["fs"] != "-":
                    totalInfo["read"] += read
                    totalInfo["write"] += write
            except SystemExit:
                sys.exit(0)
            except:
                pass

            # get device stat #
            try:
                major = minor = total = free = use = avail = "?"

                fstat = os.lstat(val["path"])
                major = os.major(fstat.st_dev)
                minor = os.minor(fstat.st_dev)

                if hasattr(os, "statvfs"):
                    stat = os.statvfs(val["path"])
                else:
                    stat = SysMgr.statvfs(val["path"])

                total = stat.f_bsize * stat.f_blocks
                free = stat.f_bsize * stat.f_bavail
                if hasattr(stat, "f_favail"):
                    avail = stat.f_favail
                else:
                    avail = 0

                use = "%d%%" % long((total - free) / float(total) * 100)

                try:
                    if val["fs"] != "tmpfs":
                        totalInfo["total"] += total
                        totalInfo["free"] += free
                        totalInfo["favail"] += avail
                except:
                    pass

                total = UtilMgr.convSize2Unit(total)
                free = UtilMgr.convSize2Unit(free)
                avail = UtilMgr.convSize2Unit(avail)
            except SystemExit:
                sys.exit(0)
            except:
                pass

            # update device number #
            if major == "?" and minor == "?":
                if "major" in val:
                    major = long(val["major"])
                if "minor" in val:
                    minor = long(val["minor"])

            # get partition range #
            try:
                devid = "%s:%s" % (major, minor)
                prange = "[%s-%s]" % (
                    self.partitionInfo[devid]["start"],
                    self.partitionInfo[devid]["end"],
                )
            except:
                prange = "[?]"

            # update device path with partition range #
            try:
                key = "%s (%s) %s" % (
                    key,
                    ",".join(self.devInfo["block"][major]),
                    prange,
                )
            except SystemExit:
                sys.exit(0)
            except:
                pass

            # print device info #
            SysMgr.infoBufferPrint("{0:<16}".format(key))

            # build block device info string #
            try:
                diskInfo = (
                    "{0:<16} {1:>7} {2:>8} {3:>8} {4:>8} "
                    "{5:>8} {6:>6} {7:>7} {8:>8} "
                ).format(
                    " ",
                    "%s:%s" % (major, minor),
                    readSize,
                    writeSize,
                    total,
                    free,
                    use,
                    avail,
                    val["fs"],
                )
            except:
                continue

            # print storage info #
            try:
                title = diskInfo
                splitLen = SysMgr.lineLength - len(diskInfo) - 1

                if val["option"]:
                    option = "+".join([val["option"], val["soption"]])
                else:
                    option = val["option"]

                if option:
                    option = " <%s>" % option
                mountList = "%s%s" % (val["path"], option)

                mountList = [
                    mountList[i : i + splitLen]
                    for i in xrange(0, len(mountList), splitLen)
                ]

                for string in mountList:
                    SysMgr.infoBufferPrint(
                        "{0:85} {1:<1}".format(title, string)
                    )
                    title = " "
            except SystemExit:
                sys.exit(0)
            except:
                pass

            try:
                if SysMgr.jsonEnable:
                    jsonData[key] = {
                        "major": major,
                        "minor": minor,
                        "read": readSize,
                        "write": writeSize,
                        "total": total,
                        "free": free,
                        "use": use,
                        "avail": avail,
                        "fs": val["fs"],
                        "mount": "%s %s" % (val["path"], val["option"]),
                    }
            except SystemExit:
                sys.exit(0)
            except:
                pass

        # print total I/O size #
        if outputCnt == 0:
            SysMgr.infoBufferPrint("\tN/A")
        else:
            try:
                try:
                    usage = long(
                        (totalInfo["total"] - totalInfo["free"])
                        / float(totalInfo["total"])
                        * 100
                    )
                except:
                    usage = 0

                totalInfo["total"] = UtilMgr.convSize2Unit(totalInfo["total"])
                totalInfo["free"] = UtilMgr.convSize2Unit(totalInfo["free"])
                totalInfo["favail"] = UtilMgr.convSize2Unit(
                    totalInfo["favail"]
                )
                totalInfo["read"] = UtilMgr.convSize2Unit(totalInfo["read"])
                totalInfo["write"] = UtilMgr.convSize2Unit(totalInfo["write"])
                totalInfo["use"] = "%d%%" % usage
            except SystemExit:
                sys.exit(0)
            except:
                totalInfo["use"] = "?%"

            SysMgr.infoBufferPrint(
                (
                    "{0:^16}\n{1:^24} {2:>8} {3:>8} {4:>8} "
                    "{5:>8} {6:>6} {7:>7} {8:>8} {9:<20}"
                ).format(
                    oneLine,
                    "TOTAL",
                    totalInfo["read"],
                    totalInfo["write"],
                    totalInfo["total"],
                    totalInfo["free"],
                    totalInfo["use"],
                    totalInfo["favail"],
                    " ",
                    " ",
                )
            )

        SysMgr.infoBufferPrint("%s" % twoLine)

    def printMemInfo(self):
        if len(self.memData) != 2:
            return

        # parse previous data #
        time = "prev"
        self.memInfo[time] = {}
        for l in self.memData[time]:
            m = re.match(r"(?P<type>\S+):\s+(?P<size>[0-9]+)", l)
            if m:
                d = m.groupdict()
                self.memInfo[time][d["type"]] = d["size"]

        # parse current data #
        time = "next"
        self.memInfo[time] = {}
        for l in self.memData[time]:
            m = re.match(r"(?P<type>\S+):\s+(?P<size>[0-9]+)", l)
            if m:
                d = m.groupdict()
                self.memInfo[time][d["type"]] = d["size"]

        before = self.memInfo["prev"]
        after = self.memInfo["next"]

        # check items for compatibility #
        try:
            before["Shmem"]
        except:
            before["Shmem"] = "0"
            after["Shmem"] = "0"

        try:
            before["SReclaimable"]
        except:
            before["SReclaimable"] = "0"
            after["SReclaimable"] = "0"

        try:
            before["Sunreclaim"]
        except:
            before["Sunreclaim"] = "0"
            after["Sunreclaim"] = "0"

        try:
            before["Mlocked"]
        except:
            before["Mlocked"] = "0"
            after["Mlocked"] = "0"

        # define convert function #
        convSize = UtilMgr.convSize2Unit

        # print memory info #
        SysMgr.infoBufferPrint("\n[System Memory Info]")
        SysMgr.infoBufferPrint(twoLine)
        SysMgr.infoBufferPrint(
            (
                "[%6s] %10s %10s %10s %10s %10s %10s %10s %10s "
                "%10s %10s %10s %10s %10s"
            )
            % (
                "DESC ",
                "Memory",
                "Swap",
                "Buffer",
                "Cache",
                "Shared",
                "Mapped",
                "Active",
                "Inactive",
                "PageTables",
                "Slab",
                "SlabRclm",
                "SlabUnRclm",
                "Mlocked",
            )
        )
        SysMgr.infoBufferPrint(twoLine)

        SysMgr.infoBufferPrint(
            "[ TOTAL] %10s %10s"
            % (
                convSize(long(before["MemTotal"]) << 10),
                convSize(long(before["SwapTotal"]) << 10),
            )
        )

        SysMgr.infoBufferPrint(
            "[ FREE ] %10s %10s"
            % (
                convSize(long(before["MemFree"]) << 10),
                convSize(long(before["SwapFree"]) << 10),
            )
        )
        if "MemAvailable" in before:
            SysMgr.infoBufferPrint(
                "[ AVAIL] %10s %10s"
                % (
                    convSize(long(before["MemAvailable"]) << 10),
                    convSize(long(before["SwapFree"]) << 10),
                )
            )
        SysMgr.infoBufferPrint(oneLine)

        if "MemAvailable" in before:
            memBeforeUsage = long(before["MemTotal"]) - long(
                before["MemAvailable"]
            )
        else:
            memBeforeUsage = long(before["MemTotal"]) - long(before["MemFree"])

        swapBeforeUsage = long(before["SwapTotal"]) - long(before["SwapFree"])
        if "MemAvailable" in before:
            memAfterUsage = long(after["MemTotal"]) - long(
                after["MemAvailable"]
            )
        else:
            memAfterUsage = long(after["MemTotal"]) - long(after["MemFree"])

        swapAfterUsage = long(after["SwapTotal"]) - long(after["SwapFree"])

        SysMgr.infoBufferPrint(
            (
                "[ FIRST] %10s %10s %10s %10s %10s %10s %10s "
                "%10s %10s %10s %10s %10s %10s"
            )
            % (
                convSize(memBeforeUsage << 10),
                convSize(swapBeforeUsage << 10),
                convSize(long(before["Buffers"]) << 10),
                convSize(long(before["Cached"]) << 10),
                convSize(long(before["Shmem"]) << 10),
                convSize(long(before["Mapped"]) << 10),
                convSize(long(before["Active"]) << 10),
                convSize(long(before["Inactive"]) << 10),
                convSize(long(before["PageTables"]) << 10),
                convSize(long(before["Slab"]) << 10),
                convSize(long(before["SReclaimable"]) << 10),
                convSize(long(before["SUnreclaim"]) << 10),
                convSize(long(before["Mlocked"]) << 10),
            )
        )

        SysMgr.infoBufferPrint(
            (
                "[ LAST ] %10s %10s %10s %10s %10s %10s %10s "
                "%10s %10s %10s %10s %10s %10s"
            )
            % (
                convSize(memAfterUsage << 10),
                convSize(swapAfterUsage << 10),
                convSize(long(after["Buffers"]) << 10),
                convSize(long(after["Cached"]) << 10),
                convSize(long(after["Shmem"]) << 10),
                convSize(long(after["Mapped"]) << 10),
                convSize(long(after["Active"]) << 10),
                convSize(long(after["Inactive"]) << 10),
                convSize(long(after["PageTables"]) << 10),
                convSize(long(after["Slab"]) << 10),
                convSize(long(after["SReclaimable"]) << 10),
                convSize(long(after["SUnreclaim"]) << 10),
                convSize(long(after["Mlocked"]) << 10),
            )
        )

        SysMgr.infoBufferPrint(oneLine)

        SysMgr.infoBufferPrint(
            (
                "[ DIFF ] %10s %10s %10s %10s %10s %10s %10s "
                "%10s %10s %10s %10s %10s %10s"
            )
            % (
                convSize((memAfterUsage - memBeforeUsage) << 10),
                convSize((swapAfterUsage - swapBeforeUsage) << 10),
                convSize(
                    (long(after["Buffers"]) - long(before["Buffers"])) << 10
                ),
                convSize(
                    (long(after["Cached"]) - long(before["Cached"])) << 10
                ),
                convSize((long(after["Shmem"]) - long(before["Shmem"])) << 10),
                convSize(
                    (long(after["Mapped"]) - long(before["Mapped"])) << 10
                ),
                convSize(
                    (long(after["Active"]) - long(before["Active"])) << 10
                ),
                convSize(
                    (long(after["Inactive"]) - long(before["Inactive"])) << 10
                ),
                convSize(
                    (long(after["PageTables"]) - long(before["PageTables"]))
                    << 10
                ),
                convSize((long(after["Slab"]) - long(before["Slab"])) << 10),
                convSize(
                    (
                        long(after["SReclaimable"])
                        - long(before["SReclaimable"])
                    )
                    << 10
                ),
                convSize(
                    (long(after["SUnreclaim"]) - long(before["SUnreclaim"]))
                    << 10
                ),
                convSize(
                    (long(after["Mlocked"]) - long(before["Mlocked"])) << 10
                ),
            )
        )

        SysMgr.infoBufferPrint(twoLine)

        # add JSON stats #
        if SysMgr.jsonEnable:
            SysMgr.jsonData.setdefault("general", {})
            SysMgr.jsonData["general"]["mem"] = {
                "memTotal": convSize(long(after["MemTotal"]) << 10),
                "memFree": convSize(long(after["MemFree"]) << 10),
                "swapTotal": convSize(long(after["SwapTotal"]) << 10),
                "swapFree": convSize(long(after["SwapFree"]) << 10),
                "buffer": convSize(long(after["Buffers"]) << 10),
                "cache": convSize(long(after["Cached"]) << 10),
                "shmem": convSize(long(after["Shmem"]) << 10),
                "mapped": convSize(long(after["Mapped"]) << 10),
                "active": convSize(long(after["Active"]) << 10),
                "inactive": convSize(long(after["Inactive"]) << 10),
                "pagetable": convSize(long(after["PageTables"]) << 10),
                "slab": convSize(long(after["Slab"]) << 10),
                "sreclaimable": convSize(long(after["SReclaimable"]) << 10),
                "sunreclaimable": convSize(long(after["SUnreclaim"]) << 10),
                "mlock": convSize(long(after["Mlocked"]) << 10),
            }

            if "MemAvailable" in after:
                SysMgr.jsonData["general"]["mem"]["memAvailable"] = convSize(
                    long(after["MemAvailable"]) << 10
                )


class DbusMgr(object):
    """Analyzer for D-Bus"""

    errObj = None
    dbusErrObj = None
    sentData = {}
    recvData = {}
    prevData = {}
    msgSentTable = {}
    msgRecvTable = {}
    msgColorList = {}
    connCache = {}
    dbgObj = None
    isTopMode = False
    watchList = []

    G_IO_ERROR_TYPE = [
        "G_IO_ERROR_FAILED",
        "G_IO_ERROR_NOT_FOUND",
        "G_IO_ERROR_EXISTS",
        "G_IO_ERROR_IS_DIRECTORY",
        "G_IO_ERROR_NOT_DIRECTORY",
        "G_IO_ERROR_NOT_EMPTY",
        "G_IO_ERROR_NOT_REGULAR_FILE",
        "G_IO_ERROR_NOT_SYMBOLIC_LINK",
        "G_IO_ERROR_NOT_MOUNTABLE_FILE",
        "G_IO_ERROR_FILENAME_TOO_LONG",
        "G_IO_ERROR_INVALID_FILENAME",
        "G_IO_ERROR_TOO_MANY_LINKS",
        "G_IO_ERROR_NO_SPACE",
        "G_IO_ERROR_INVALID_ARGUMENT",
        "G_IO_ERROR_PERMISSION_DENIED",
        "G_IO_ERROR_NOT_SUPPORTED",
        "G_IO_ERROR_NOT_MOUNTED",
        "G_IO_ERROR_ALREADY_MOUNTED",
        "G_IO_ERROR_CLOSED",
        "G_IO_ERROR_CANCELLED",
        "G_IO_ERROR_PENDING",
        "G_IO_ERROR_READ_ONLY",
        "G_IO_ERROR_CANT_CREATE_BACKUP",
        "G_IO_ERROR_WRONG_ETAG",
        "G_IO_ERROR_TIMED_OUT",
        "G_IO_ERROR_WOULD_RECURSE",
        "G_IO_ERROR_BUSY",
        "G_IO_ERROR_WOULD_BLOCK",
        "G_IO_ERROR_HOST_NOT_FOUND",
        "G_IO_ERROR_WOULD_MERGE",
        "G_IO_ERROR_FAILED_HANDLED",
        "G_IO_ERROR_TOO_MANY_OPEN_FILES",
        "G_IO_ERROR_NOT_INITIALIZED",
        "G_IO_ERROR_ADDRESS_IN_USE",
        "G_IO_ERROR_PARTIAL_INPUT",
        "G_IO_ERROR_INVALID_DATA",
        "G_IO_ERROR_DBUS_ERROR",
        "G_IO_ERROR_HOST_UNREACHABLE",
        "G_IO_ERROR_NETWORK_UNREACHABLE",
        "G_IO_ERROR_CONNECTION_REFUSED",
        "G_IO_ERROR_PROXY_FAILED",
        "G_IO_ERROR_PROXY_AUTH_FAILED",
        "G_IO_ERROR_PROXY_NEED_AUTH",
        "G_IO_ERROR_PROXY_NOT_ALLOWED",
        "G_IO_ERROR_BROKEN_PIPE",
        "G_IO_ERROR_CONNECTION_CLOSED",
        "G_IO_ERROR_NOT_CONNECTED",
        "G_IO_ERROR_MESSAGE_TOO_LARGE",
    ]

    DBusBusType = {
        "DBUS_BUS_SESSION": 0,
        "DBUS_BUS_SYSTEM": 1,
        "DBUS_BUS_STARTER": 2,
    }

    GDBusMessageType = [
        "INVALID",
        "METHOD",  # METHOD_CALL
        "RETURN",  # METHOD_RETURN
        "ERROR",
        "SIGNAL",
    ]

    taskInfo = {"min": 0, "max": 0, "err": 0, "cnt": 0, "size": 0, "total": 0}

    @staticmethod
    def getErrInfo():
        if DbusMgr.dbusErrObj:
            errObj = DbusMgr.dbusErrObj
            return "%s: %s" % (errObj.name, errObj.message)
        else:
            return "N/A"

    @staticmethod
    def getErrP():
        if DbusMgr.dbusErrObj:
            dbusErrP = byref(DbusMgr.dbusErrObj)
            SysMgr.libdbusObj.dbus_error_init(dbusErrP)
            return dbusErrP

        # define error object #
        class DBusError(Structure):
            _fields_ = (
                ("name", c_char_p),
                ("message", c_char_p),
                ("padding2", c_void_p * 2),
            )

        DbusMgr.dbusErrObj = dbusErr = DBusError()
        dbusErrP = byref(dbusErr)
        SysMgr.libdbusObj.dbus_error_init(dbusErrP)
        return dbusErrP

    @staticmethod
    def getBus(bus, tid=None, addr=None):
        def _setEuid():
            # set EUID #
            try:
                euidOrig = os.geteuid()
                if tid:
                    euidNew = SysMgr.getUid(tid, "effective")
                    os.seteuid(euidNew)
            except SystemExit:
                sys.exit(0)
            except:
                comm = SysMgr.getComm(tid, cache=True)
                SysMgr.printErr(
                    "failed to set EUID for %s(%s)'s one" % (comm, tid),
                    reason=True,
                )

            return euidOrig

        # reuse connection from cache #
        if bus in DbusMgr.connCache:
            return DbusMgr.connCache[bus]

        dbusObj = SysMgr.libdbusObj
        name = "guider.method.caller".encode()
        procInfo = "%s(%s)" % (SysMgr.getComm(tid, cache=True), tid)

        # get bus type #
        if bus == "system":
            bustype = DbusMgr.DBusBusType["DBUS_BUS_SYSTEM"]

            # save EUID #
            euidOrig = os.geteuid()
        elif bus == "session" or bus == "user":
            bustype = DbusMgr.DBusBusType["DBUS_BUS_SESSION"]

            # set EUID #
            euidOrig = _setEuid()
        else:
            comm = SysMgr.getComm(tid, cache=True)
            SysMgr.printWarn(
                "failed to recognize %s bus for %s" % (bus, procInfo)
            )
            return None

        # get connection #
        conn = dbusObj.dbus_bus_get_private(bustype, DbusMgr.getErrP())
        if conn:
            conn = dbusObj.dbus_connection_ref(conn)
        else:
            # get connection by session address #
            ADDRENV = "DBUS_SESSION_BUS_ADDRESS"
            if ADDRENV in os.environ:
                address = os.environ[ADDRENV]
                address = c_char_p(address.encode())
                conn = dbusObj.dbus_connection_open(address, DbusMgr.getErrP())
            elif tid:
                # recover EUID #
                os.seteuid(euidOrig)

                envList = SysMgr.getEnv(tid)
                for env in envList:
                    if env.startswith(ADDRENV):
                        renv = UtilMgr.lstrip(env, ADDRENV)[1:].encode()
                        address = c_char_p(renv)
                        conn = dbusObj.dbus_connection_open(
                            address, DbusMgr.getErrP()
                        )
                        break

            # check error #
            if conn:
                conn = dbusObj.dbus_connection_ref(conn)
                ret = dbusObj.dbus_bus_set_unique_name(
                    c_void_p(conn), c_char_p(name)
                )
                ret = dbusObj.dbus_bus_get_unique_name(c_void_p(conn))
                ret = dbusObj.dbus_bus_register(
                    c_void_p(conn), DbusMgr.getErrP()
                )
                if not ret:
                    SysMgr.printWarn(
                        "failed to register D-Bus %s bus for %s because %s"
                        % (bus, procInfo, DbusMgr.getErrInfo())
                    )
                    return None
            else:
                SysMgr.printWarn(
                    "failed to get D-Bus %s bus for %s because %s"
                    % (bus, procInfo, DbusMgr.getErrInfo())
                )
                return None

        """
        # request name #
        DBUS_NAME_FLAG_ALLOW_REPLACEMENT = c_uint(0x1)
        DBUS_NAME_FLAG_REPLACE_EXISTING = c_uint(0x2)
        ret = dbusObj.dbus_bus_request_name(
            conn, c_char_p(name), DBUS_NAME_FLAG_REPLACE_EXISTING,
            DbusMgr.getErrP())
        if ret < 0:
            SysMgr.printWarn(
                "failed to request D-Bus bus name to %s for %s because %s" % \
                    (name.decode(), procInfo, DbusMgr.getErrInfo()))
        """

        try:
            ret = conn

            # check connection #
            if dbusObj.dbus_connection_get_is_connected(conn) == 0:
                SysMgr.printWarn(
                    "D-Bus %s bus is not connected yet for %s"
                    % (bus, procInfo)
                )
                ret = None
            # send a message for method call #
            elif dbusObj.dbus_connection_get_is_authenticated(conn) == 0:
                path = "/org/freedesktop/DBus"
                des = iface = "org.freedesktop.DBus"
                method = "Hello"
                msg, reply = DbusMgr.callMethod(conn, des, path, iface, method)
                if not msg or not reply:
                    if bustype == DbusMgr.DBusBusType["DBUS_BUS_SESSION"]:
                        SysMgr.printWarn(
                            (
                                "check DBUS_SESSION_BUS_ADDRESS "
                                "for %s bus for %s"
                            )
                            % (bus, procInfo),
                            True,
                        )
                    ret = None
        finally:
            # recover EUID #
            try:
                os.seteuid(euidOrig)
            except:
                pass

            # save connection cache #
            if ret:
                DbusMgr.connCache[bus] = ret

            return ret

    @staticmethod
    def runMonitor(bus, des=None):
        if not bus:
            return

        dbusObj = SysMgr.libdbusObj

        conn = DbusMgr.getBus(bus)
        if not conn:
            return

        # prepare method args #
        path = "/"
        if not des:
            des = "org.freedesktop.DBus"
        if not des.startswith(":"):
            path += des.replace(".", "/")
        if (
            dbusObj.dbus_validate_path(
                c_char_p(path.encode()), DbusMgr.getErrP()
            )
            == 0
        ):
            SysMgr.printWarn(
                "failed to create a D-Bus message because %s"
                % DbusMgr.getErrInfo()
            )
            return

        # set interface, method, timeout #
        iface = "org.freedesktop.DBus.Monitoring"
        method = "BecomeMonitor"
        timeout = c_int(-1)

        # create a message for method call #
        msg = dbusObj.dbus_message_new_method_call(
            des.encode(), path.encode(), iface.encode(), method.encode()
        )
        if not msg:
            # dbusObj.dbus_connection_unref(conn)
            SysMgr.printWarn("failed to create a D-Bus message")
            return

        # prepare args #
        array = c_char("a".encode())
        DBUS_TYPE_ARRAY = cast(byref(array), POINTER(c_int)).contents
        dicte = c_char("e".encode())
        DBUS_TYPE_DICT_ENTRY = cast(byref(dicte), POINTER(c_int)).contents
        char = c_char("s".encode())
        char2 = c_char("s".encode())
        DBUS_TYPE_STRING = cast(byref(char), POINTER(c_int)).contents
        uint32 = c_char("u".encode())
        DBUS_TYPE_UINT32 = cast(byref(uint32), POINTER(c_int)).contents
        null = c_char("\0".encode())
        DBUS_TYPE_INVALID = cast(byref(null), POINTER(c_int)).contents
        zero = c_uint32(0)

        class DBusMessageIter(Structure):
            _fields_ = (
                ("dummy1", c_void_p),
                ("dummy2", c_void_p),
                ("dummy3", c_uint32),
                ("dummy4", c_int),
                ("dummy5", c_int),
                ("dummy6", c_int),
                ("dummy7", c_int),
                ("dummy8", c_int),
                ("dummy9", c_int),
                ("dummy10", c_int),
                ("dummy11", c_int),
                ("pad1", c_int),
                ("pad2", c_void_p),
                ("pad3", c_void_p),
            )

        msgIter = DBusMessageIter()
        msgIterP = byref(msgIter)
        arrayIter = DBusMessageIter()
        arrayIterP = byref(arrayIter)

        # initialize iteration #
        ret = dbusObj.dbus_message_iter_init_append(msg, msgIterP)
        if not ret:
            SysMgr.printWarn("failed to initialize D-Bus message iteration")
            dbusObj.dbus_message_unref(msg)
            # dbusObj.dbus_connection_unref(conn)
            return

        # append container #
        ret = dbusObj.dbus_message_iter_open_container(
            msgIterP, DBUS_TYPE_ARRAY, byref(char2), arrayIterP
        )
        if not ret:
            SysMgr.printWarn("failed to initialize D-Bus message container")
            dbusObj.dbus_message_unref(msg)
            # dbusObj.dbus_connection_unref(conn)
            return

        """
        # append filter #
        ret = dbusObj.dbus_message_iter_append_basic(
            arrayIterP, DBUS_TYPE_STRING, byref(char))
        if not ret:
            SysMgr.printWarn("failed to initialize D-Bus message iteration")
            dbusObj.dbus_message_unref(msg)
            #dbusObj.dbus_connection_unref(conn)
            return
        """

        # close container #
        ret = dbusObj.dbus_message_iter_close_container(msgIterP, arrayIterP)
        if not ret:
            SysMgr.printWarn("failed to close D-Bus message container")
            dbusObj.dbus_message_unref(msg)
            # dbusObj.dbus_connection_unref(conn)
            return

        # append zero to container #
        ret = dbusObj.dbus_message_iter_append_basic(
            msgIterP, DBUS_TYPE_UINT32, pointer(zero)
        )
        if not ret:
            SysMgr.printWarn("failed to initialize D-Bus message iteration")
            dbusObj.dbus_message_unref(msg)
            # dbusObj.dbus_connection_unref(conn)
            return

        # call a remote method #
        reply = dbusObj.dbus_connection_send_with_reply_and_block(
            conn, msg, timeout, DbusMgr.getErrP()
        )
        if not reply:
            dbusObj.dbus_message_unref(msg)
            # dbusObj.dbus_connection_unref(conn)
            SysMgr.printWarn(
                "failed to call a D-Bus remote method because %s at %s"
                % (DbusMgr.getErrInfo(), SysMgr.getLine())
            )
            return

        while 1:
            reply = dbusObj.dbus_connection_read_write_dispatch(conn, -1)

    @staticmethod
    def callMethod(conn, des, path, iface, method, timeout=None):
        dbusObj = SysMgr.libdbusObj

        if timeout is None:
            timeout = c_int(-1)

        # create a message for method call #
        msg = dbusObj.dbus_message_new_method_call(
            des.encode(), path.encode(), iface.encode(), method.encode()
        )
        if not msg:
            # dbusObj.dbus_connection_unref(conn)
            SysMgr.printWarn("failed to create a D-Bus message")
            return msg, None

        # call a remote method #
        reply = dbusObj.dbus_connection_send_with_reply_and_block(
            conn, msg, timeout, DbusMgr.getErrP()
        )
        if not reply:
            dbusObj.dbus_message_unref(msg)
            # dbusObj.dbus_connection_unref(conn)
            SysMgr.printWarn(
                "failed to call a D-Bus remote method because %s at %s"
                % (DbusMgr.getErrInfo(), SysMgr.getLine())
            )
            return msg, reply

        return msg, reply

    @staticmethod
    def getStats(bus, request, des=None, tid=None, procStr=None):
        # pylint: disable=no-member
        def _printWarn(procStr, line, err):
            SysMgr.printWarn(
                ("failed to parse D-Bus message for %s at %s " "because %s")
                % (procStr, line, err),
                True,
            )

        if not bus:
            return

        dbusObj = SysMgr.libdbusObj

        conn = DbusMgr.getBus(bus, tid)
        if not conn:
            return

        getLine = SysMgr.getLine
        getErr = DbusMgr.getErrInfo

        # prepare method args #
        path = "/"
        if not des:
            des = "org.freedesktop.DBus"
        if not des.startswith(":"):
            path += des.replace(".", "/")
        if (
            dbusObj.dbus_validate_path(
                c_char_p(path.encode()), DbusMgr.getErrP()
            )
            == 0
        ):
            _printWarn(procStr, getLine(), getErr())
            return

        # set interface, method, timeout #
        if request == "introspect":
            iface = "org.freedesktop.DBus.Introspectable"
            method = "Introspect"
            timeout = c_int(100)
        elif request == "allmatch":
            iface = "org.freedesktop.DBus.Debug.Stats"
            method = "GetAllMatchRules"
            timeout = c_int(-1)
        elif request == "stats":
            iface = "org.freedesktop.DBus.Debug.Stats"
            method = "GetStats"
            timeout = c_int(-1)
        else:
            SysMgr.printErr("unknown request %s for %s" % (request, procStr))
            sys.exit(-1)

        # send a message for method call #
        msg, reply = DbusMgr.callMethod(
            conn, des, path, iface, method, timeout
        )
        if not msg or not reply:
            return

        # prepare args #
        # refer to https://dbus.freedesktop.org/doc/api/html/group__DBusProtocol.html #
        array = c_char("a".encode())
        DBUS_TYPE_ARRAY = cast(byref(array), POINTER(c_int)).contents
        dicte = c_char("e".encode())
        DBUS_TYPE_DICT_ENTRY = cast(byref(dicte), POINTER(c_int)).contents
        char = c_char("s".encode())
        DBUS_TYPE_STRING = cast(byref(char), POINTER(c_int)).contents
        uint32 = c_char("u".encode())
        DBUS_TYPE_UINT32 = cast(byref(uint32), POINTER(c_int)).contents
        null = c_char("\0".encode())
        DBUS_TYPE_INVALID = cast(byref(null), POINTER(c_int)).contents

        # introspect #
        if request == "introspect":
            strRes = c_char_p("".encode())
            res = dbusObj.dbus_message_get_args(
                reply,
                DbusMgr.getErrP(),
                DBUS_TYPE_STRING,
                byref(strRes),
                DBUS_TYPE_INVALID,
            )
            if not res:
                dbusObj.dbus_message_unref(msg)
                dbusObj.dbus_message_unref(reply)
                # dbusObj.dbus_connection_unref(conn)
                _printWarn(procStr, getLine(), getErr())
                return

            # parse args #
            strRes = c_char_p("".encode())
            res = dbusObj.dbus_message_get_args(
                reply,
                DbusMgr.getErrP(),
                DBUS_TYPE_STRING,
                byref(strRes),
                DBUS_TYPE_INVALID,
            )
            if not res:
                _printWarn(procStr, getLine(), getErr())
                return

            # convert value #
            buf = str(strRes.value.decode())

            # clean up #
            dbusObj.dbus_message_unref(msg)
            dbusObj.dbus_message_unref(reply)
            # dbusObj.dbus_connection_unref(conn)

            return buf

        # allmatch #
        perProcList = {}
        perSigList = {}

        class DBusMessageIter(Structure):
            _fields_ = (
                ("dummy1", c_void_p),
                ("dummy2", c_void_p),
                ("dummy3", c_uint32),
                ("dummy4", c_int),
                ("dummy5", c_int),
                ("dummy6", c_int),
                ("dummy7", c_int),
                ("dummy8", c_int),
                ("dummy9", c_int),
                ("dummy10", c_int),
                ("dummy11", c_int),
                ("pad1", c_int),
                ("pad2", c_void_p),
                ("pad3", c_void_p),
            )

        # initialize message iterator #
        rootIter = DBusMessageIter()
        rootIterP = byref(rootIter)
        arrayIter = DBusMessageIter()
        arrayIterP = byref(arrayIter)
        dictIter = DBusMessageIter()
        dictIterP = byref(dictIter)
        arraySigIter = DBusMessageIter()
        arraySigIterP = byref(arraySigIter)

        procInfo = c_char_p("".encode())
        sigInfo = c_char_p("".encode())

        # initialize iteration #
        ret = dbusObj.dbus_message_iter_init(reply, rootIterP)
        if not ret:
            _printWarn(procStr, getLine(), getErr())
            dbusObj.dbus_message_unref(msg)
            dbusObj.dbus_message_unref(reply)
            # dbusObj.dbus_connection_unref(conn)
            return

        ret = dbusObj.dbus_message_iter_get_arg_type(rootIterP)
        if ret != DBUS_TYPE_ARRAY.value:
            _printWarn(procStr, getLine(), getErr())
            dbusObj.dbus_message_unref(msg)
            dbusObj.dbus_message_unref(reply)
            # dbusObj.dbus_connection_unref(conn)
            return

        # get item count #
        cnt = dbusObj.dbus_message_iter_get_element_count(rootIterP)
        dbusObj.dbus_message_iter_recurse(rootIterP, arrayIterP)

        # stats #
        if request == "stats":
            SysMgr.printStat(
                "start collecting stats for %s bus for %s" % (bus, procStr)
            )

            variant = c_char("v".encode())
            DBUS_TYPE_VARIANT = cast(byref(variant), POINTER(c_int)).contents
            uint32 = c_char("u".encode())
            DBUS_TYPE_UINT32 = cast(byref(uint32), POINTER(c_int)).contents

            varIter = DBusMessageIter()
            varIterP = byref(varIter)

            name = c_char_p("".encode())
            value = c_uint32(0)
            statList = {}

            # array item loop #
            while 1:
                ret = dbusObj.dbus_message_iter_get_arg_type(arrayIterP)
                if ret != DBUS_TYPE_DICT_ENTRY.value:
                    _printWarn(procStr, getLine(), getErr())
                    dbusObj.dbus_message_unref(msg)
                    dbusObj.dbus_message_unref(reply)
                    # dbusObj.dbus_connection_unref(conn)
                    return statList

                dbusObj.dbus_message_iter_recurse(arrayIterP, dictIterP)

                # dictionary item loop #
                while 1:
                    ret = dbusObj.dbus_message_iter_get_arg_type(dictIterP)
                    if ret != DBUS_TYPE_STRING.value:
                        _printWarn(procStr, getLine(), getErr())
                        dbusObj.dbus_message_unref(msg)
                        dbusObj.dbus_message_unref(reply)
                        # dbusObj.dbus_connection_unref(conn)
                        return statList

                    # get name #
                    dbusObj.dbus_message_iter_get_basic(dictIterP, byref(name))
                    if not name.value:
                        return statList

                    # decode name #
                    sname = name.value.decode()

                    # register stat name #
                    statList.setdefault(sname, [])

                    # next stat value #
                    if not dbusObj.dbus_message_iter_next(dictIterP):
                        break

                    # get stat values as a variant-type value #
                    ret = dbusObj.dbus_message_iter_get_arg_type(dictIterP)
                    if ret != DBUS_TYPE_VARIANT.value:
                        _printWarn(procStr, getLine(), getErr())
                        dbusObj.dbus_message_unref(msg)
                        dbusObj.dbus_message_unref(reply)
                        # dbusObj.dbus_connection_unref(conn)
                        break

                    # parse variant #
                    dbusObj.dbus_message_iter_recurse(dictIterP, varIterP)

                    # variant item loop #
                    while 1:
                        ret = dbusObj.dbus_message_iter_get_arg_type(varIterP)
                        if ret != DBUS_TYPE_UINT32.value:
                            _printWarn(procStr, getLine(), getErr())
                            dbusObj.dbus_message_unref(msg)
                            dbusObj.dbus_message_unref(reply)
                            # dbusObj.dbus_connection_unref(conn)
                            return statList

                        # get value #
                        dbusObj.dbus_message_iter_get_basic(
                            varIterP, byref(value)
                        )
                        if value.value:
                            statList[sname].append(value.value)

                        # next value #
                        if not dbusObj.dbus_message_iter_next(varIterP):
                            break

                    # next stat #
                    if not dbusObj.dbus_message_iter_next(dictIterP):
                        break

                # next item #
                if not dbusObj.dbus_message_iter_next(arrayIterP):
                    break

            return statList

        SysMgr.printStat(
            "start collecting subscription info for %s bus for %s"
            % (bus, procStr)
        )

        # array item loop #
        while 1:
            ret = dbusObj.dbus_message_iter_get_arg_type(arrayIterP)
            if ret != DBUS_TYPE_DICT_ENTRY.value:
                _printWarn(procStr, getLine(), getErr())
                dbusObj.dbus_message_unref(msg)
                dbusObj.dbus_message_unref(reply)
                # dbusObj.dbus_connection_unref(conn)
                return

            dbusObj.dbus_message_iter_recurse(arrayIterP, dictIterP)

            # dictionary item loop #
            while 1:
                ret = dbusObj.dbus_message_iter_get_arg_type(dictIterP)
                if ret != DBUS_TYPE_STRING.value:
                    _printWarn(procStr, getLine(), getErr())
                    dbusObj.dbus_message_unref(msg)
                    dbusObj.dbus_message_unref(reply)
                    # dbusObj.dbus_connection_unref(conn)
                    return

                # get process ID #
                dbusObj.dbus_message_iter_get_basic(dictIterP, byref(procInfo))
                if not procInfo.value:
                    _printWarn(procStr, getLine(), getErr())
                    dbusObj.dbus_message_unref(msg)
                    dbusObj.dbus_message_unref(reply)
                    # dbusObj.dbus_connection_unref(conn)
                    return

                if not dbusObj.dbus_message_iter_next(dictIterP):
                    break

                ret = dbusObj.dbus_message_iter_get_arg_type(dictIterP)
                if ret != DBUS_TYPE_ARRAY.value:
                    _printWarn(procStr, getLine(), getErr())
                    dbusObj.dbus_message_unref(msg)
                    dbusObj.dbus_message_unref(reply)
                    # dbusObj.dbus_connection_unref(conn)
                    return

                # check array size #
                if dbusObj.dbus_message_iter_get_element_count(dictIterP) == 0:
                    if not dbusObj.dbus_message_iter_next(dictIterP):
                        break
                    continue

                # allocate a new task dict #
                procId = procInfo.value.decode()
                perProcList.setdefault(procId, {})
                procSigList = perProcList[procId]

                # parse signal array #
                dbusObj.dbus_message_iter_recurse(dictIterP, arraySigIterP)

                while 1:
                    ret = dbusObj.dbus_message_iter_get_arg_type(arraySigIterP)
                    if ret != DBUS_TYPE_STRING.value:
                        _printWarn(procStr, getLine(), getErr())
                        dbusObj.dbus_message_unref(msg)
                        dbusObj.dbus_message_unref(reply)
                        # dbusObj.dbus_connection_unref(conn)
                        return

                    # get signal info #
                    dbusObj.dbus_message_iter_get_basic(
                        arraySigIterP, byref(sigInfo)
                    )

                    sinfo = {}

                    # parse items #
                    if sigInfo.value:
                        for item in sigInfo.value.decode().split(","):
                            slist = item.strip('"').split("=")
                            sinfo[slist[0]] = slist[1].strip("'")

                    # save items to list #
                    if "interface" in sinfo:
                        iface = sinfo["interface"]

                        if "sender" in sinfo:
                            sender = sinfo["sender"]
                        else:
                            sender = iface

                        if "member" in sinfo:
                            member = ".%s" % sinfo["member"]
                        else:
                            member = ""

                        addr = "%s%s" % (iface, member)

                        # save perProc items #
                        procSigList.setdefault(sender, {})
                        procSigList[sender].setdefault(addr, {})
                        if "arg0" in sinfo:
                            argList = [
                                "%s" % sinfo[i]
                                for i in sorted(list(sinfo))
                                if i.startswith("arg")
                            ]
                            procSigList[sender][addr].setdefault(
                                ", ".join(argList)
                            )

                        # save perSignal items #
                        perSigList.setdefault(sender, {})
                        sigProcList = perSigList[sender]
                        sigProcList.setdefault(addr, {})
                        sigProcList[addr].setdefault(procId)

                    if not dbusObj.dbus_message_iter_next(arraySigIterP):
                        break

                if not dbusObj.dbus_message_iter_next(dictIterP):
                    break

            if not dbusObj.dbus_message_iter_next(arrayIterP):
                break

        # clean up #
        dbusObj.dbus_message_unref(msg)
        dbusObj.dbus_message_unref(reply)
        # dbusObj.dbus_connection_unref(conn)

        return perProcList, perSigList

    @staticmethod
    def getServiceProc(bus, service):
        if not bus or not service:
            return

        dbusObj = SysMgr.libdbusObj

        conn = DbusMgr.getBus(bus)
        if not conn:
            return

        # create a message for method call #
        des = "org.freedesktop.DBus"
        path = "/"
        iface = des
        method = "GetConnectionUnixProcessID"
        msg = dbusObj.dbus_message_new_method_call(
            des.encode(), path.encode(), iface.encode(), method.encode()
        )
        if not msg:
            # dbusObj.dbus_connection_unref(conn)
            SysMgr.printWarn("failed to create a D-Bus message")
            return

        # prepare args #
        char = c_char("s".encode())
        DBUS_TYPE_STRING = cast(byref(char), POINTER(c_int)).contents
        null = c_char("\0".encode())
        DBUS_TYPE_INVALID = cast(byref(null), POINTER(c_int)).contents

        # append args #
        item = c_char_p(service.encode())
        res = dbusObj.dbus_message_append_args(
            msg, DBUS_TYPE_STRING, byref(item), DBUS_TYPE_INVALID
        )
        if not res:
            dbusObj.dbus_message_unref(msg)
            # dbusObj.dbus_connection_unref(conn)
            SysMgr.printWarn("failed to append D-Bus message args")
            return

        # call a remote method #
        reply = dbusObj.dbus_connection_send_with_reply_and_block(
            conn, msg, -1, DbusMgr.getErrP()
        )
        if not reply:
            dbusObj.dbus_message_unref(msg)
            # dbusObj.dbus_connection_unref(conn)
            SysMgr.printWarn(
                "failed to call a D-Bus remote method because %s at %s"
                % (DbusMgr.getErrInfo(), SysMgr.getLine())
            )
            return

        # parse args #
        pid = c_uint32(0)
        uint32 = c_char("u".encode())
        DBUS_TYPE_UINT32 = cast(byref(uint32), POINTER(c_int)).contents
        res = dbusObj.dbus_message_get_args(
            reply,
            DbusMgr.getErrP(),
            DBUS_TYPE_UINT32,
            byref(pid),
            DBUS_TYPE_INVALID,
        )
        if not res:
            dbusObj.dbus_message_unref(msg)
            dbusObj.dbus_message_unref(reply)
            # dbusObj.dbus_connection_unref(conn)
            SysMgr.printWarn(
                "failed to parse D-Bus message args because %s"
                % DbusMgr.getErrInfo()
            )
            return

        # clean up #
        dbusObj.dbus_message_unref(msg)
        dbusObj.dbus_message_unref(reply)
        # dbusObj.dbus_connection_unref(conn)

        # get comm #
        comm = SysMgr.getComm(pid.value)
        if not comm:
            comm = "??"

        try:
            return "%s(%s)" % (comm, pid.value)
        except SystemExit:
            sys.exit(0)
        except:
            return

    @staticmethod
    def getBusService(bus, tid=None, addr=None):
        if not bus:
            return

        dbusObj = SysMgr.libdbusObj

        conn = DbusMgr.getBus(bus, tid, addr)
        if not conn:
            return

        # create a message for method call #
        des = "org.freedesktop.DBus"
        path = "/"
        iface = des
        method = "ListNames"

        # send a message for method call #
        msg, reply = DbusMgr.callMethod(
            conn, des, path, iface, method, c_int(3)
        )
        if not msg or not reply:
            return

        # prepare args #
        array = c_char("a".encode())
        DBUS_TYPE_ARRAY = cast(byref(array), POINTER(c_int)).contents
        char = c_char("s".encode())
        DBUS_TYPE_STRING = cast(byref(char), POINTER(c_int)).contents
        null = c_char("\0".encode())
        DBUS_TYPE_INVALID = cast(byref(null), POINTER(c_int)).contents

        # parse args #
        cntRes = c_int(0)
        arrayRes = (POINTER(c_char_p))()
        res = dbusObj.dbus_message_get_args(
            reply,
            DbusMgr.getErrP(),
            DBUS_TYPE_ARRAY,
            DBUS_TYPE_STRING,
            byref(arrayRes),
            byref(cntRes),
            DBUS_TYPE_INVALID,
        )
        if not res:
            dbusObj.dbus_message_unref(msg)
            dbusObj.dbus_message_unref(reply)
            # dbusObj.dbus_connection_unref(conn)
            SysMgr.printWarn(
                "failed to parse D-Bus message args because %s"
                % DbusMgr.getErrInfo()
            )
            return

        slist = []
        for idx in xrange(cntRes.value):
            slist.append(str(arrayRes[idx].decode()))

        dbusObj.dbus_free_string_array(arrayRes)

        # clean up #
        dbusObj.dbus_message_unref(msg)
        dbusObj.dbus_message_unref(reply)
        # dbusObj.dbus_connection_unref(conn)

        return slist

    @staticmethod
    def prepareDbusMethods():
        # get ctypes object #
        SysMgr.importPkgItems("ctypes")

        # try to load libraries #
        try:
            # load libgio library #
            if not SysMgr.libgioObj:
                SysMgr.libgioObj = SysMgr.loadLib(SysMgr.libgioPath)

            # load libgobj library #
            if not SysMgr.libgObj:
                SysMgr.libgObj = SysMgr.loadLib(SysMgr.libgobjPath)

            # load standard libdbus library #
            if not SysMgr.libdbusObj:
                SysMgr.libdbusObj = SysMgr.loadLib(SysMgr.libdbusPath)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to load library to analyze D-Bus packets", True
            )
            sys.exit(-1)

        # define error object #
        class GError(Structure):
            _fields_ = (
                ("domain", c_uint32),
                ("code", c_int),
                ("message", c_char_p),
            )

        DbusMgr.errObj = GError

        # define gobject methods #
        gObj = SysMgr.libgObj

        gObj.g_object_unref.argtypes = [c_void_p]

        # define gio methods #
        gioObj = SysMgr.libgioObj

        gioObj.g_dbus_message_new_from_blob.argtypes = [
            c_char_p,
            c_ulong,
            c_ulong,
            c_void_p,
        ]
        gioObj.g_dbus_message_new_from_blob.restype = c_ulong

        gioObj.g_dbus_message_bytes_needed.argtypes = [
            c_char_p,
            c_ulong,
            c_void_p,
        ]
        gioObj.g_dbus_message_bytes_needed.restype = c_ulong

        gioObj.g_error_free.argtypes = [c_void_p]

        gioObj.g_dbus_message_get_message_type.argtypes = [c_ulong]
        gioObj.g_dbus_message_get_message_type.restype = c_ulong

        gioObj.g_dbus_message_get_arg0.argtypes = [c_ulong]
        gioObj.g_dbus_message_get_arg0.restype = c_char_p

        gioObj.g_dbus_message_get_sender.argtypes = [c_ulong]
        gioObj.g_dbus_message_get_sender.restype = c_char_p

        gioObj.g_dbus_message_get_destination.argtypes = [c_ulong]
        gioObj.g_dbus_message_get_destination.restype = c_char_p

        gioObj.g_dbus_message_get_path.argtypes = [c_ulong]
        gioObj.g_dbus_message_get_path.restype = c_char_p

        gioObj.g_dbus_message_get_signature.argtypes = [c_ulong]
        gioObj.g_dbus_message_get_signature.restype = c_char_p

        gioObj.g_dbus_message_get_interface.argtypes = [c_ulong]
        gioObj.g_dbus_message_get_interface.restype = c_char_p

        gioObj.g_dbus_message_get_member.argtypes = [c_ulong]
        gioObj.g_dbus_message_get_member.restype = c_char_p

        gioObj.g_dbus_message_get_error_name.argtypes = [c_ulong]
        gioObj.g_dbus_message_get_error_name.restype = c_char_p

        gioObj.g_dbus_message_get_serial.argtypes = [c_ulong]
        gioObj.g_dbus_message_get_serial.restype = c_ulong

        gioObj.g_dbus_message_print.argtypes = [c_ulong, c_ulong]
        gioObj.g_dbus_message_print.restype = c_char_p

        gioObj.g_dbus_message_get_reply_serial.argtypes = [c_ulong]
        gioObj.g_dbus_message_get_reply_serial.restype = c_ulong

        # define dbus methods #
        dbusObj = SysMgr.libdbusObj

        dbusObj.dbus_bus_get.argtypes = [c_uint, c_void_p]
        dbusObj.dbus_bus_get.restype = c_void_p

        dbusObj.dbus_connection_open.argtypes = [c_char_p, c_void_p]
        dbusObj.dbus_connection_open.restype = c_void_p

        dbusObj.dbus_connection_open_private.argtypes = [c_char_p, c_void_p]
        dbusObj.dbus_connection_open_private.restype = c_void_p

        dbusObj.dbus_bus_get_private.argtypes = [c_uint, c_void_p]
        dbusObj.dbus_bus_get_private.restype = c_void_p

        dbusObj.dbus_message_iter_init.restype = c_bool
        dbusObj.dbus_message_iter_init.argtypes = [c_void_p, c_void_p]

        dbusObj.dbus_error_init.restype = None
        dbusObj.dbus_error_init.argtypes = [c_void_p]

        dbusObj.dbus_message_iter_next.restype = c_bool
        dbusObj.dbus_message_iter_next.argtypes = [c_void_p]

        dbusObj.dbus_message_iter_get_basic.restype = None
        dbusObj.dbus_message_iter_get_basic.argtypes = [c_void_p, c_void_p]

        dbusObj.dbus_connection_ref.argtypes = [c_void_p]
        dbusObj.dbus_connection_ref.restype = c_void_p

        dbusObj.dbus_message_iter_get_arg_type.restype = c_int
        dbusObj.dbus_message_iter_get_arg_type.argtypes = [c_void_p]

        dbusObj.dbus_message_iter_recurse.restype = None
        dbusObj.dbus_message_iter_recurse.argtypes = [c_void_p, c_void_p]

        dbusObj.dbus_message_iter_get_element_count.restype = c_int
        dbusObj.dbus_message_iter_get_element_count.argtypes = [c_void_p]

        dbusObj.dbus_bus_get_unique_name.argtypes = [c_void_p]
        dbusObj.dbus_bus_get_unique_name.restype = c_char_p

        dbusObj.dbus_connection_close.argtypes = [c_void_p]
        dbusObj.dbus_connection_close.restype = None

        dbusObj.dbus_bus_set_unique_name.argtypes = [c_void_p, c_char_p]
        dbusObj.dbus_bus_set_unique_name.restype = c_bool

        dbusObj.dbus_connection_get_is_connected.argtypes = [c_void_p]
        dbusObj.dbus_connection_get_is_connected.restype = c_bool

        dbusObj.dbus_connection_get_is_authenticated.argtypes = [c_void_p]
        dbusObj.dbus_connection_get_is_authenticated.restype = c_bool

        dbusObj.dbus_connection_get_is_anonymous.argtypes = [c_void_p]
        dbusObj.dbus_connection_get_is_anonymous.restype = c_bool

        dbusObj.dbus_bus_register.argtypes = [c_void_p, c_void_p]
        dbusObj.dbus_bus_register.restype = c_bool

        dbusObj.dbus_parse_address.argtypes = [
            c_void_p,
            c_void_p,
            POINTER(c_int),
            c_void_p,
        ]
        dbusObj.dbus_parse_address.restype = c_bool

        dbusObj.dbus_bus_request_name.argtypes = [
            c_void_p,
            c_char_p,
            c_uint,
            c_void_p,
        ]
        dbusObj.dbus_bus_request_name.restype = c_int

        dbusObj.dbus_message_unref.argtypes = [c_void_p]
        dbusObj.dbus_message_unref.restype = None

        dbusObj.dbus_connection_unref.argtypes = [c_void_p]
        dbusObj.dbus_connection_unref.restype = None

        dbusObj.dbus_message_new_method_call.argtypes = [
            c_char_p,
            c_char_p,
            c_char_p,
            c_char_p,
        ]
        dbusObj.dbus_message_new_method_call.restype = c_void_p

        dbusObj.dbus_connection_send_with_reply_and_block.argtypes = [
            c_void_p,
            c_void_p,
            c_int,
            c_void_p,
        ]
        dbusObj.dbus_connection_send_with_reply_and_block.restype = c_void_p

        dbusObj.dbus_message_get_args.argtypes = [c_void_p, c_void_p, c_int]
        dbusObj.dbus_message_get_args.restype = c_bool

        dbusObj.dbus_message_append_args.argtypes = [c_void_p, c_int]
        dbusObj.dbus_message_append_args.restype = c_bool

        dbusObj.dbus_message_demarshal.argtypes = [c_char_p, c_int, c_void_p]
        dbusObj.dbus_message_demarshal.restype = c_ulong

        dbusObj.dbus_message_demarshal_bytes_needed.argtypes = [
            c_char_p,
            c_int,
        ]
        dbusObj.dbus_message_demarshal_bytes_needed.restype = c_int

        dbusObj.dbus_message_get_interface.argtypes = [c_void_p]
        dbusObj.dbus_message_get_interface.restype = c_char_p

        dbusObj.dbus_message_get_type.argtypes = [c_void_p]
        dbusObj.dbus_message_get_type.restype = c_int

    @staticmethod
    def printIntrospection(tid, introList):
        procId = "%s(%s)" % (SysMgr.getComm(tid, cache=True), tid)

        if not introList:
            SysMgr.printErr("no introspection for %s" % procId)
            return

        # print title #
        SysMgr.printPipe(
            "\n[D-Bus Introspection Info] <Target: %s>\n%s" % (procId, twoLine)
        )

        # print introspection #
        for name, value in introList.items():
            if not value:
                continue
            SysMgr.printPipe(
                "\n[%s]\n%s%s%s\n" % (name, oneLine, value, oneLine)
            )

    @staticmethod
    def printStatInfo(tid, statList):
        conv = UtilMgr.convNum
        procId = "%s(%s)" % (SysMgr.getComm(tid, cache=True), tid)

        if not statList:
            SysMgr.printErr("no stat for %s" % procId)
            return

        # print title #
        SysMgr.printPipe(
            "\n[D-Bus Stat Info] <Target: %s>\n%s" % (procId, twoLine)
        )
        SysMgr.printPipe(
            "{0:^32} {1:<16}\n{2:1}".format("Name", "Value", oneLine)
        )

        # print stats #
        for name, value in statList.items():
            if value:
                value = " ".join(list(map(conv, value)))
            else:
                value = "N/A"

            SysMgr.printPipe("{0:<32} {1:>16}".format(name, value))

        SysMgr.printPipe(oneLine)

    @staticmethod
    def printSignalInfo(tid, perProc, perSig, procInfo):
        conv = UtilMgr.convNum
        totalSubscription = 0
        procId = "%s(%s)" % (SysMgr.getComm(tid, cache=True), tid)

        if not perProc and not perSig:
            SysMgr.printErr("no subscription info for %s" % procId)
            return

        # create a table for perProc signals #
        nrPerProcSignals = {}
        for cli, items in perProc.items():
            nrPerProcSignals.setdefault(
                cli, dict({"nrStub": 0, "nrSignal": 0})
            )

            for sender, iface in items.items():
                nrPerProcSignals[cli]["nrStub"] += 1
                nrPerProcSignals[cli]["nrSignal"] += len(iface)
                totalSubscription += len(iface)

        # print perProc signals #
        SysMgr.printPipe(
            (
                "\n[D-Bus Signal Proxy Info] (Target: %s) "
                "(nrProc: %s) (nrSub: %s)\n%s"
            )
            % (procId, conv(len(perProc)), conv(totalSubscription), twoLine)
        )

        SysMgr.printPipe(
            "{0:^23} {1:<23} {2:^10} {3:>1}\n{4:1}".format(
                "Client", "Server", "Interface", "Args", oneLine
            )
        )

        for cli, stats in sorted(
            nrPerProcSignals.items(),
            key=lambda e: e[1]["nrSignal"],
            reverse=True,
        ):
            if cli in procInfo:
                proc = procInfo[cli]
            else:
                proc = cli

            # print signal stat #
            mergedList = {}
            for sender, iface in perProc[cli].items():
                if sender in procInfo:
                    sender = procInfo[sender]
                else:
                    tokens = sender.split(".")
                    pos = len(tokens) - 1
                    while 1:
                        if pos == 0:
                            break

                        key = ".".join(tokens[:pos])
                        if key in procInfo:
                            procInfo[sender] = procInfo[key]
                            sender = procInfo[key]
                            break

                        pos -= 1

                if sender in mergedList:
                    mergedList[sender].update(iface)
                else:
                    mergedList[sender] = dict(iface)

            # print process stat #
            SysMgr.printPipe(
                "{0:>23} <nrStub: {1:1}, nrSignal: {2:1}>".format(
                    proc, conv(len(mergedList)), conv(stats["nrSignal"])
                )
            )

            # print signal stat #
            for sender, iface in sorted(
                mergedList.items(), key=lambda e: len(e[1]), reverse=True
            ):
                SysMgr.printPipe(
                    "{0:>23} {1:<23} <nrSignal: {2:1}>".format(
                        " ", sender, conv(len(iface))
                    )
                )
                if not SysMgr.showAll:
                    continue

                for name, arg in sorted(iface.items()):
                    SysMgr.printPipe(
                        "{0:>23} {0:<23} {1:<12}".format(" ", name)
                    )
                    for key in sorted(list(arg)):
                        SysMgr.printPipe(
                            "{0:>23} {0:<23} {0:<10} ({1:<1})".format(" ", key)
                        )
            SysMgr.printPipe(oneLine)
        if not nrPerProcSignals:
            SysMgr.printPipe("\tNone\n%s" % oneLine)

        # create a table for perSignal processes #
        nrPerSigProcs = {}
        for sender, items in perSig.items():
            if sender in procInfo:
                proc = procInfo[sender]
            else:
                proc = sender

            initDict = {"proxyList": {}, "nrSignal": 0, "interface": {}}

            nrPerSigProcs.setdefault(proc, dict(initDict))
            nrPerSigProcs[proc]["interface"].setdefault(sender, {})
            nrPerSigProcs[proc]["interface"][sender].update(items)

            nrPerSigProcs[proc]["nrSignal"] += len(items)
            for iface, receiver in items.items():
                nrPerSigProcs[proc]["proxyList"].update(receiver)

        # print perSignal processes #
        SysMgr.printPipe(
            (
                "\n[D-Bus Signal Stub Info] (Target: %s) "
                "(nrProc: %s) (nrSub: %s)\n%s"
            )
            % (procId, conv(len(perSig)), conv(totalSubscription), twoLine)
        )

        SysMgr.printPipe(
            "{0:^23} {1:^12} {2:<23}\n{3:1}".format(
                "Server", "Interface", "Client", oneLine
            )
        )

        for serv, stats in sorted(
            nrPerSigProcs.items(),
            key=lambda e: len(e[1]["proxyList"]),
            reverse=True,
        ):
            # print stub process stat #
            SysMgr.printPipe(
                "{0:>23} <nrProxy: {1:1}, nrSignal: {2:1}>".format(
                    serv,
                    conv(len(stats["proxyList"])),
                    conv(stats["nrSignal"]),
                )
            )

            # print interface stat #
            for iface, receiver in sorted(
                stats["interface"].items(),
                key=lambda e: len(e[1]),
                reverse=True,
            ):
                procList = {}
                for signame, procs in receiver.items():
                    procList.update(procs)

                SysMgr.printPipe(
                    "{0:>23} {1:<12} <nrProxy: {2:1}> <nrSignal: {3:1}>".format(
                        " ", iface, conv(len(procList)), conv(len(receiver))
                    )
                )

                if not SysMgr.showAll:
                    continue

                for signame, procs in sorted(
                    receiver.items(), key=lambda e: len(e[1]), reverse=True
                ):
                    SysMgr.printPipe(
                        "{0:>23} {1:<12} {2:<23} [nrProxy: {3:<1}]".format(
                            " ", " ", signame, conv(len(procs))
                        )
                    )
                    procs = [
                        procInfo[name] if name in procInfo else name
                        for name in list(procs)
                    ]
                    # print proxy process stat #
                    for name in sorted(procs):
                        if name in procInfo:
                            cproc = procInfo[name]
                        else:
                            cproc = name

                        SysMgr.printPipe(
                            "{0:>23} {0:<12} {0:<12} {1:<1}".format(" ", cproc)
                        )
            SysMgr.printPipe(oneLine)
        if not nrPerSigProcs:
            SysMgr.printPipe("\tNone\n%s" % oneLine)

    @staticmethod
    def runDbusSnooper(mode="top"):
        def _updateTaskInfo(dbusData, sentData, recvData):
            try:
                taskManager.saveSystemStat()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("failed to update system stat", True)

            convNum = UtilMgr.convNum
            convertSize = UtilMgr.convSize2Unit
            convertColor = UtilMgr.convColor

            for pid in taskList:
                try:
                    if pid not in dbusData:
                        continue

                    dbusList = []

                    # build D-Bus usage string #
                    dbusCnt = dbusData[pid]["totalCnt"]
                    dbusList.append(
                        "[TOTAL]: %s / [TYPE]: %s"
                        % (convNum(dbusCnt), convNum(len(dbusData[pid]) - 1))
                    )

                    for name, value in sorted(
                        dbusData[pid].items(),
                        key=lambda x: x[1]["cnt"] if x[0] != "totalCnt" else 0,
                        reverse=True,
                    ):

                        if name == "totalCnt" or value["cnt"] == 0:
                            continue

                        try:
                            per = long((value["cnt"] / float(dbusCnt)) * 100)
                        except SystemExit:
                            sys.exit(0)
                        except:
                            per = 0

                        # get time info #
                        if pid in sentData and name in sentData[pid]:
                            data = sentData[pid][name]
                        elif pid in recvData and name in recvData[pid]:
                            data = recvData[pid][name]
                        else:
                            continue

                        # get complete count and status #
                        cnt = data["cnt"]
                        if data["time"] > 0:
                            wstat = "/WAIT"
                        else:
                            wstat = ""

                        # get complete call count #
                        if cnt > 0:
                            avr = data["total"] / cnt
                        else:
                            avr = 0

                        # check error #
                        if data["err"] > 0:
                            errstr = ", Err: %s" % data["err"]
                        else:
                            errstr = ""

                        # set color #
                        try:
                            mtype, stats = name.lstrip("[").split("]", 1)
                            mtype = DbusMgr.msgColorList[mtype.strip()]
                            name = "[%s]%s" % (mtype, stats)
                        except SystemExit:
                            sys.exit(0)
                        except:
                            pass

                        if data["max"] > 0:
                            name = (
                                "%s {Min: %.3f, Avr: %.3f, Max: %.3f%s}%s"
                            ) % (
                                name,
                                data["min"],
                                avr,
                                data["max"],
                                errstr,
                                wstat,
                            )

                        count = convNum(value["cnt"])
                        size = convertSize(data["size"], isInt=True)

                        dbusList.append(
                            "{0:>4}({1:>5}/{2:>3}%) {3:1}".format(
                                count, size, per, name
                            )
                        )

                    # add D-Bus usage #
                    taskManager.procData[pid]["dbusList"] = dbusList
                    taskManager.procData[pid]["dbusCnt"] = dbusCnt
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printWarn(
                        "failed to update task info", True, reason=True
                    )

        def _printSummary(signum, frame):
            def _checkRepeatCnt():
                # check user event #
                if SysMgr.condExit:
                    if SysMgr.repeatCount == 0:
                        SysMgr.printWarn("terminated by user\n", True)
                    os.kill(SysMgr.pid, signal.SIGINT)
                    return
                elif SysMgr.repeatCount == 0:
                    return

                # check timer event #
                SysMgr.progressCnt += 1
                if SysMgr.repeatCount <= SysMgr.progressCnt:
                    SysMgr.printWarn("terminated by timer\n", True)
                    if SysMgr.outPath:
                        SysMgr.removeExitFunc(_printSummary, [0, 0])
                    sys.exit(0)

            # check repeat count #
            if SysMgr.checkMode("printdbus"):
                _checkRepeatCnt()
                return

            # disable alarm #
            signal.alarm(0)

            # check user input #
            SysMgr.waitUserInput(0.000001)

            # acquire lock for shared stats #
            if lock:
                lock.acquire()

            # initialize data #
            prevRecvData = DbusMgr.recvData
            prevSentData = DbusMgr.sentData
            DbusMgr.sentData = {}
            DbusMgr.recvData = {}
            DbusMgr.msgSentTable = {}
            DbusMgr.msgRecvTable = {}
            prevDbusData = TaskAnalyzer.dbusData
            TaskAnalyzer.dbusData = {"totalCnt": 0, "totalErr": 0}

            # release lock for shared stats #
            if lock and lock.locked():
                try:
                    lock.release()
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

            convNum = UtilMgr.convNum

            # update CPU usage of tasks #
            _updateTaskInfo(prevDbusData, prevSentData, prevRecvData)

            if DbusMgr.dbgObj:
                # get CPU usage for myself #
                cpuUsage = DbusMgr.dbgObj.getCpuUsage(system=True)
                diff = SysMgr.uptimeDiff
                ttime = cpuUsage[0] / diff
                utime = cpuUsage[1] / diff
                stime = cpuUsage[2] / diff
                mcpu = "%d%%" % ttime
                mcpu = UtilMgr.convCpuColor(ttime, mcpu)
                mcpuStr = "%s(U%d%%+S%d%%)" % (mcpu, utime, stime)

                # get memory usage for myself #
                rssStr = DbusMgr.dbgObj.getMemUsage()

                # get CPU usage for system #
                ctime = 100 - (cpuUsage[3] / diff)
                ctime = ctime if ctime > 0 else 0
                sysCpuStr = "%d%%" % ctime
                sysCpuStr = UtilMgr.convCpuColor(ctime, sysCpuStr)

                # get available memory for system #
                sysMemStr = SysMgr.getAvailMemInfo()
            else:
                cpuStr = mcpuStr = rssStr = sysCpuStr = sysMemStr = "?"

            # set error #
            nrErr = prevDbusData["totalErr"]
            if nrErr > 0:
                nrErr = UtilMgr.convColor(convNum(nrErr), "RED")
            else:
                nrErr = convNum(nrErr)

            # print title #
            SysMgr.addPrint(
                (
                    "[%s] [Time: %7.3f] [Interval: %.1f] "
                    "[NrMsg: %s] [NrErr: %s] [SYS: %s/%s] [%s(%s): %s/%s] \n"
                )
                % (
                    "D-Bus Info",
                    SysMgr.uptime,
                    SysMgr.uptimeDiff,
                    convNum(prevDbusData["totalCnt"]),
                    nrErr,
                    sysCpuStr,
                    sysMemStr,
                    DbusMgr.dbgObj.comm,
                    DbusMgr.dbgObj.pid,
                    mcpuStr,
                    rssStr,
                )
            )

            # print resource usage of tasks #
            taskManager.printSystemUsage()
            taskManager.printTaskUsage()
            taskManager.reinitStats()
            SysMgr.printTopStats()

            # reset timer #
            if signum:
                # check repeat count #
                _checkRepeatCnt()

                # update timer #
                SysMgr.updateTimer()

        def _executeLoop(rdPipeList):
            tid = SysMgr.syscall("gettid")

            # main thread #
            if SysMgr.pid == tid:
                SysMgr.updateUptime()

                # update stats #
                _updateTaskInfo(
                    TaskAnalyzer.dbusData, DbusMgr.sentData, DbusMgr.recvData
                )

                # save initial stat of tasks #
                taskManager.reinitStats()

                # set timer #
                signal.signal(signal.SIGALRM, _printSummary)
                SysMgr.updateTimer()

                # set handler for exit #
                if mode == "top":
                    signal.signal(signal.SIGINT, SysMgr.exitHandler)
                    if SysMgr.outPath:
                        SysMgr.addExitFunc(_printSummary, [0, 0])
                    SysMgr.addExitFunc(SysMgr.stopHandler, [0, 0])

            while 1:
                if not rdPipeList:
                    return

                # multi-threaded loop #
                if threadingList:
                    # sibling thread #
                    if SysMgr.pid != tid:
                        _updateDataFromPipe(rdPipeList)
                    # main thread #
                    else:
                        try:
                            signal.pause()
                        except SystemExit:
                            sys.exit(0)
                        except:
                            break
                # single-threaded loop #
                else:
                    _updateDataFromPipe(rdPipeList)

        def _updateData(data):
            tid, params, bus, service = data

            # convert string to dict #
            jsonData = UtilMgr.convStr2Dict(params)
            if not jsonData:
                return

            # check message #
            try:
                ctype = jsonData["name"]

                # check time #
                if jsonData["type"] != "enter":
                    return
            except SystemExit:
                sys.exit(0)
            except:
                return

            # check args #
            try:
                if ctype == "sendmsg" or ctype == "recvmsg":
                    if type(jsonData["args"]["msg"]) is dict:
                        msgList = jsonData["args"]["msg"]["msg_iov"]
                        _handleMsg(ctype, msgList, jsonData, data)
                elif ctype == "sendmmsg" or ctype == "recvmmsg":
                    for idx, value in jsonData["args"]["msg"].items():
                        msgList = value["msg_iov"]
                        _handleMsg(ctype, msgList, jsonData, data)
                else:
                    return
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn(
                    "failed to handle %s for %s(%s)"
                    % ([jsonData], jsonData["comm"], jsonData["tid"]),
                    reason=True,
                )

        def _handleMsg(ctype, msgList, jsonData, data):
            if type(msgList) is not dict:
                return

            try:
                tid, params, bus, service = data

                mlist = {}
                cnt = 0
                gdmsg = 0

                gioObj = SysMgr.libgioObj
                libgObj = SysMgr.libgObj
                G_IO_ERROR_TYPE = DbusMgr.G_IO_ERROR_TYPE
                isTopMode = DbusMgr.isTopMode

                msgs = []
                for key, msg in sorted(msgList.items()):
                    msgs.append(msg)

                for idx, msg in enumerate(msgs):
                    # get message info #
                    length = msg["len"]
                    ecall = msg["data"]

                    # free gdbus message object #
                    if gdmsg != 0:
                        libgObj.g_object_unref(gdmsg)
                        gdmsg = 0

                    # decode from base64 #
                    call = UtilMgr.decodeBase64(ecall)
                    if type(call) is bytes:
                        call = call.decode("latin-1")

                    # check message sequence #
                    isFirst = isLast = False
                    if idx == 0:
                        isFirst = True
                    if idx == len(msgs) - 1:
                        isLast = True

                    # update message size #
                    if length == 0:
                        length = len(call)

                    # check message size #
                    if length == 0:
                        TaskAnalyzer.dbusData["totalErr"] += 1
                        continue

                    # recover data #
                    if len(call) > length:
                        call = call[:length]
                    elif len(call) < length:
                        call = call + ("\0" * (length - len(call)))

                    # check previous data #
                    if not tid in DbusMgr.prevData:
                        DbusMgr.prevData[tid] = {}
                        DbusMgr.prevData[tid]["recvmsg"] = ""
                        DbusMgr.prevData[tid]["sendmsg"] = ""

                    try:
                        prevData = DbusMgr.prevData[tid][ctype]
                    except:
                        prevData = ""

                    # check direction #
                    if ctype.startswith("sendm"):
                        direction = "OUT"
                        data = DbusMgr.sentData
                        msgTable = DbusMgr.msgSentTable
                    else:
                        direction = "IN"
                        data = DbusMgr.recvData
                        msgTable = DbusMgr.msgRecvTable

                    # composite data #
                    if isLast:
                        if DbusMgr.prevData[tid][ctype]:
                            call = DbusMgr.prevData[tid][ctype] + call

                        if direction == "OUT":
                            DbusMgr.prevData[tid][ctype] = ""
                        else:
                            DbusMgr.prevData[tid][ctype] = call
                    else:
                        if isFirst:
                            if direction == "OUT":
                                DbusMgr.prevData[tid][ctype] = call
                            else:
                                DbusMgr.prevData[tid][ctype] += call
                        else:
                            DbusMgr.prevData[tid][ctype] += call

                        continue

                    # check message size #
                    if len(call) < 16:
                        continue

                    # cast bytes to void_p #
                    buf = c_char_p(call.encode("latin-1"))

                    errp = POINTER(DbusMgr.errObj)()

                    # check message size in header #
                    hsize = gioObj.g_dbus_message_bytes_needed(
                        buf, c_ulong(len(call)), byref(errp)
                    )
                    if direction == "OUT" and errp:
                        SysMgr.printWarn(
                            (
                                "failed to handle D-Bus message %s for %s(%s) "
                                "because %s(%s)"
                            )
                            % (
                                [call],
                                jsonData["comm"],
                                jsonData["tid"],
                                G_IO_ERROR_TYPE[errp.contents.code],
                                errp.contents.message,
                            )
                        )
                        gioObj.g_error_free(byref(errp.contents))
                        TaskAnalyzer.dbusData["totalErr"] += 1
                        continue
                    elif direction == "OUT" and hsize > len(call):
                        continue

                    # handle incoming data #
                    if direction == "IN":
                        if hsize > len(call):
                            continue
                        else:
                            DbusMgr.prevData[tid][ctype] = ""

                    # create GDBusMessage from bytes #
                    gdmsg = gioObj.g_dbus_message_new_from_blob(
                        buf, c_ulong(len(call)), 0, byref(errp)
                    )

                    # check error #
                    if not gdmsg and errp:
                        SysMgr.printWarn(
                            (
                                "failed to handle D-Bus message %s for %s(%s) "
                                "because %s(%s)"
                            )
                            % (
                                [call],
                                jsonData["comm"],
                                jsonData["tid"],
                                G_IO_ERROR_TYPE[errp.contents.code],
                                errp.contents.message,
                            )
                        )
                        gioObj.g_error_free(byref(errp.contents))
                        TaskAnalyzer.dbusData["totalErr"] += 1
                        continue

                    # get address of the message #
                    addr = c_ulong(gdmsg)

                    # get sender #
                    srcInfo = "??"
                    src = gioObj.g_dbus_message_get_sender(addr)
                    if src:
                        if type(src) is bytes:
                            src = src.decode()
                        srcInfo = src

                        if service:
                            if src in service:
                                srcInfo = service[src]
                            else:
                                service[src] = src
                                ret = _updateServiceProc(bus, tid, service)
                                if src in service:
                                    srcInfo = service[src]

                    # get receiver #
                    desInfo = "??"
                    des = gioObj.g_dbus_message_get_destination(addr)
                    if des:
                        if type(des) is bytes:
                            des = des.decode()
                        desInfo = des

                        if service:
                            if des in service:
                                desInfo = service[des]
                            else:
                                service[des] = des
                                ret = _updateServiceProc(bus, tid, service)
                                if des in service:
                                    desInfo = service[des]

                    # get message type #
                    try:
                        nrType = gioObj.g_dbus_message_get_message_type(addr)
                        mtype = DbusMgr.GDBusMessageType[nrType]
                    except SystemExit:
                        sys.exit(0)
                    except:
                        SysMgr.printWarn(
                            "failed to get type of GDBusMessage", reason=True
                        )
                        TaskAnalyzer.dbusData["totalErr"] += 1
                        continue

                    effectiveReply = False
                    if mtype == "RETURN":
                        # get reply-serial #
                        repSerial = gioObj.g_dbus_message_get_reply_serial(
                            c_ulong(gdmsg)
                        )
                        if repSerial in msgTable:
                            effectiveReply = True
                        else:
                            effectiveReply = False

                    # print message #
                    if not isTopMode or SysMgr.customCmd:
                        if len(jsonData["backtrace"]) > 2:
                            backtrace = (
                                "Backtrace: %s\n" % jsonData["backtrace"]
                            )
                        else:
                            backtrace = ""

                        if isTopMode or SysMgr.showAll:
                            addInfo = "\n%s%s" % (
                                gioObj.g_dbus_message_print(
                                    c_ulong(gdmsg), c_ulong(0)
                                ).decode(),
                                backtrace,
                            )
                        else:
                            """
                            path = gioObj.g_dbus_message_get_path(addr)
                            if not path:
                                path = b''
                            """

                            iface = gioObj.g_dbus_message_get_interface(addr)
                            if not iface:
                                iface = b""

                            member = gioObj.g_dbus_message_get_member(addr)
                            if not member:
                                member = b""

                            addInfo = " %s.%s" % (
                                iface.decode(),
                                member.decode(),
                            )
                            addInfo = UtilMgr.convColor(addInfo, "GREEN")

                        # get serial number #
                        serial = gioObj.g_dbus_message_get_serial(addr)
                        if not serial:
                            serial = b""

                        msgStr = "[%s] %.6f %s(%s) %3s %s->%s %s %sB%s" % (
                            DbusMgr.msgColorList[mtype],
                            jsonData["time"],
                            jsonData["comm"],
                            tid,
                            direction,
                            srcInfo,
                            desInfo,
                            serial,
                            UtilMgr.convSize2Unit(hsize),
                            addInfo,
                        )

                        # check skip condition #
                        if effectiveReply:
                            pass
                        elif SysMgr.customCmd and not UtilMgr.isValidStr(
                            msgStr, SysMgr.customCmd, ignCap=True
                        ):
                            continue

                        # finish printing this message #
                        if not isTopMode:
                            SysMgr.printPipe(msgStr, flush=True)

                            # check log command #
                            SysMgr.checkLogCond(msgStr, DbusMgr.watchList)

                            continue

                    # set task default dict #
                    DbusMgr.sentData.setdefault(tid, {})
                    DbusMgr.recvData.setdefault(tid, {})

                    # return check #
                    if mtype == "RETURN":
                        if effectiveReply:
                            targetIf, prevTime = msgTable[repSerial]
                        else:
                            targetIf = prevTime = None

                        # handle method return #
                        if targetIf in data[tid] and prevTime:
                            lastData = data[tid][targetIf]
                            elapsed = jsonData["time"] - prevTime

                            if (
                                lastData["min"] == 0
                                or elapsed < lastData["min"]
                            ):
                                data[tid][targetIf]["min"] = elapsed

                            if elapsed > lastData["max"]:
                                data[tid][targetIf]["max"] = elapsed

                            data[tid][targetIf]["total"] += elapsed
                            data[tid][targetIf]["cnt"] += 1
                            data[tid][targetIf]["time"] = 0

                        continue

                    # get properties from message #
                    # path = gioObj.g_dbus_message_get_path(addr)
                    interface = gioObj.g_dbus_message_get_interface(addr)
                    member = gioObj.g_dbus_message_get_member(addr)
                    arg0 = gioObj.g_dbus_message_get_arg0(addr)
                    serial = gioObj.g_dbus_message_get_serial(addr)

                    # handle error message #
                    if mtype == "ERROR" or mtype == "INVALID":
                        ename = gioObj.g_dbus_message_get_error_name(addr)
                        if not ename:
                            continue

                        mname = "[%6s] %3s %s: %s" % (
                            mtype,
                            direction,
                            ename.decode(),
                            arg0.decode(),
                        )
                        data[tid].setdefault(mname, dict(DbusMgr.taskInfo))
                        data[tid][mname]["cnt"] += 1
                        data[tid][mname]["err"] += 1
                        TaskAnalyzer.dbusData["totalErr"] += 1
                    # handle normal message #
                    else:
                        mname = "[%6s] %3s %s.%s" % (
                            mtype,
                            direction,
                            interface.decode(),
                            member.decode(),
                        )

                    # save serial number except for signal #
                    if mtype != "SIGNAL":
                        msgTable[serial] = (mname, jsonData["time"])

                    # initialize new interface #
                    data[tid].setdefault(mname, dict(DbusMgr.taskInfo))

                    # increase count #
                    cnt += 1
                    if mname not in mlist:
                        mlist[mname] = {"count": 1}
                    else:
                        mlist[mname]["count"] += 1

                    # increase size #
                    data[tid][mname]["size"] += hsize

                    # save timestamp #
                    data[tid][mname]["time"] = jsonData["time"]

                if cnt == 0:
                    return

                # acquire lock #
                if lock:
                    lock.acquire()

                # increase count #
                if tid not in TaskAnalyzer.dbusData:
                    TaskAnalyzer.dbusData[tid] = {"totalCnt": cnt}
                else:
                    TaskAnalyzer.dbusData[tid]["totalCnt"] += cnt

                TaskAnalyzer.dbusData["totalCnt"] += cnt

                # merge D-Bus interface #
                for name, value in mlist.items():
                    try:
                        TaskAnalyzer.dbusData[tid][name]["cnt"] += value[
                            "count"
                        ]
                    except SystemExit:
                        sys.exit(0)
                    except:
                        TaskAnalyzer.dbusData[tid][name] = {}
                        TaskAnalyzer.dbusData[tid][name]["cnt"] = value[
                            "count"
                        ]
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn(
                    "failed to handle %s" % [jsonData], reason=True
                )
            finally:
                # free gdbus message object #
                if gdmsg != 0:
                    libgObj.g_object_unref(gdmsg)

                # release lock #
                if lock and lock.locked():
                    try:
                        lock.release()
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass

        def _updateDataFromPipe(rdPipeList):
            # merge dbus data #
            try:
                tid = comm = None

                # wait for event #
                [read, write, error] = selectObj.select(rdPipeList, [], [])

                # read messages through pipe connected to child processes #
                for robj in read:
                    tid = None
                    bus = None
                    service = None

                    # get tid of target #
                    try:
                        index = pipeList.index(robj)
                        tid = taskList[index]
                        bus = busList[index]
                        service = busServiceList[tid][bus]
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass

                    # handle data arrived #
                    while 1:
                        if SysMgr.condExit:
                            return

                        output = robj.readline()
                        if output == "\n":
                            continue
                        elif output == "":
                            try:
                                rdPipeList.remove(robj)
                            except SystemExit:
                                sys.exit(0)
                            except:
                                pass
                        elif output and len(output) > 0:
                            _updateData((tid, output, bus, service))

                        break
            except SystemExit:
                sys.exit(0)
            except:
                comm = SysMgr.getComm(tid, cache=True)

                if tid:
                    procInfo = " for %s(%s)" % (comm, tid)
                else:
                    procInfo = ""

                SysMgr.printWarn(
                    "failed to read data from pipe%s" % procInfo, reason=True
                )

                return

        def _updateServiceProc(bus, tid, serviceList, addr=None):
            """
            some case, hang up for remote call with below error message.
            so disable this feature.

            "the remote application did not send a reply,
            the message bus security policy blocked the reply,
            the reply timeout expired, or the network connection was broken"
            """
            return False

            if not bus:
                return False

            services = DbusMgr.getBusService(bus, tid=tid, addr=None)
            if not services:
                return False

            # register process #
            for idx, svc in enumerate(services):
                pinfo = DbusMgr.getServiceProc(bus, svc)
                if pinfo:
                    serviceList[svc] = pinfo

            return True

        def _getDefaultTasks(comm, sibling=True):
            taskList = []
            tempList = SysMgr.getTids(comm, sibling=sibling)
            for tid in tempList:
                taskList.append(SysMgr.getTgid(tid))

                comm = SysMgr.getComm(tid, cache=True)
                if comm == "gdbus":
                    taskList.append(tid)

            return taskList

        # check essential json module #
        SysMgr.getPkg("json")

        # check permission #
        SysMgr.checkRootPerm()

        # check filter #
        taskList = []
        if not SysMgr.filterGroup:
            if SysMgr.hasMainArg():
                onlyDaemon = False
                items = SysMgr.getMainArgs()
                for val in items:
                    if SysMgr.groupProcEnable:
                        taskList += SysMgr.getTids(val, sibling=True)
                    else:
                        taskList += _getDefaultTasks(val)
            else:
                onlyDaemon = True
                taskList += _getDefaultTasks("dbus-daemon")
                taskList += _getDefaultTasks("dbus-broker")
        else:
            onlyDaemon = False
            for val in SysMgr.filterGroup:
                if SysMgr.groupProcEnable:
                    taskList += SysMgr.getTids(val, sibling=True)
                else:
                    taskList += _getDefaultTasks(val)

        # check task list #
        if not taskList:
            SysMgr.printErr("failed to find task to analyze D-Bus message")
            sys.exit(-1)
        else:
            # remove redundant tasks #
            taskList = UtilMgr.cleanItem(taskList)
            taskList.sort(key=int)
            SysMgr.printInfo(
                (
                    "only specific processes that are involved "
                    "in the process group [ %s ] are shown"
                )
                % SysMgr.getCommList(taskList)
            )

        # prepare D-Bus methods to analyze BLOB data #
        DbusMgr.prepareDbusMethods()

        # get select object #
        selectObj = SysMgr.getPkg("select")

        # get threading object #
        threadObj = SysMgr.getPkg("threading", False)
        if threadObj:
            lock = threadObj.Lock()
        else:
            lock = None

        # initialize task stat #
        DbusMgr.dbgObj = Debugger(SysMgr.pid, attach=False)
        DbusMgr.dbgObj.initValues()
        DbusMgr.dbgObj.getCpuUsage(system=True)
        DbusMgr.isTopMode = SysMgr.checkMode("dbustop")

        # define common list #
        busList = []
        pipeList = []
        busServiceList = {}
        gBusServiceList = {}
        interfaceList = {}
        threadingList = []
        SysMgr.filterGroup = taskList

        # get item for log filter #
        if "WATCHLOG" in SysMgr.environList:
            DbusMgr.watchList = SysMgr.environList["WATCHLOG"][0].split("+")

        # initialize system stat #
        SysMgr.exceptCommFilter = True
        taskManager = TaskAnalyzer(onlyInstance=True)
        taskManager.saveSystemStat()
        SysMgr.sort = "d"
        SysMgr.processEnable = False
        SysMgr.cmdlineEnable = True

        # set target syscalls #
        if not onlyDaemon:
            SysMgr.syscallList.append(SysMgr.getNrSyscall("sys_recvmsg"))
            SysMgr.syscallList.append(SysMgr.getNrSyscall("sys_recvmmsg"))
        SysMgr.syscallList.append(SysMgr.getNrSyscall("sys_sendmsg"))
        SysMgr.syscallList.append(SysMgr.getNrSyscall("sys_sendmmsg"))

        # set colors for each message types #
        DbusMgr.msgColorList = {
            "INVALID": UtilMgr.convColor("INVALI", "RED", 6),
            "ERROR": UtilMgr.convColor("ERROR", "RED", 6),
            "METHOD": UtilMgr.convColor("METHOD", "CYAN", 6),
            "RETURN": UtilMgr.convColor("RETURN", "BLUE", 6),
            "SIGNAL": UtilMgr.convColor("SIGNAL", "PINK", 6),
        }

        # create a sync lock #
        syncLock = Debugger.getGlobalLock(SysMgr.pid, exit=False)
        if syncLock:
            lockf(syncLock, LOCK_EX)  # pylint: disable=undefined-variable

        # create child processes to monitor each targets #
        for tid in taskList:
            # create pipe #
            rd, wr = os.pipe()

            # get cmdline for parent #
            try:
                ppidIdx = SysMgr.topInstance.ppidIdx
                ppid = taskManager.procData[tid]["stat"][ppidIdx]
                cmdline = SysMgr.getCmdline(ppid)
            except SystemExit:
                sys.exit(0)
            except:
                cmdline = ""

            # get bus type #
            bus = None
            listen = None
            introList = {}
            cmdline += SysMgr.getCmdline(tid)
            if "--system" in cmdline:
                bus = "system"
            elif "--session" in cmdline:
                bus = "session"
            elif "--scope system" in cmdline:
                bus = "system"
            elif "--scope user" in cmdline:
                bus = "user"
            elif "--config-file=" in cmdline:
                try:
                    cpath = cmdline.split("--config-file=", 1)[1]
                    pos = cpath.find(" --")
                    if pos > 0:
                        cpath = cpath[:pos]

                    with open(cpath, "r") as fd:
                        for item in fd.readlines():
                            item = item.strip()
                            if item.startswith("<listen>"):
                                item = UtilMgr.lstrip(item, "<listen>")
                                item = UtilMgr.rstrip(item, "</listen>")
                                item = item.strip()
                                listen = item
                            if item.startswith("<type>"):
                                item = UtilMgr.lstrip(item, "<type>")
                                item = UtilMgr.rstrip(item, "</type>")
                                item = item.strip()
                                bus = item
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printWarn("failed to get D-Bus config", reason=True)
            busList.append(bus)

            # get service list #
            if bus:
                services = DbusMgr.getBusService(bus, tid=tid, addr=listen)
            else:
                services = None

            # register services #
            busServiceList.setdefault(tid, {})
            if services:
                busProcList = {}

                # register process #
                for idx, service in enumerate(services):
                    pinfo = DbusMgr.getServiceProc(bus, service)
                    busProcList[service] = pinfo
                    gBusServiceList.setdefault(service, pinfo)

                    # register methods and properties #
                    if mode == "printintro":
                        # get service tid #
                        if pinfo:
                            ptid = pinfo[pinfo.rfind("(") + 1 : -1]
                        else:
                            ptid = None

                        introList[service] = DbusMgr.getStats(
                            bus, "introspect", service, procStr=pinfo
                        )

                busServiceList[tid].setdefault(bus, busProcList)
            else:
                busServiceList[tid].setdefault(bus, {})

            # define process string #
            procStr = "%s(%s)" % (SysMgr.getComm(tid, cache=True), tid)

            # printintro #
            if mode == "printintro":
                for service, intro in introList.items():
                    DbusMgr.printIntrospection(tid, introList)
                continue
            # monitor #
            elif mode == "monitor":
                ret = DbusMgr.runMonitor(bus)
                continue
            # signal #
            elif mode == "signal":
                ret = DbusMgr.getStats(bus, "allmatch", procStr=procStr)
                if ret:
                    perProc, perSig = ret
                    DbusMgr.printSignalInfo(tid, perProc, perSig, busProcList)
                continue
            # printstat #
            elif mode == "printstat":
                ret = DbusMgr.getStats(bus, "stats", procStr=procStr)
                DbusMgr.printStatInfo(tid, ret)
                continue

            # create a new process #
            pid = SysMgr.createProcess()

            # parent #
            if pid > 0:
                os.close(wr)
                rdPipe = os.fdopen(rd, "r")
                pipeList.append(rdPipe)

                # create a new worker thread #
                if threadObj:
                    tobj = threadObj.Thread(
                        target=_executeLoop, args=[[rdPipe]]
                    )
                    tobj.daemon = True
                    threadingList.append(tobj)
            # child #
            elif pid == 0:
                # redirect stdout to pipe #
                os.close(rd)
                os.dup2(wr, 1)

                # set SIGPIPE handler for termination of parent #
                SysMgr.setPipeHandler()

                # set environment for workers #
                sys.argv[1] = "strace"
                SysMgr.showAll = True
                SysMgr.intervalEnable = 0
                SysMgr.outPath = SysMgr.inputFile = SysMgr.printFd = None
                SysMgr.logEnable = False
                SysMgr.filterGroup = [tid]
                SysMgr.jsonEnable = True
                Debugger.dbusEnable = True
                SysMgr.streamEnable = True
                SysMgr.addOption("Q")

                # wait for parent to create all children #
                if syncLock:
                    lockf(  # pylint: disable=undefined-variable
                        syncLock, LOCK_EX  # pylint: disable=undefined-variable
                    )
                    lockf(  # pylint: disable=undefined-variable
                        syncLock, LOCK_UN  # pylint: disable=undefined-variable
                    )

                # execute strace mode #
                SysMgr.doTrace("syscall", tid=tid)

                sys.exit(0)

            # error #
            else:
                sys.exit(-1)

        # check signal mode #
        if mode == "signal":
            return

        # release lock to start tracers #
        if syncLock:
            lockf(syncLock, LOCK_UN)  # pylint: disable=undefined-variable

        # remove lock file #
        try:
            os.remove(syncLock.name)
        except:
            pass

        # start worker threads #
        for tobj in threadingList:
            tobj.start()

        # run event loop #
        _executeLoop(pipeList)


class DltAnalyzer(object):
    """Manager for DLT"""

    # define constant #
    DLT_HTYP_WEID = 0x04
    DLT_SIZE_WEID = DLT_ID_SIZE = 4
    DLT_MSIN_MSTP = 0x0E  # message type #
    DLT_MSIN_MSTP_SHIFT = 1  # shift right offset to get mstp value #
    DLT_DAEMON_TEXTSIZE = 10024
    DLT_FILTER_MAX = 30

    # define message color type #
    msgColorList = []

    # define message type #
    MSGTYPE = ["log", "app_trace", "nw_trace", "control"]

    # define log type #
    LOGINFO = ["", "fatal", "error", "warn", "info", "debug", "verb"]

    # define log level #
    LOGLEVEL = {
        "DEFAULT": -1,  # Default log level
        "OFF": 0x00,  # Log level off
        "FATAL": 0x01,  # fatal system error
        "ERROR": 0x02,  # error with impact to correct functionality
        "WARN": 0x03,  # warning, correct behaviour could not be ensured
        "INFO": 0x04,  # informational
        "DEBUG": 0x05,  # debug
        "VERBOSE": 0x06,  # highest grade of information
    }

    RETURNTYPE = {
        "DLT_RETURN_LOGGING_DISABLED": -7,
        "DLT_RETURN_USER_BUFFER_FULL": -6,
        "DLT_RETURN_WRONG_PARAMETER": -5,
        "DLT_RETURN_BUFFER_FULL": -4,
        "DLT_RETURN_PIPE_FULL": -3,
        "DLT_RETURN_PIPE_ERROR": -2,
        "DLT_RETURN_ERROR": -1,
        "DLT_RETURN_OK": 0,
        "DLT_RETURN_TRUE": 1,
    }

    SERVICEID = {
        "DLT_SERVICE_ID": 0x00,
        "DLT_SERVICE_ID_SET_LOG_LEVEL": 0x01,
        "DLT_SERVICE_ID_SET_TRACE_STATUS": 0x02,
        "DLT_SERVICE_ID_GET_LOG_INFO": 0x03,
        "DLT_SERVICE_ID_GET_DEFAULT_LOG_LEVEL": 0x04,
        "DLT_SERVICE_ID_STORE_CONFIG": 0x05,
        "DLT_SERVICE_ID_RESET_TO_FACTORY_DEFAULT": 0x06,
        "DLT_SERVICE_ID_SET_COM_INTERFACE_STATUS": 0x07,
        "DLT_SERVICE_ID_SET_COM_INTERFACE_MAX_BANDWIDTH": 0x08,
        "DLT_SERVICE_ID_SET_VERBOSE_MODE": 0x09,
        "DLT_SERVICE_ID_SET_MESSAGE_FILTERING": 0x0A,
        "DLT_SERVICE_ID_SET_TIMING_PACKETS": 0x0B,
        "DLT_SERVICE_ID_GET_LOCAL_TIME": 0x0C,
        "DLT_SERVICE_ID_USE_ECU_ID": 0x0D,
        "DLT_SERVICE_ID_USE_SESSION_ID": 0x0E,
        "DLT_SERVICE_ID_USE_TIMESTAMP": 0x0F,
        "DLT_SERVICE_ID_USE_EXTENDED_HEADER": 0x10,
        "DLT_SERVICE_ID_SET_DEFAULT_LOG_LEVEL": 0x11,
        "DLT_SERVICE_ID_SET_DEFAULT_TRACE_STATUS": 0x12,
        "DLT_SERVICE_ID_GET_SOFTWARE_VERSION": 0x13,
        "DLT_SERVICE_ID_MESSAGE_BUFFER_OVERFLOW": 0x14,
    }

    SERVICERESPONSE = {
        "DLT_SERVICE_RESPONSE_OK": 0x00,
        "DLT_SERVICE_RESPONSE_NOT_SUPPORTED": 0x01,
        "DLT_SERVICE_RESPONSE_ERROR": 0x02,
        "DLT_SERVICE_RESPONSE_PERM_DENIED": 0x03,
        "DLT_SERVICE_RESPONSE_WARNING": 0x04,
        "DLT_SERVICE_RESPONSE_LAST": 0x05,
    }

    # define list #
    pids = []
    procInfo = None
    dltData = {"cnt": 0}
    dbgObj = None
    version = None

    @staticmethod
    def printSummary(force=False):
        quitLoop = False
        convSize = UtilMgr.convNum

        # update CPU usage #
        if DltAnalyzer.dbgObj:
            # get CPU usage for myself #
            cpuUsage = DltAnalyzer.dbgObj.getCpuUsage(system=True)
            diff = SysMgr.uptimeDiff
            ttime = cpuUsage[0] / diff
            utime = cpuUsage[1] / diff
            stime = cpuUsage[2] / diff
            mcpu = "%d%%" % ttime
            mcpu = UtilMgr.convCpuColor(ttime, mcpu)
            mcpuStr = "%s(U%d%%+S%d%%)" % (mcpu, utime, stime)

            # get memory usage for myself #
            rssStr = DltAnalyzer.dbgObj.getMemUsage()

            # get CPU usage for system #
            ctime = 100 - (cpuUsage[3] / diff)
            ctime = ctime if ctime > 0 else 0
            sysCpuStr = "%d%%" % ctime
            sysCpuStr = UtilMgr.convCpuColor(ctime, sysCpuStr)

            # get available memory for system #
            sysMemStr = SysMgr.getAvailMemInfo()

            procInfo = "%s(%s)" % (
                DltAnalyzer.dbgObj.comm,
                DltAnalyzer.dbgObj.pid,
            )
        else:
            procInfo = cpuStr = mcpuStr = rssStr = sysCpuStr = sysMemStr = "?"

        # print title #
        SysMgr.addPrint(
            (
                "[%s] [Time: %7.3f] [Interval: %.1f] [NrMsg: %s] "
                "[SYS: %s/%s] [%s: %s/%s]\n"
            )
            % (
                "DLT Info",
                SysMgr.uptime,
                SysMgr.uptimeDiff,
                convSize(DltAnalyzer.dltData["cnt"]),
                sysCpuStr,
                sysMemStr,
                procInfo,
                mcpuStr,
                rssStr,
            ),
            force=force,
        )

        # update daemon stat #
        DltAnalyzer.procInfo.saveProcInstance()
        saved = False
        for pid in DltAnalyzer.pids:
            ret = DltAnalyzer.procInfo.saveProcData(None, pid)
            if ret:
                saved = True

        # print daemon stat #
        if saved:
            DltAnalyzer.procInfo.printTaskUsage()
            DltAnalyzer.procInfo.reinitStats()
        else:
            SysMgr.addPrint("%s\n" % twoLine, force=force)

        SysMgr.addPrint(
            "{0:^20} | {1:^19} | {2:^19} |\n{3:1}\n".format(
                "ECU", "AP", "CONTEXT", twoLine
            ),
            newline=2,
            force=force,
        )

        # traverse DLT table #
        dltCnt = 0
        for ecuId, ecuItem in sorted(
            DltAnalyzer.dltData.items(),
            key=lambda x: x[1]["cnt"] if x[0] != "cnt" else 0,
            reverse=True,
        ):
            if ecuId == "cnt":
                continue

            if quitLoop or (not force and SysMgr.checkCutCond()):
                break

            ecuCnt = ecuItem["cnt"]
            ecuPer = ecuCnt / float(DltAnalyzer.dltData["cnt"]) * 100
            ecuStr = "{0:4} {1:>8}({2:5.1f}%)\n".format(
                ecuId, convSize(ecuCnt), ecuPer
            )
            SysMgr.addPrint(ecuStr, force=force)
            dltCnt += 1

            for apId, apItem in sorted(
                ecuItem.items(),
                key=lambda x: x[1]["cnt"] if x[0] != "cnt" else 0,
                reverse=True,
            ):
                if apId == "cnt":
                    continue

                if quitLoop or (not force and SysMgr.checkCutCond()):
                    quitLoop = True
                    break

                depth = len(ecuStr) * " "
                apCnt = apItem["cnt"]
                apPer = apCnt / float(ecuCnt) * 100
                apStr = "{0:1}{1:4} {2:>8}({3:5.1f}%)\n".format(
                    depth, apId, convSize(apCnt), apPer
                )
                SysMgr.addPrint(apStr, force=force)

                for ctxId, ctxItem in sorted(
                    apItem.items(),
                    key=lambda x: x[1]["cnt"] if x[0] != "cnt" else 0,
                    reverse=True,
                ):
                    if ctxId == "cnt":
                        continue

                    if quitLoop or (not force and SysMgr.checkCutCond()):
                        quitLoop = True
                        break

                    depth = len(apStr) * " "
                    ctxCnt = ctxItem["cnt"]
                    ctxPer = ctxCnt / float(apCnt) * 100
                    ctxStr = "{0:1}{1:4} {2:>8}({3:5.1f}%)\n".format(
                        depth, ctxId, convSize(ctxCnt), ctxPer
                    )
                    SysMgr.addPrint(ctxStr, force=force)

        if dltCnt == 0:
            SysMgr.addPrint("\tNone\n", force=force)

        if not quitLoop:
            SysMgr.addPrint("%s\n" % oneLine, force=force)

        SysMgr.printTopStats()

        # initialize data #
        DltAnalyzer.dltData = {"cnt": 0}

    @staticmethod
    def onAlarm(signum, frame):
        # check user input #
        SysMgr.waitUserInput(wait=0.000001, msg="DEFAULT")

        # update uptime #
        SysMgr.updateUptime()

        if DltAnalyzer.dltData["cnt"] or SysMgr.inWaitStatus:
            DltAnalyzer.printSummary()
        elif not SysMgr.condExit:
            SysMgr.printWarn("no DLT message received", True)

        if SysMgr.condExit:
            return

        # check term condition #
        SysMgr.progressCnt += 1
        if 0 < SysMgr.repeatCount <= SysMgr.progressCnt:
            SysMgr.printWarn("terminated by timer\n", True)
            os.kill(SysMgr.pid, signal.SIGINT)

        # print progress #
        if SysMgr.repeatCount:
            UtilMgr.printProgress(SysMgr.progressCnt, SysMgr.repeatCount)

        SysMgr.updateTimer()

    @staticmethod
    def getMsgLogLevel(msg):
        DLT_MSIN_MTIN = 0xF0  # message type info #
        DLT_MSIN_MTIN_SHIFT = 4  # shift right offset to get mtin value #
        return (
            msg.extendedheader.contents.msin & DLT_MSIN_MTIN
        ) >> DLT_MSIN_MTIN_SHIFT

    @staticmethod
    def handleMessage(
        dltObj,
        msg,
        buf,
        mode,
        verb,
        buffered=False,
        cond=None,
        since=0,
        fname=None,
    ):
        # save and reset global filter #
        filterGroup = SysMgr.filterGroup

        # check headers #
        if not msg.storageheader or not msg.extendedheader:
            return

        # pick header info #
        ecuId = msg.storageheader.contents.ecu.decode()
        apId = msg.extendedheader.contents.apid.decode()
        ctxId = msg.extendedheader.contents.ctid.decode()

        # check time condition #
        if since and msg.storageheader.contents.seconds < since:
            return

        # summarizing #
        if mode == "top":
            # check filter #
            if filterGroup:
                skipFlag = True
                for cond in filterGroup:
                    if cond in (ecuId, apId, ctxId):
                        skipFlag = False
                        break
                if skipFlag:
                    return

            DltAnalyzer.dltData["cnt"] += 1

            # add ecuId #
            if not ecuId in DltAnalyzer.dltData:
                DltAnalyzer.dltData[ecuId] = {"cnt": 0}
            DltAnalyzer.dltData[ecuId]["cnt"] += 1

            # add apId #
            if not apId in DltAnalyzer.dltData[ecuId]:
                DltAnalyzer.dltData[ecuId][apId] = {"cnt": 0}
            DltAnalyzer.dltData[ecuId][apId]["cnt"] += 1

            # add ctxId #
            if not ctxId in DltAnalyzer.dltData[ecuId][apId]:
                DltAnalyzer.dltData[ecuId][apId][ctxId] = {"cnt": 0}
            DltAnalyzer.dltData[ecuId][apId][ctxId]["cnt"] += 1
        # printing #
        elif mode == "print":
            # get payload #
            dltObj.dlt_message_payload(
                byref(msg), buf, DltAnalyzer.DLT_DAEMON_TEXTSIZE, 2, verb
            )

            try:
                # string = buf.value.decode("utf8")
                string = buf.value
                string = string.decode().strip()
            except SystemExit:
                sys.exit(0)
            except:
                string = [string]

            # check filter #
            if filterGroup:
                skipFlag = True
                for cond in filterGroup:
                    if cond in (ecuId, apId, ctxId) or cond in string:
                        skipFlag = False
                        break
                if skipFlag:
                    return

            # get message info #
            timeSec = msg.storageheader.contents.seconds
            timeUs = msg.storageheader.contents.microseconds
            uptime = "%.6f" % (msg.headerextra.tmsp / float(10000))

            # get log level #
            try:
                level = DltAnalyzer.getMsgLogLevel(msg)
                level = DltAnalyzer.msgColorList[level]
            except SystemExit:
                sys.exit(0)
            except:
                level = ""

            # get date time #
            ntime = time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(timeSec))

            output = (
                "{0:1}.{1:06d} {2:1} {3:4} {4:4} {5:4} {6:5} {7!s:1}"
            ).format(ntime, timeUs, uptime, ecuId, apId, ctxId, level, string)

            if fname:
                fname = UtilMgr.convColor("[%s] " % fname, "YELLOW")
                output = fname + output

            # print log #
            if buffered:
                SysMgr.addPrint(output, force=True, isList=True)
            else:
                SysMgr.printPipe(output, flush=True)

            # check exit condition #
            SysMgr.checkLogCond(string, cond)

    @staticmethod
    def doLogDlt(
        appid=b"GIDR", context=b"GIDR", msg=None, level="INFO", split=True
    ):

        # get ctypes object #
        SysMgr.importPkgItems("ctypes")

        class DltContext(Structure):
            _fields_ = [
                ("contextID", c_char * 4),
                ("log_level_pos", c_int32),
                ("log_level_ptr", POINTER(c_int8)),
                ("trace_status_ptr", POINTER(c_int8)),
                ("mcnt", c_uint8),
            ]

        # check dlt-daemon #
        DltAnalyzer.pids = SysMgr.getProcPids("dlt-daemon")
        if not DltAnalyzer.pids and not SysMgr.remoteServObj:
            SysMgr.printWarn("failed to find dlt-daemon process", True)

        DLT_USER_BUF_MAX_SIZE = 1380

        # set log level #
        try:
            loglevel = DltAnalyzer.LOGLEVEL[level.upper()]
        except:
            loglevel = DltAnalyzer.LOGLEVEL["INFO"]

        # load DLT library #
        try:
            if not SysMgr.dltObj:
                SysMgr.dltObj = SysMgr.loadLib(SysMgr.libdltPath)
            if not SysMgr.dltObj:
                raise Exception("no DLT library")
            dltObj = SysMgr.dltObj
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.dltObj = None
            SysMgr.printWarn(
                "failed to find %s to log DLT" % SysMgr.libdltPath, True
            )
            return -1

        # register #
        if not SysMgr.dltCtx:
            ctx = DltContext()
            ret = dltObj.dlt_register_app(appid, "Guider".encode())
            if ret < 0:
                SysMgr.printErr("failed to register app '%s'" % appid)
                return -1

            ret = dltObj.dlt_register_context(
                byref(ctx), context, "Guider".encode()
            )
            if ret < 0:
                SysMgr.printErr("failed to register context '%s'" % context)
                return -1

            SysMgr.dltCtx = ctx

        # split by newline #
        msgList = msg.strip().split("\n")

        # log #
        for msg in msgList:
            pos = 0
            while 1:
                if len(msg[pos:]) >= DLT_USER_BUF_MAX_SIZE:
                    end = DLT_USER_BUF_MAX_SIZE + pos
                else:
                    end = len(msg)

                ret = dltObj.dlt_log_string(
                    byref(SysMgr.dltCtx), loglevel, msg[pos:end].encode()
                )

                if end == len(msg):
                    break

                pos = end

        """
        # unregister #
        dltObj.dlt_unregister_context(byref(ctx))
        dltObj.dlt_unregister_app()
        """

        return 0

    @staticmethod
    def runDltReceiver(mode="top"):
        def _findNextHeader(path, filePos):
            with open(path, "rb") as fobj:
                lastPos = filePos
                fobj.seek(lastPos)
                buf = fobj.read(1024)
                while buf:
                    found = buf.find(b"DLT\x01")
                    if found != -1:
                        return lastPos + found
                    lastPos = fobj.tell()
                    buf = fobj.read(1024)
            return None

        def _setFilter(
            dltObj, dltFilter, dltFile, apid=None, ctid=None, init=True
        ):
            # initialize filter #
            if init and dltObj.dlt_filter_init(byref(dltFilter), verb) == -1:
                SysMgr.printErr("failed to initialize the DLTFilter object")
                return -1

            if (
                dltObj.dlt_filter_add(
                    byref(dltFilter), apid or b"", ctid or b"", verb
                )
                == -1
            ):
                SysMgr.printErr(
                    "failed to add %s and %s to the DLTFilter object"
                    % (apid, ctid)
                )
                return -1

            if dltFilter.counter >= DltAnalyzer.DLT_FILTER_MAX:
                SysMgr.printErr(
                    (
                        "failed to add %s and %s to the DLTFilter object "
                        "because maximum filter count %s exceed"
                    )
                    % (apid, ctid, DltAnalyzer.DLT_FILTER_MAX)
                )
                return -1

            return dltObj.dlt_file_set_filter(
                byref(dltFile), byref(dltFilter), verb
            )

        # get ctypes object #
        SysMgr.importPkgItems("ctypes")

        # define constant #
        DLT_HTYP_WEID = DltAnalyzer.DLT_HTYP_WEID
        DLT_ID_SIZE = DltAnalyzer.DLT_ID_SIZE
        DLT_FILTER_MAX = DltAnalyzer.DLT_FILTER_MAX

        class in_addr(Structure):
            _fields_ = [
                ("s_addr", c_ulong),
            ]

        class sockaddr_in(Structure):
            _fields_ = [
                ("sin_family", c_short),
                ("sin_port", c_ushort),
                ("sin_addr", in_addr),
                ("sin_zero", c_char * 8),
            ]

        class DltContext(Structure):
            _fields_ = [
                ("contextID", c_char * 4),
                ("log_level_pos", c_int32),
                ("log_level_ptr", POINTER(c_int8)),
                ("trace_status_ptr", POINTER(c_int8)),
                ("mcnt", c_uint8),
            ]

        class DltReceiver(Structure):
            """
            typedef struct
             {
                 int32_t lastBytesRcvd;    /**< bytes received in last receive call */
                 int32_t bytesRcvd;        /**< received bytes */
                 int32_t totalBytesRcvd;   /**< total number of received bytes */
                 char *buffer;             /**< pointer to receiver buffer */
                 char *buf;                /**< pointer to position within receiver buffer */
                 char *backup_buf;     /** pointer to the buffer with partial messages if any **/
                 int fd;                   /**< connection handle */
                 DltReceiverType type;     /**< type of connection handle */
                 int32_t buffersize;       /**< size of receiver buffer */
                 struct sockaddr_in addr;  /**< socket address information */
             } DltReceiver;
            """

            _fields_ = [
                ("lastBytesRcvd", c_int32),
                ("bytesRcvd", c_int32),
                ("totalBytesRcvd", c_int32),
                ("buffer", POINTER(c_char)),
                ("buf", POINTER(c_char)),
                ("backup_buf", POINTER(c_char)),
                ("fd", c_int),
                ("type", c_int),
                ("buffersize", c_int32),
                ("addr", sockaddr_in),
            ]

        class DltClient(Structure):
            """
            typedef struct
            {
                DltReceiver receiver;  /**< receiver pointer to dlt receiver structure */
                int sock;              /**< sock Connection handle/socket */
                char *servIP;          /**< servIP IP adress/Hostname of TCP/IP interface */
                int port;              /**< Port for TCP connections (optional) */
                char *serialDevice;    /**< serialDevice Devicename of serial device */
                char *socketPath;      /**< socketPath Unix socket path */
                char ecuid[4];           /**< ECUiD */
                speed_t baudrate;      /**< baudrate Baudrate of serial interface, as speed_t */
                DltClientMode mode;    /**< mode DltClientMode */
            } DltClient;
            """

            _fields_ = [
                ("receiver", DltReceiver),
                ("sock", c_int),
                ("servIP", c_char_p),
                ("hostIP", c_char_p),
                ("port", c_int),
                ("serialDevice", c_char_p),
                ("socketPath", c_char_p),
                ("ecuid", c_char * DLT_ID_SIZE),
                ("baudrate", c_uint),
                ("mode", c_int),
                ("send_serial_header", c_int),
                ("resync_serial_header", c_int),
            ]

        class ContextIDsInfoType(Structure):
            """
            typedef struct
            {
                char context_id[DLT_ID_SIZE];
                int16_t log_level;
                int16_t trace_status;
                uint16_t len_context_description;
                char *context_description;
            } ContextIDsInfoType;
            """

            _fields_ = [
                ("context_id", c_char * DLT_ID_SIZE),
                ("log_level", c_int16),
                ("trace_status", c_int16),
                ("len_context_description", c_uint16),
                ("context_description", c_char_p),
            ]

        class AppIDsType(Structure):
            """
            typedef struct
             {
                 char app_id[DLT_ID_SIZE];
                 uint16_t count_context_ids;
                 ContextIDsInfoType *context_id_info; /**< holds info about a specific con id */
                 uint16_t len_app_description;
                 char *app_description;
             } AppIDsType;
            """

            _fields_ = [
                ("app_id", c_char * DLT_ID_SIZE),
                ("count_context_ids", c_uint16),
                ("context_id_info", POINTER(ContextIDsInfoType)),
                ("len_app_description", c_uint16),
                ("app_description", c_char_p),
            ]

        class LogInfoType(Structure):
            """
            typedef struct
            {
                uint16_t count_app_ids;
                AppIDsType *app_ids;            /**< holds info about a specific app id */
             } LogInfoType;
            """

            _fields_ = [
                ("count_app_ids", c_uint16),
                ("app_ids", POINTER(AppIDsType)),
            ]

        class DltServiceGetLogInfoResponse(Structure):
            """
            typedef struct
            {
                uint32_t service_id;            /**< service ID */
                uint8_t status;                 /**< type of request */
                LogInfoType log_info_type;      /**< log info type */
                char com[DLT_ID_SIZE];      /**< communication interface */
             } DltServiceGetLogInfoResponse;
            """

            _fields_ = [
                ("service_id", c_uint32),
                ("status", c_uint8),
                ("log_info_type", LogInfoType),
                ("com", c_char * DLT_ID_SIZE),
            ]

        class DltStorageHeader(Structure):
            """
            typedef struct
            {
                char pattern[DLT_ID_SIZE];        /**< This pattern should be DLT0x01 */
                uint32_t seconds;                    /**< seconds since 1.1.1970 */
                int32_t microseconds;            /**< Microseconds */
                char ecu[DLT_ID_SIZE];            /**< The ECU id is added, if it is not already in the DLT message itself */
            } PACKED DltStorageHeader;
            """

            _fields_ = [
                ("pattern", c_char * DLT_ID_SIZE),
                ("seconds", c_uint32),
                ("microseconds", c_int32),
                ("ecu", c_char * DLT_ID_SIZE),
            ]

            def __reduce__(self):
                return (
                    DltStorageHeader,
                    (self.pattern, self.seconds, self.microseconds, self.ecu),
                )

        class DltStandardHeader(BigEndianStructure):
            """
            typedef struct
            {
                uint8_t htyp;           /**< This parameter contains several information, see definitions below */
                uint8_t mcnt;           /**< The message counter is increased with each sent DLT message */
                uint16_t len;           /**< Length of the complete message, without storage header */
            } PACKED DltStandardHeader;
            """

            _fields_ = [
                ("htyp", c_uint8),
                ("mcnt", c_uint8),
                ("len", c_ushort),
            ]

            def __reduce__(self):
                return (DltStandardHeader, (self.htyp, self.mcnt, self.len))

        class DltExtendedHeader(Structure):
            """
            typedef struct
            {
                uint8_t msin;          /**< message info */
                uint8_t noar;          /**< number of arguments */
                char apid[DLT_ID_SIZE];          /**< application id */
                char ctid[DLT_ID_SIZE];          /**< context id */
            } PACKED DltExtendedHeader;
            """

            _fields_ = [
                ("msin", c_uint8),
                ("noar", c_uint8),
                ("apid", c_char * DLT_ID_SIZE),
                ("ctid", c_char * DLT_ID_SIZE),
            ]

            def __reduce__(self):
                return (
                    DltExtendedHeader,
                    (self.msin, self.noar, self.apid, self.ctid),
                )

        class DltStandardHeaderExtra(Structure):
            """
            typedef struct
            {
                char ecu[DLT_ID_SIZE];       /**< ECU id */
                uint32_t seid;     /**< Session number */
                uint32_t tmsp;     /**< Timestamp since system start in 0.1 milliseconds */
            } PACKED DltStandardHeaderExtra;
            """

            _fields_ = [
                ("ecu", c_char * DLT_ID_SIZE),
                ("seid", c_uint32),
                ("tmsp", c_uint32),
            ]

            def __reduce__(self):
                return (
                    DltStandardHeaderExtra,
                    (self.ecu, self.seid, self.tmsp),
                )

        class DLTMessage(Structure):
            """
            typedef struct sDltMessage
            {
                /* flags */
                int8_t found_serialheader;

                /* offsets */
                int32_t resync_offset;

                /* size parameters */
                int32_t headersize;  /**< size of complete header including storage header */
                int32_t datasize;  /**< size of complete payload */

                /* buffer for current loaded message */
                uint8_t headerbuffer[
                    sizeof(DltStorageHeader)+
                    sizeof(DltStandardHeader)+
                    sizeof(DltStandardHeaderExtra)+
                    sizeof(DltExtendedHeader)];
                    /**< buffer for loading complete header */
                uint8_t *databuffer;  /**< buffer for loading payload */
                int32_t databuffersize;

                /* header values of current loaded message */
                DltStorageHeader       *storageheader;  /**< pointer to storage header of current loaded header */
                DltStandardHeader      *standardheader; /**< pointer to standard header of current loaded header */
                DltStandardHeaderExtra headerextra;     /**< extra parameters of current loaded header */
                DltExtendedHeader      *extendedheader; /**< pointer to extended of current loaded header */
            } DltMessage;
            """

            _fields_ = [
                ("found_serialheader", c_int8),
                ("resync_offset", c_int32),
                ("headersize", c_int32),
                ("datasize", c_int32),
                (
                    "headerbuffer",
                    c_uint8
                    * (
                        sizeof(DltStorageHeader)
                        + sizeof(DltStandardHeader)
                        + sizeof(DltStandardHeaderExtra)
                        + sizeof(DltExtendedHeader)
                    ),
                ),
                ("databuffer", POINTER(c_uint8)),
                ("databuffersize", c_int32),
                ("storageheader", POINTER(DltStorageHeader)),
                ("standardheader", POINTER(DltStandardHeader)),
                ("headerextra", DltStandardHeaderExtra),
                ("extendedheader", POINTER(DltExtendedHeader)),
            ]

        class DLTFilter(Structure):
            """
            typedef struct
            {
                char apid[DLT_FILTER_MAX][DLT_ID_SIZE]; /**< application id */
                char ctid[DLT_FILTER_MAX][DLT_ID_SIZE]; /**< context id */
                int  counter;                           /**< number of filters */
            } DltFilter;
            """

            _fields_ = [
                ("apid", (c_char * DLT_ID_SIZE) * DLT_FILTER_MAX),
                ("ctid", (c_char * DLT_ID_SIZE) * DLT_FILTER_MAX),
                ("counter", c_int),
            ]

        class DLTFile(Structure):
            """
            typedef struct sDltFile
            {
                /* file handle and index for fast access */
                FILE *handle;      /**< file handle of opened DLT file */
                long *index;       /**< file positions of all DLT messages for fast access to file, only filtered messages */

                /* size parameters */
                int32_t counter;       /**< number of messages in DLT file with filter */
                int32_t counter_total; /**< number of messages in DLT file without filter */
                int32_t position;      /**< current index to message parsed in DLT file starting at 0 */
                long file_length;  /**< length of the file */
                long file_position; /**< current position in the file */

                /* error counters */
                int32_t error_messages; /**< number of incomplete DLT messages found during file parsing */

                /* filter parameters */
                DltFilter *filter;  /**< pointer to filter list. Zero if no filter is set. */
                int32_t filter_counter; /**< number of filter set */

                /* current loaded message */
                DltMessage msg;     /**< pointer to message */

            } DltFile;
            """

            _fields_ = [
                ("handle", POINTER(c_int)),
                ("index", POINTER(c_long)),
                ("counter", c_int32),
                ("counter_total", c_int32),
                ("position", c_int32),
                ("file_length", c_long),
                ("file_position", c_long),
                ("error_messages", c_int32),
                ("filter", POINTER(DLTFilter)),
                ("filter_counter", c_int32),
                ("msg", DLTMessage),
            ]

        # load DLT library #
        try:
            if "LIBDLT" in SysMgr.environList:
                libpath = SysMgr.environList["LIBDLT"][0]
                SysMgr.dltObj = SysMgr.loadLib(libpath, True)
            elif not SysMgr.dltObj:
                SysMgr.dltObj = SysMgr.loadLib(SysMgr.libdltPath)

            if not SysMgr.dltObj:
                raise Exception("no DLT library")

            dltObj = SysMgr.dltObj
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.dltObj = None
            SysMgr.printWarn(
                "failed to find %s to get DLT logs" % SysMgr.libdltPath,
                always=True,
                reason=True,
            )
            sys.exit(-1)

        # define verbose variable #
        if SysMgr.warnEnable:
            # set log level to DEBUG #
            if hasattr(dltObj, "dlt_log_set_level"):
                dltObj.dlt_log_set_level(LogMgr.LOG_DEBUG)

            verb = 1
        else:
            verb = 0

        # get socket object #
        socket = SysMgr.getPkg("socket")

        try:
            from socket import SOL_SOCKET, SO_RCVBUF, create_connection
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to import socket", True)
            sys.exit(-1)

        # define dlt functions #
        dltObj.dlt_register_app.argtypes = [c_char_p, c_char_p]
        dltObj.dlt_register_app.restype = c_int

        dltObj.dlt_register_context.argtypes = [c_void_p, c_char_p, c_char_p]
        dltObj.dlt_register_context.restype = c_int

        dltObj.dlt_log_string.argtypes = [c_void_p, c_int, c_char_p]
        dltObj.dlt_log_string.restype = c_int

        dltObj.dlt_filter_init.argtypes = [c_void_p, c_int]
        dltObj.dlt_filter_init.restype = c_int

        dltObj.dlt_log_set_level.argtypes = [c_int]
        dltObj.dlt_log_set_level.restype = None

        dltObj.dlt_filter_add.argtypes = [c_void_p, c_char_p, c_char_p, c_int]
        dltObj.dlt_filter_add.restype = c_int

        dltObj.dlt_file_set_filter.argtypes = [c_void_p, c_void_p, c_int]
        dltObj.dlt_file_set_filter.restype = c_int

        dltObj.dlt_file_init.argtypes = [c_void_p, c_int]
        dltObj.dlt_file_init.restype = c_int

        dltObj.dlt_file_open.argtypes = [c_void_p, c_char_p, c_int]
        dltObj.dlt_file_open.restype = c_int

        dltObj.dlt_file_read.argtypes = [c_void_p, c_int]
        dltObj.dlt_file_read.restype = c_int

        dltObj.dlt_file_message.argtypes = [c_void_p, c_int, c_int]
        dltObj.dlt_file_message.restype = c_int

        dltObj.dlt_file_free.argtypes = [c_void_p, c_int]
        dltObj.dlt_file_free.restype = c_int

        dltObj.dlt_client_init.argtypes = [c_void_p, c_int]
        dltObj.dlt_client_init.restype = c_int

        dltObj.dlt_client_cleanup.argtypes = [c_void_p, c_int]
        dltObj.dlt_client_cleanup.restype = c_int

        dltObj.dlt_client_send_all_log_level.argtypes = [c_void_p, c_int8]
        dltObj.dlt_client_send_all_log_level.restype = c_int

        dltObj.dlt_client_get_log_info.argtypes = [c_void_p]
        dltObj.dlt_client_get_log_info.restype = c_int

        dltObj.dlt_client_main_loop.argtypes = [c_void_p, c_void_p, c_int]
        dltObj.dlt_client_main_loop.restype = c_int

        dltObj.dlt_receiver_init.argtypes = [c_void_p, c_int, c_int, c_int]
        dltObj.dlt_receiver_init.restype = c_int

        dltObj.dlt_get_version.argtypes = [c_char_p, c_int]
        dltObj.dlt_get_version.restype = None

        dltObj.dlt_message_init.argtypes = [c_void_p, c_int]
        dltObj.dlt_message_init.restype = c_int

        dltObj.dlt_message_read.argtypes = [
            c_void_p,
            c_void_p,
            c_uint,
            c_int,
            c_int,
        ]
        dltObj.dlt_message_read.restype = c_int

        dltObj.dlt_receiver_move_to_begin.argtypes = [c_void_p]
        dltObj.dlt_receiver_move_to_begin.restype = c_int

        dltObj.dlt_receiver_remove.argtypes = [c_void_p, c_int]
        dltObj.dlt_receiver_remove.restype = c_int

        dltObj.dlt_message_print_ascii.argtypes = [
            c_void_p,
            c_void_p,
            c_uint32,
            c_int,
        ]
        dltObj.dlt_message_print_ascii.restype = c_int

        dltObj.dlt_set_storageheader.argtypes = [c_void_p, c_char_p]
        dltObj.dlt_set_storageheader.restype = c_int

        dltObj.dlt_message_free.argtypes = [c_void_p, c_int]
        dltObj.dlt_message_free.restype = c_int

        # define default variables #
        msg = DLTMessage()
        dltFile = DLTFile()
        dltFilter = DLTFilter()
        buf = create_string_buffer(b"\000" * DltAnalyzer.DLT_DAEMON_TEXTSIZE)

        # initialize input path #
        flist = []
        if SysMgr.hasMainArg():
            args = SysMgr.getMainArg()
            for item in args.split(","):
                ret = UtilMgr.convPath(item.strip())
                flist += ret
            flist = UtilMgr.cleanItem(flist)
            if not flist:
                SysMgr.printErr("wrong path '%s' for DLT files" % args)
                sys.exit(-1)
        elif SysMgr.inputParam:
            for item in SysMgr.inputParam.split(","):
                ret = UtilMgr.convPath(item.strip())
                flist += ret
            flist = UtilMgr.cleanItem(flist)
            if not flist:
                SysMgr.printErr(
                    "wrong path '%s' for DLT files" % SysMgr.inputParam
                )
                sys.exit(-1)

        # check sort option #
        if SysMgr.findOption("S"):
            buffered = True
            SysMgr.streamEnable = False
        else:
            buffered = False

        # set colors for each message types #
        for item in DltAnalyzer.LOGINFO:
            if item == "fatal" or item == "error":
                color = "RED"
            elif item == "info":
                color = "CYAN"
            elif item == "debug":
                color = "BLUE"
            elif item == "warn":
                color = "PINK"
            else:
                color = "DEFAULT"

            DltAnalyzer.msgColorList.append(
                UtilMgr.convColor(item, color, 5, "left")
            )

        # initialize task stat #
        try:
            DltAnalyzer.dbgObj = Debugger(SysMgr.pid, attach=False)
            DltAnalyzer.dbgObj.initValues()
            DltAnalyzer.dbgObj.getCpuUsage(system=True)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("failed to read CPU usage", reason=True)

        # get log level option #
        try:
            if SysMgr.customCmd:
                val = SysMgr.customCmd[0].upper()
                level = DltAnalyzer.LOGLEVEL[val]
            else:
                level = None
        except:
            SysMgr.printErr("failed to recognize log level", True)
            sys.exit(-1)

        # get DLT version #
        try:
            vbuf = (c_char * 256)()
            dltObj.dlt_get_version(vbuf, c_int(255))
            vstr = memoryview(vbuf).tobytes().decode().split("\x00")[0]
            verstr = " ".join(vstr.split("\n"))

            SysMgr.printInfo(verstr)

            ver = UtilMgr.lstrip(verstr, "DLT Package Version: ")
            DltAnalyzer.version = tuple(
                map(int, ver[: ver.find(" ")].split("."))
            )
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("failed to get DLT version", reason=True)

        # set new data structures (>=2.18.6) #
        legacy = True
        try:
            if not DltAnalyzer.version:
                raise Exception("no version")
            elif DltAnalyzer.version >= (2, 18, 6):
                legacy = False
                raise Exception("recent version")

            # dlt_receiver_init #
            dltObj.dlt_receiver_init.argtypes = [c_void_p, c_int, c_int]
            dltObj.dlt_receiver_init.restype = c_int

            def _popFields(struct, items):
                popList = []
                for idx, item in enumerate(struct._fields_):
                    if item[0] in items:
                        popList.append(idx)
                for idx in reversed(popList):
                    struct._fields_.pop(idx)

            # DltReceiver #
            _popFields(DltReceiver, ("addr", "type"))

            # DltClient #
            _popFields(
                DltClient,
                ("hostIP", "send_serial_header", "resync_serial_header"),
            )
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn(
                "failed to set legacy data structures", reason=True
            )

        # messages from file #
        if mode == "print" and flist:
            # set print mode #
            if "PRINTSUMMARY" in SysMgr.environList:
                printMode = "top"
                if not SysMgr.findOption("Q"):
                    SysMgr.streamEnable = False
                DltAnalyzer.procInfo = TaskAnalyzer(onlyInstance=True)
                action = "summarizing"
            else:
                printMode = mode
                action = "printing"

            # set print filename flag #
            if "PRINTFILENAME" in SysMgr.environList:
                printName = True
            else:
                printName = False

            for path in flist:
                # get file size #
                fsize = UtilMgr.getFileSizeStr(path)

                SysMgr.printInfo(
                    "start %s DLT logs from '%s'%s..." % (action, path, fsize)
                )

                # convert path string to utf-8 format #
                pathOrig = path
                path = UtilMgr.encodeStr(path)

                # initialize file object #
                ret = dltObj.dlt_file_init(byref(dltFile), verb)
                if ret < 0:
                    SysMgr.printErr("failed to initialize a DLTFile object")

                # set filter #
                # _setFilter(dltObj, dltFilter, dltFile, apid=b"", ctid=b"", init=True)

                # open the file #
                ret = dltObj.dlt_file_open(byref(dltFile), path, verb)
                if ret != 0:
                    SysMgr.printErr("failed to open %s" % pathOrig)
                    return
                elif dltFile.file_length == 0:
                    SysMgr.printErr(
                        "failed to read %s because size is 0" % pathOrig
                    )
                    return

                # read the file #
                while dltFile.file_position < dltFile.file_length:
                    ret = dltObj.dlt_file_read(byref(dltFile), verb)
                    # storage header corrupted #
                    if ret < 0:
                        nextHeaderPos = _findNextHeader(
                            path, dltFile.file_position
                        )
                        if nextHeaderPos is None:
                            SysMgr.printWarn(
                                "wrong DLT storage header from '%s'"
                                % pathOrig,
                                True,
                            )
                            break
                        elif dltFile.file_position == nextHeaderPos:
                            break
                        else:
                            dltFile.file_position = nextHeaderPos

                    # print progress #
                    UtilMgr.printProgress(
                        dltFile.file_position, dltFile.file_length
                    )

                UtilMgr.deleteProgress()

                # print a newline #
                if printMode == "print" and not buffered:
                    SysMgr.printPipe()

                # read messages #
                for index in xrange(dltFile.counter_total):
                    ret = dltObj.dlt_file_message(byref(dltFile), index, verb)
                    if ret < 0:
                        SysMgr.printWarn(
                            "failed to read %s message from %s"
                            % (index, pathOrig),
                            True,
                        )
                        continue

                    # check log filter #
                    if level:
                        mlevel = DltAnalyzer.getMsgLogLevel(dltFile.msg)
                        if mlevel > level:
                            continue

                    # print message #
                    DltAnalyzer.handleMessage(
                        dltObj,
                        dltFile.msg,
                        buf,
                        printMode,
                        verb,
                        buffered,
                        fname=pathOrig if printName else None,
                    )

                # free file object #
                ret = dltObj.dlt_file_free(byref(dltFile), verb)
                if ret < 0:
                    SysMgr.printErr("failed to free a DLTFile object")

            # print summary #
            if printMode == "top":
                SysMgr.printPipe()
                DltAnalyzer.printSummary(force=True)

            # handle buffered logs #
            if buffered:
                output = SysMgr.getPrintList(retStr=True, sort=True)
                SysMgr.clearPrint()
                SysMgr.printPipe(output, flush=True)

            sys.exit(0)

        # check dlt-daemon #
        DltAnalyzer.pids = SysMgr.getProcPids("dlt-daemon")
        if not DltAnalyzer.pids and not SysMgr.remoteServObj:
            SysMgr.printWarn("failed to find dlt-daemon process", True)

        # set connection info #
        try:
            if SysMgr.remoteServObj:
                servIp = SysMgr.remoteServObj.ip
                port = long(SysMgr.remoteServObj.port)
                if port == SysMgr.defaultServPort:
                    servPort = 3490
                else:
                    servPort = port
            else:
                servIp = "127.0.0.1"
                servPort = 3490

            SysMgr.printInfo("use %s:%s as dlt-daemon" % (servIp, servPort))
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to get the address of dlt-daemon", True)
            sys.exit(-1)

        # get retry interval #
        retry = 0
        if "RETRYCONN" in SysMgr.environList:
            value = SysMgr.environList["RETRYCONN"][0]
            if value == "SET":
                retry = 1
            else:
                try:
                    retry = float(value) / 1000
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(
                        "failed to convert %s to retry connection interval"
                        % value
                    )
                    sys.exit(-1)

        # connect to server #
        while 1:
            try:
                servIpStr = string_at(servIp.encode())
                connSock = create_connection((servIpStr, servPort), timeout=1)
                if not connSock:
                    raise Exception("no connection")

                # set blocking #
                connSock.setblocking(1)  # pylint: disable=no-member

                break
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "failed to connect to dlt-daemon with %s:%s"
                    % (servIp, servPort),
                    True,
                )

                # retry #
                if retry:
                    time.sleep(retry)
                else:
                    sys.exit(-1)

        # initialize client #
        dltClient = DltClient()
        dltObj.dlt_client_init(byref(dltClient), verb)
        sockno = c_int(connSock.fileno())  # pylint: disable=no-member
        dltClient.sock = sockno
        dltClient.receiver.fd = sockno
        # dltObj.dlt_client_cleanup(byref(dltClient), verb)

        # change default log level #
        try:
            if level:
                dltObj.dlt_client_send_all_log_level(byref(dltClient), level)
        except:
            SysMgr.printErr("failed to set %s to default log level" % val)
            sys.exit(-1)

        # print log level #
        try:
            ret = dltObj.dlt_client_get_log_info(byref(dltClient))
            if ret == 0:
                resp = DltServiceGetLogInfoResponse()
                resp.service_id = DltAnalyzer.SERVICEID[
                    "DLT_SERVICE_ID_GET_LOG_INFO"
                ]
                resp.status = DltAnalyzer.SERVICERESPONSE[
                    "DLT_SERVICE_RESPONSE_ERROR"
                ]
                dltObj.dlt_client_main_loop(byref(dltClient), byref(resp), 0)
                appids = resp.log_info_type.count_app_ids
                for idx in xrange(appids):
                    app = resp.log_info_type.app_ids[idx]
                    for num in xrange(app.count_context_ids):
                        con = app.context_id_info[num]
                        SysMgr.printPipe(
                            "[%s] [%s] %s"
                            % (app.app_id, con.context_id, con.log_level)
                        )
        except:
            SysMgr.printWarn("failed to print log level", reason=True)

        # initialize receiver #
        dltReceiver = dltClient.receiver

        # initialize connection #
        try:
            nrConnSock = connSock.fileno()  # pylint: disable=no-member
            RECVBUFSIZE = connSock.getsockopt(
                SOL_SOCKET, SO_RCVBUF
            )  # pylint: disable=no-member

            if legacy:
                ret = dltObj.dlt_receiver_init(
                    byref(dltReceiver), c_int(nrConnSock), c_int(RECVBUFSIZE)
                )
            else:
                ret = dltObj.dlt_receiver_init(
                    byref(dltReceiver),
                    c_int(nrConnSock),
                    c_int(0),  # 0: SOCKET / 1: UDP / 2: FD #
                    c_int(RECVBUFSIZE),
                )
            if ret < 0:
                SysMgr.printErr("failed to initialize DLT receiver")
                sys.exit(-1)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to initialize connection", True)
            sys.exit(-1)

        # define receiver symbol #
        try:
            if hasattr(dltObj, "dlt_receiver_receive_socket"):
                dltObj.dlt_receiver_receive_socket.argtypes = [c_void_p]
                dltObj.dlt_receiver_receive_socket.restype = c_int
                dlt_receiver_receive = dltObj.dlt_receiver_receive_socket
                incVerb = False
                verbVal = c_int(0)
            elif hasattr(dltObj, "dlt_receiver_receive"):
                dltObj.dlt_receiver_receive.argtypes = [c_void_p, c_int]
                dltObj.dlt_receiver_receive.restype = c_int
                dlt_receiver_receive = dltObj.dlt_receiver_receive
                incVerb = True
                verbVal = c_int(1)
            else:
                raise Exception("no DLT receiver")
        except:
            SysMgr.printErr("failed to get dlt_receiver_receive symbol")
            sys.exit(-1)

        # save timestamp #
        prevTime = time.time()
        SysMgr.updateUptime()

        # initialize dlt-daemon info #
        SysMgr.showAll = True
        SysMgr.cmdlineEnable = True
        procInfo = DltAnalyzer.procInfo = TaskAnalyzer(onlyInstance=True)
        for pid in DltAnalyzer.pids:
            procInfo.saveProcData(None, pid)
            procInfo.saveCmdlineData(None, pid)

        # set timer #
        signal.signal(signal.SIGALRM, DltAnalyzer.onAlarm)
        SysMgr.updateTimer()

        # set flag and print mode #
        quitFlag = False
        if mode == "top":
            # set handler for exit #
            signal.signal(signal.SIGINT, SysMgr.exitHandler)
            if SysMgr.outPath:
                SysMgr.addExitFunc(DltAnalyzer.onAlarm, [0, 0])
            SysMgr.addExitFunc(SysMgr.stopHandler, [0, 0])

            SysMgr.printInfo("start collecting DLT logs... [ STOP(Ctrl+c) ]")
        elif mode == "print":
            quitFlag = SysMgr.findOption("Q")

            SysMgr.printInfo("start printing DLT logs... [ STOP(Ctrl+c) ]\n")

        # get item for log filter #
        if "WATCHLOG" in SysMgr.environList:
            watchcond = SysMgr.environList["WATCHLOG"][0].split("+")
        else:
            watchcond = None

        # get tail value #
        if "TAIL" in SysMgr.environList:
            since = time.time()
        else:
            since = 0

        while 1:
            try:
                # initialize message #
                ret = dltObj.dlt_message_init(byref(msg), verb)
                if ret < 0:
                    SysMgr.printErr("failed to initialize DLT message")
                    sys.exit(-1)

                # check DLT data to be read #
                try:
                    ret = dlt_receiver_receive(byref(dltReceiver), verbVal)
                    if ret <= 0:
                        continue
                except SystemExit:
                    sys.exit(0)
                except:
                    sys.exit(-1)

                # check DLT data to be read #
                while 1:
                    ret = dltObj.dlt_message_read(
                        byref(msg),
                        cast(dltReceiver.buf, POINTER(c_uint8)),
                        c_uint(dltReceiver.bytesRcvd),
                        c_int(0),
                        c_int(verb),
                    )
                    if ret != 0:
                        if quitFlag:
                            sys.exit(0)

                        # move receiver buffer pointer to start of the buffer #
                        ret = dltObj.dlt_receiver_move_to_begin(
                            byref(dltReceiver)
                        )
                        if ret < 0:
                            SysMgr.printErr(
                                "failed to move pointer to receiver buffer"
                            )
                            sys.exit(-1)

                        break

                    # check log filter #
                    if level and DltAnalyzer.getMsgLogLevel(msg) > level:
                        continue

                    # get data size to be removed #
                    size = (
                        msg.headersize
                        + msg.datasize
                        - sizeof(DltStorageHeader)
                    )
                    if msg.found_serialheader:
                        size += DLT_ID_SIZE

                    # remove message from buffer #
                    if (
                        dltObj.dlt_receiver_remove(byref(dltReceiver), size)
                        < 0
                    ):
                        SysMgr.printErr("failed to remove data from buffer")
                        sys.exit(-1)

                    # print DLT message #
                    if verb:
                        dltObj.dlt_message_print_ascii(
                            byref(msg),
                            byref(buf),
                            c_uint32(msg.headersize),
                            c_int(verb),
                        )

                    # set storage info #
                    if msg.standardheader.contents.htyp & DLT_HTYP_WEID:
                        dltObj.dlt_set_storageheader(
                            msg.storageheader, msg.headerextra.ecu
                        )
                    else:
                        dltObj.dlt_set_storageheader(
                            msg.storageheader, c_char_p("".encode())
                        )

                    # handle a message #
                    DltAnalyzer.handleMessage(
                        dltObj,
                        msg,
                        buf,
                        mode,
                        verb,
                        cond=watchcond,
                        since=since,
                    )
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn(
                    "failed to process DLT message", True, reason=True
                )
                continue

        # free message #
        dltObj.dlt_message_free(byref(msg), verb)


class Debugger(object):
    """Debugger for ptrace"""

    globalEvent = None
    gLockObj = None
    gLockPath = None
    dbgInstance = None
    tracerInstance = None
    dbusEnable = False
    RETSTR = None

    targetNums = {}
    cpuCond = -1
    pyElapsed = -1
    strSize = -1
    envFlags = {
        "COMPLETECALL": False,
        "CONTALONE": False,
        "CONVARG": False,
        "EXCEPTLD": False,
        "EXCEPTWAIT": False,
        "HIDESYM": False,
        "INCNATIVE": False,
        "INCOVERHEAD": False,
        "INTERCALL": False,
        "NOARG": False,
        "NOFILE": False,
        "NOMUTE": False,
        "NORETBT": False,
        "NOSAMPLECACHE": False,
        "NOSTRIP": False,
        "ONLYFAIL": False,
        "ONLYOK": False,
        "ONLYSYM": False,
        "PRINTARG": False,
        "PRINTDIFF": False,
        "PRINTDELAY": False,
        "PRINTHIST": False,
        "PYSTACK": False,
        "STDEV": False,
        "SYNCTASK": False,
        "TIMELINE": False,
        "TRACEBP": False,
        "WAITCLONE": False,
        "WAITWAKEUP": False,
    }

    def getSigStruct(self):
        class _sifields_sigfault_t(Union):
            _fields_ = (("_addr", c_void_p),)

        class _sifields_kill_t(Structure):
            _fields_ = (("pid", c_int), ("uid", c_ushort))

        class _sifields_sigchld_t(Structure):
            _fields_ = (
                ("pid", c_int),
                ("uid", c_ushort),
                ("status", c_int),
                ("utime", c_uint),
                ("stime", c_uint),
            )

        class _sifields_t(Union):
            _fields_ = (
                ("pad", c_char * (128 - 3 * sizeof(c_int))),
                # ("_kill", _sifields_kill_t),
                # ("_timer", _sifields_timer_t),
                ("_sigchld", _sifields_sigchld_t),
                ("_sigfault", _sifields_sigfault_t),
                # ("_rt", _sifields_rt_t),
                # ("_sigpoll", _sifields_sigpoll_t),
            )

        class siginfo(Structure):
            _fields_ = (
                ("si_signo", c_int),
                ("si_errno", c_int),
                ("si_code", c_int),
                ("_sifields", _sifields_t),
            )
            _anonymous_ = ("_sifields",)

        return siginfo()

    def getRegStruct(self):
        class user_regs_struct(Structure):
            def _getdict(struct):  # pylint: disable=no-self-argument
                return dict(
                    (field, getattr(struct, field))
                    for field, _ in struct._fields_
                )

            if self.arch == "aarch64":
                regs = tuple(("x%i" % reg, c_ulong) for reg in xrange(31))
                _fields_ = regs + (
                    ("sp", c_ulong),
                    ("pc", c_ulong),
                    ("ELP_mode", c_ulong),
                    ("RA_SIGN_STATE", c_ulong),
                )

            elif self.arch == "x64":
                _fields_ = (
                    ("r15", c_ulong),
                    ("r14", c_ulong),
                    ("r13", c_ulong),
                    ("r12", c_ulong),
                    ("rbp", c_ulong),
                    ("rbx", c_ulong),
                    ("r11", c_ulong),
                    ("r10", c_ulong),
                    ("r9", c_ulong),
                    ("r8", c_ulong),
                    ("rax", c_ulong),
                    ("rcx", c_ulong),
                    ("rdx", c_ulong),
                    ("rsi", c_ulong),
                    ("rdi", c_ulong),
                    ("orig_rax", c_ulong),
                    ("rip", c_ulong),
                    ("cs", c_ulong),
                    ("eflags", c_ulong),
                    ("rsp", c_ulong),
                    ("ss", c_ulong),
                    ("fs_base", c_ulong),
                    ("gs_base", c_ulong),
                    ("ds", c_ulong),
                    ("es", c_ulong),
                    ("fs", c_ulong),
                    ("gs", c_ulong),
                )
            elif self.arch == "arm":
                _fields_ = tuple(("r%i" % reg, c_ulong) for reg in xrange(18))
            elif self.arch == "x86":
                _fields_ = (
                    ("ebx", c_ulong),
                    ("ecx", c_ulong),
                    ("edx", c_ulong),
                    ("esi", c_ulong),
                    ("edi", c_ulong),
                    ("ebp", c_ulong),
                    ("eax", c_ulong),
                    ("ds", c_ushort),
                    ("__ds", c_ushort),
                    ("es", c_ushort),
                    ("__es", c_ushort),
                    ("fs", c_ushort),
                    ("__fs", c_ushort),
                    ("gs", c_ushort),
                    ("__gs", c_ushort),
                    ("orig_eax", c_ulong),
                    ("eip", c_ulong),
                    ("cs", c_ushort),
                    ("__cs", c_ushort),
                    ("eflags", c_ulong),
                    ("esp", c_ulong),
                    ("ss", c_ushort),
                    ("__ss", c_ushort),
                )
            elif self.arch == "powerpc":
                _fields_ = (
                    ("gpr0", c_ulong),
                    ("gpr1", c_ulong),
                    ("gpr2", c_ulong),
                    ("gpr3", c_ulong),
                    ("gpr4", c_ulong),
                    ("gpr5", c_ulong),
                    ("gpr6", c_ulong),
                    ("gpr7", c_ulong),
                    ("gpr8", c_ulong),
                    ("gpr9", c_ulong),
                    ("gpr10", c_ulong),
                    ("gpr11", c_ulong),
                    ("gpr12", c_ulong),
                    ("gpr13", c_ulong),
                    ("gpr14", c_ulong),
                    ("gpr15", c_ulong),
                    ("gpr16", c_ulong),
                    ("gpr17", c_ulong),
                    ("gpr18", c_ulong),
                    ("gpr19", c_ulong),
                    ("gpr20", c_ulong),
                    ("gpr21", c_ulong),
                    ("gpr22", c_ulong),
                    ("gpr23", c_ulong),
                    ("gpr24", c_ulong),
                    ("gpr25", c_ulong),
                    ("gpr26", c_ulong),
                    ("gpr27", c_ulong),
                    ("gpr28", c_ulong),
                    ("gpr29", c_ulong),
                    ("gpr30", c_ulong),
                    ("gpr31", c_ulong),
                    ("nip", c_ulong),
                    ("msr", c_ulong),
                    ("orig_gpr3", c_ulong),
                    ("ctr", c_ulong),
                    ("link", c_ulong),
                    ("xer", c_ulong),
                    ("ccr", c_ulong),
                    ("mq", c_ulong),
                    ("trap", c_ulong),
                    ("dar", c_ulong),
                    ("dsisr", c_ulong),
                    ("result", c_ulong),
                )

        return user_regs_struct()

    def getFpRegStruct(self):
        class user_fpregs_struct(Structure):
            def _getdict(struct):  # pylint: disable=no-self-argument
                return dict(
                    (field, getattr(struct, field))
                    for field, _ in struct._fields_
                )

            if self.arch == "aarch64" or self.arch == "x64":
                _fields_ = (
                    ("cwd", c_uint16),
                    ("swd", c_uint16),
                    ("ftw", c_uint16),
                    ("fop", c_uint16),
                    ("rip", c_uint64),
                    ("rdp", c_uint64),
                    ("mxcsr", c_uint32),
                    ("mxcr_mask", c_uint32),
                    ("st_space", c_uint32 * 32),
                    ("xmm_space", c_uint32 * 64),
                    ("padding", c_uint32 * 24),
                )
            else:
                _fields_ = (
                    ("cwd", c_ulong),
                    ("swd", c_ulong),
                    ("twd", c_ulong),
                    ("fip", c_ulong),
                    ("fcs", c_ulong),
                    ("foo", c_ulong),
                    ("fos", c_ulong),
                    ("st_space", c_ulong * 20),
                )

        return user_fpregs_struct()

    def updateBreakMode(self):
        # set break mode #
        if self.mode == "break" or self.mode == "pybreak":
            self.isBreakMode = True
        else:
            self.isBreakMode = False

    def updateCurrent(self):
        self.current = time.time()

    def __init__(self, pid=None, execCmd=None, attach=True, mode=None):
        self.pthreadid = 0
        self.comm = None
        self.mode = mode
        self.status = "enter"
        self.traceStatus = False
        self.runStatus = False
        self.attached = attach
        self.execCmd = execCmd
        self.arch = arch = SysMgr.getArch()
        self.skipInst = 5
        self.indentLen = 20
        self.errmsg = ""
        self.syscall = ""
        self.bufferedStr = ""
        self.mapFd = None
        self.pmap = None
        self.prevPmap = None
        self.stackFd = None
        self.amap = []
        self.jmapFd = None
        self.jmapPath = None
        self.jmapSize = None
        self.jmapSymTable = []
        self.jmapAddrTable = []
        self.needMapScan = True
        self.initPtrace = False
        self.initWaitpid = False
        self.initPvr = False
        self.initPvw = False
        self.supportGetRegset = True
        self.supportSetRegset = True
        self.supportProcessVmRd = True
        self.supportProcessVmWr = False
        self.lastSig = None
        self.forked = False
        self.multi = False
        self.errCnt = 0
        self.sampleTime = 0
        self.sampleTimeOrig = 0
        self.sampleTimeMax = 0
        self.incrementalSampling = True
        self.startProfTime = False
        self.showStatus = True

        # init task number #
        self.myNum = 0
        self.childNum = 0

        # update break mode #
        self.updateBreakMode()

        # set character for word decoding #
        if ConfigMgr.wordSize == 4:
            self.decChar = "I"
        else:
            self.decChar = "Q"

        # define timestamp variables #
        self.current = 0
        self.dstart = 0
        self.dvalue = 0
        self.vdiff = 0
        self.interDiff = 0
        self.updateCurrent()

        self.args = []
        self.values = []
        self.fileList = []
        self.addrList = []
        self.callstack = []
        self.overlayfsList = []
        self.totalCall = 0
        self.syscallAddr = None
        self.syscallFound = True
        self.bpList = {}
        self.bpNewList = {}
        self.entryTime = {}
        self.entryContext = {}
        self.retCmdList = {}
        self.retFilterList = {}
        self.exceptBpList = {}
        self.targetBpList = {}
        self.targetBpFileList = {}
        self.exceptBpFileList = {}
        self.symbolCacheList = {}
        self.failedAddrList = {}
        self.ldInjected = False
        self.libcLoaded = False
        self.dftBpFileList = {}
        self.dftBpSymList = {
            "mmap": 0,
            "mmap64": 0,
            "munmap": 0,
            "prctl": 0,
            "pthread_setname_np": 0,
        }

        self.backtrace = {
            "x86": self.getBacktrace_X86,
            "x64": self.getBacktrace_X86,
            "arm": self.getBacktrace_ARM,
            "aarch64": self.getBacktrace_AARCH64,
        }
        self.btList = None
        self.btStr = None
        self.btArgList = []
        self.csBtList = None
        self.csBtSymList = None
        self.csContext = None
        self.prevBtList = None
        self.prevBtStr = None
        self.startAddr = None
        self.prevSym = None
        self.inBacktrace = False

        self.lockObj = None
        self.tempPage = None
        self.sockObj = None

        self.pyAddr = None
        self.pyFrameCache = {}
        self.readPyStr = None
        self.readPyFrame = None
        self.readPyState = None

        self.stack = None
        self.startStack = None
        self.endStack = None
        self.stackSize = 0

        # define timeline #
        self.timelineIdx = {}
        self.timelineData = {"time_unit": "us", "segments": []}
        self.timeDuration = UtilMgr.getEnvironNum(
            "DURATION", False, 100, False
        )

        # set ptrace indexes #
        plist = ConfigMgr.PTRACE_TYPE
        self.peekIdx = plist.index("PTRACE_PEEKTEXT")
        self.pokeIdx = plist.index("PTRACE_POKEDATA")
        self.contCmd = plist.index("PTRACE_CONT")
        self.getregsCmd = plist.index("PTRACE_GETREGS")
        self.getfpregsCmd = plist.index("PTRACE_GETFPREGS")
        self.setregsCmd = plist.index("PTRACE_SETREGS")
        self.syscallCmd = plist.index("PTRACE_SYSCALL")
        self.sysemuCmd = plist.index("PTRACE_SYSEMU")
        self.singlestepCmd = plist.index("PTRACE_SINGLESTEP")

        # set ptrace event indexes #
        pelist = ConfigMgr.PTRACE_EVENT_TYPE
        self.sigExecFlag = (
            signal.SIGTRAP | pelist.index("PTRACE_EVENT_EXEC") << 8
        )
        self.sigCloneFlag = (
            signal.SIGTRAP | pelist.index("PTRACE_EVENT_CLONE") << 8
        )
        self.sigForkFlag = (
            signal.SIGTRAP | pelist.index("PTRACE_EVENT_FORK") << 8
        )
        self.sigVforkFlag = (
            signal.SIGTRAP | pelist.index("PTRACE_EVENT_VFORK") << 8
        )
        self.sigExitFlag = (
            signal.SIGTRAP | pelist.index("PTRACE_EVENT_EXIT") << 8
        )

        # set task indexes #
        clist = ConfigMgr.STAT_ATTR
        self.commIdx = clist.index("COMM")
        self.utimeIdx = clist.index("UTIME")
        self.stimeIdx = clist.index("STIME")
        self.rssIdx = clist.index("RSS")
        self.tkillIdx = SysMgr.getNrSyscall("sys_tkill")

        # set arch regs #
        self.arch = SysMgr.arch
        self.sysreg = ConfigMgr.SYSREG_LIST[self.arch]
        self.retreg = ConfigMgr.RET_LIST[self.arch]

        # set python reader functions #
        if ConfigMgr.wordSize == 4:
            self.readPyStr = self.readPyStr32
            self.readPyFrame = self.readPyFrame32
            self.readPyState = self.readPyState32
        else:
            self.readPyStr = self.readPyStr64
            self.readPyFrame = self.readPyFrame64
            self.readPyState = self.readPyState64

        # set breakpoint variables #
        if self.arch == "arm" or self.arch == "aarch64":
            self.brkInst = b"\xFE\xDE\xFF\xE7"
            self.prevInstOffset = 0
        else:
            self.brkInst = b"\xCC"
            self.prevInstOffset = 1

        # set ignore list #
        self.ignoreItemList = list(
            map(lambda x: x.encode(), SysMgr.ignoreItemList)
        )

        # check ptrace scope #
        if Debugger.checkPtraceScope() < 0:
            raise Exception("no ptrace perm")

        # trace flags #
        self.traceEventList = [
            "PTRACE_O_TRACEEXEC",
            "PTRACE_O_TRACESYSGOOD",
            "PTRACE_O_TRACECLONE",
            "PTRACE_O_TRACEFORK",
            "PTRACE_O_TRACEVFORK",
            "PTRACE_O_TRACEEXIT",
        ]

        # load libc #
        SysMgr.loadLibcObj(exit=True)

        # define member classes #
        """
struct iovec {
    ptr_t iov_base; /* Starting address */
    size_t iov_len; /* Length in bytes */
};
        """

        class iovec(Structure):
            _fields_ = (("iov_base", c_void_p), ("iov_len", c_size_t))

        self.iovec = iovec
        self.iovec_ptr = iovec_ptr = POINTER(iovec)

        """
struct msghdr {
    void            *msg_name;  /* ptr to socket address structure */
    int             msg_namelen;    /* size of socket address structure */
    struct iov_iter msg_iter;   /* data */
    void            *msg_control;   /* ancillary data */
    size_t msg_controllen; /* ancillary data buffer length */
    unsigned int    msg_flags;  /* flags on received message */
    struct kiocb    *msg_iocb;  /* ptr to iocb for async requests */
};
        """

        class msghdr(Structure):
            _fields_ = (
                ("msg_name", c_void_p),
                ("msg_namelen", c_uint),
                ("msg_iov", iovec_ptr),
                ("msg_iovlen", c_size_t),
                ("msg_control", c_void_p),
                ("msg_controllen", c_size_t),
                ("msg_flags", c_int),
            )

        self.msghdr = msghdr
        self.msghdr_ptr = POINTER(msghdr)

        """
struct mmsghdr {
    struct msghdr msg_hdr;  /* Message header */
    unsigned int  msg_len;  /* Number of received bytes for header */
};
        """

        class mmsghdr(Structure):
            _fields_ = (("msg_hdr", msghdr), ("msg_len", c_uint))

        self.mmsghdr = mmsghdr
        self.mmsghdr_ptr = POINTER(mmsghdr)

        """
struct cmsghdr {
   size_t cmsg_len;    /* Data byte count, including header
                          (type is socklen_t in POSIX) */
   int    cmsg_level;  /* Originating protocol */
   int    cmsg_type;   /* Protocol-specific type */
/* followed by
  unsigned char cmsg_data[]; */
};
        """

        class cmsghdr(Structure):
            _fields_ = (
                ("cmsg_len", c_size_t),
                ("cmsg_level", c_int),
                ("cmsg_type", c_int),
            )

        self.cmsghdr = cmsghdr
        self.cmsghdr_ptr = cmsghdr_ptr = POINTER(cmsghdr)

        """
typedef struct {
    uintptr_t absolute_pc;     /* absolute PC offset */
    uintptr_t stack_top;       /* top of stack for this frame */
    size_t stack_size;         /* size of this stack frame */
} backtrace_frame_t;
        """

        class backtrace_frame_t(Structure):
            _fields_ = (
                ("absolute_pc", c_uint),
                ("stack_top", c_uint),
                ("stack_size", c_size_t),
            )

        self.btframe = backtrace_frame_t
        self.btframe_ptr = btframe_ptr = POINTER(backtrace_frame_t)

        """
typedef struct {
    uintptr_t relative_pc;       /* relative frame PC offset from the start of the library,
                                    or the absolute PC if the library is unknown */
    uintptr_t relative_symbol_addr; /* relative offset of the symbol from the start of the
                                    library or 0 if the library is unknown */
    char* map_name;              /* executable or library name, or NULL if unknown */
    char* symbol_name;           /* symbol name, or NULL if unknown */
    char* demangled_name;        /* demangled symbol name, or NULL if unknown */
} backtrace_symbol_t;
        """

        class backtrace_symbol_t(Structure):
            _fields_ = (
                ("relative_pc", c_uint),
                ("relative_symbol_addr", c_uint),
                ("map_name", c_char_p),
                ("symbol_name", c_char_p),
                ("demangled_name", c_char_p),
            )

        self.btsym = backtrace_symbol_t
        self.btsym_ptr = btsym_ptr = POINTER(backtrace_symbol_t)

        # apply environment variables #
        self.applyEnviron()

        # running #
        self.isRunning = False
        if self.checkPid(pid) >= 0:
            self.pid = long(pid)
            self.isRunning = True

            if self.isInRun() is None:
                if self.comm:
                    procInfo = "%s(%s)" % (self.comm, pid)
                else:
                    procInfo = "the task with TID %s" % pid
                SysMgr.printErr("failed to find %s" % procInfo)

                sys.exit(-1)

            # update comm #
            if not self.comm:
                self.comm = SysMgr.getComm(self.pid, cache=True, save=True)

            if attach:
                if self.attach(verb=True) < 0:
                    sys.exit(-1)
        # execute #
        elif self.execCmd:
            self.execute(self.execCmd)
            if mode in ("signal", "kernel"):
                # wait for PTRACE_TRACEME of the child #
                time.sleep(0.1)

                # attach to the child #
                self.attach()
        # ready #
        else:
            self.pid = None

        # set variables for register #
        self.regs = self.getRegStruct()
        self.iovecObj = self.getIovec(self.regs)
        self.fpregs = self.getFpRegStruct()
        self.tempFpRegs = self.getFpRegStruct()
        self.tempRegs = self.getRegStruct()
        self.tempIovecObj = self.getIovec(self.tempRegs)
        self.btRegs = self.getRegStruct()
        self.btIovecObj = self.getIovec(self.btRegs)
        self.sigObj = self.getSigStruct()
        self.regsDict = None
        self.fpRegsDict = None

        # save singleton instance #
        if self.pid != SysMgr.pid:
            Debugger.dbgInstance = self

    def applyEnviron(self):
        # set return time condition #
        self.retTime = 0.1

        # set filter condition for elapsed time #
        if "ELAPSED" in SysMgr.environList:
            self.retTime = UtilMgr.getEnvironNum("ELAPSED")

        # set target sequence #
        if not Debugger.targetNums and "TARGETNUM" in SysMgr.environList:
            for item in SysMgr.environList["TARGETNUM"]:
                try:
                    Debugger.targetNums.setdefault(long(item), None)
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(
                        "failed to add '%s' target number list" % item, True
                    )
                    sys.exit(-1)

            SysMgr.printInfo(
                "set the target number list to [%s] for new threads"
                % ",".join(list(map(str, Debugger.targetNums)))
            )

        # apply color for return string #
        if not Debugger.RETSTR:
            Debugger.RETSTR = UtilMgr.convColor("[RET]", "OKBLUE")

        # update flags by environment variable #
        for item in list(Debugger.envFlags):
            if item in SysMgr.environList and not Debugger.envFlags[item]:
                Debugger.envFlags[item] = True

        # apply showing symbol flag #
        if Debugger.envFlags["HIDESYM"]:
            self.showStatus = False

        # print elapsed time for python #
        if "PYELAPSED" in SysMgr.environList:
            Debugger.pyElapsed = UtilMgr.getEnvironNum("PYELAPSED")

        # filter for CPU threshold #
        if "CPUCOND" in SysMgr.environList:
            Debugger.cpuCond = UtilMgr.getEnvironNum("CPUCOND", isInt=True)

        # set string size #
        if Debugger.strSize == -1 and "STRSIZE" in SysMgr.environList:
            Debugger.strSize = UtilMgr.getEnvironNum("STRSIZE", isInt=True)

    def getIovec(self, reg):
        return self.iovec(iov_base=addressof(reg), iov_len=sizeof(reg))

    def __del__(self, stop=False):
        if not self.attached:
            return
        elif not self.isAlive():
            return

        # kill target children #
        if hasattr(self, "childList"):
            SysMgr.killChildren(sig=signal.SIGINT, children=self.childList)
            del self.childList

        # detach target #
        self.detach()

        # continue target #
        try:
            if stop:
                os.kill(self.pid, signal.SIGSTOP)
            else:
                SysMgr.syscall(self.tkillIdx, self.pid, signal.SIGCONT)
        except:
            SysMgr.printSigError(self.pid, "SIGCONT")
            return

    @staticmethod
    def loadElfList(path):
        try:
            with open(path, "r") as fd:
                fdList = fd.readlines()
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to open '%s' to get ELF file list" % path, True
            )
            sys.exit(0)

        for item in fdList:
            try:
                # get target file #
                target = item.split()
                if not target:
                    continue
                elif len(target) == 1:
                    target = target[0]
                else:
                    target = target[-1]

                # check validation #
                if not target:
                    continue
                elif not FileAnalyzer.isValidFile(target):
                    continue

                # load target file #
                eobj = ElfAnalyzer.getObject(target.strip("[]"))
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("failed to load ELF file '%s'" % target, True)

    @staticmethod
    def hookFunc(pid, hookList=[], mode="hook"):
        comm = SysMgr.getComm(pid)
        procInfo = "%s(%s)" % (comm, pid)

        # attach to target #
        try:
            dobj = Debugger(pid=pid, attach=False)
            dobj.initValues()
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to hook for %s" % procInfo, True)
            sys.exit(-1)

        # load libraries in advance #
        dobj.loadSymbols()
        if dobj.attach() < 0:
            sys.exit(-1)

        # register my instance #
        SysMgr.addExitFunc(Debugger.destroyDebugger, [dobj])

        SysMgr.printInfo("start gathering symbols for %s" % procInfo)

        # convert filter for print mode #
        if mode == "print":
            filterList = hookList
            hookList = []
        else:
            filterList = []

        # get symbol info #
        loadBin = {}
        hooks = []
        for item in hookList:
            symbols = item.split("#")

            # check parameter #
            if len(symbols) == 1:
                SysMgr.printErr("failed to recognize '%s'" % item)
                sys.exit(-1)

            # get symbols from string #
            oldSym = symbols[0]
            fpath = os.path.realpath(os.path.expanduser(symbols[1].strip()))
            if len(symbols) == 2:
                if fpath:
                    newSym = oldSym
                else:
                    newSym = symbols[1]
            elif len(symbols) == 3:
                newSym = symbols[2]
            else:
                SysMgr.printErr("failed to recognize '%s'" % item)
                sys.exit(-1)

            # load the library #
            if not fpath in loadBin:
                loadBin.setdefault(fpath, None)

                # remote load #
                ret = dobj.dlopen(fpath)
                if ret == 0:
                    errMsg = " because remote dlopen failed"
                else:
                    errMsg = ""

                # update and check target map #
                dobj.loadSymbols()
                if not fpath in dobj.pmap:
                    SysMgr.printErr(
                        "failed to find '%s' on memory map for %s%s"
                        % (fpath, procInfo, errMsg)
                    )

                    PageAnalyzer.printMemoryArea(pid, comm=comm, lastLine=True)

                    sys.exit(-1)

            # get target symbol info #
            oldSet = dobj.getAddrBySymbol(oldSym)
            if not oldSet:
                SysMgr.printWarn(
                    "failed to find '%s' info from %s" % (oldSym, procInfo)
                )
                continue

            # get hook symbol info #
            newSet = dobj.getAddrBySymbol(newSym, fpath)
            if not newSet:
                SysMgr.printErr(
                    "failed to find '%s' info in %s from %s"
                    % (newSym, fpath, procInfo)
                )
                continue

            # add a set to list #
            hooks.append([oldSet, newSet])

        # create a hook hash list #
        hookHash = {}
        for item in hooks:
            targetSym = item[0][0][1]
            hookHash[targetSym] = item

        # stop target #
        SysMgr.sendSignalProcs(signal.SIGSTOP, [pid], verb=False)

        # print context #
        dobj.printContext(regs=SysMgr.showAll, newline=True)

        # define link list #
        linkList = {}
        convColor = UtilMgr.convColor
        nrUpdated = 0

        for fpath, mapInfo in dobj.pmap.items():
            # skip same binary to prevent infinite recursive call #
            if not fpath.startswith("/"):
                continue

            # get ELF object #
            fcache = ElfAnalyzer.getObject(fpath)
            if not hasattr(fcache, "attr"):
                continue

            # get start address on map for the binary #
            if ElfAnalyzer.isRelocFile(fpath):
                vstart = mapInfo["vstart"]
            else:
                vstart = 0

            # get mapping info #
            for sym, attr in sorted(
                fcache.attr["dynsymTable"].items(),
                key=lambda x: x[1]["size"],
                reverse=False,
            ):
                # ignore original symbols #
                if mode == "hook" and attr["size"] > 0:
                    break
                # save link info #
                elif mode == "print" and sym and not hookHash:
                    # get relative type #
                    try:
                        rtype = ElfAnalyzer.RELOC_TYPE[attr["rtype"]]
                    except:
                        rtype = None

                    # original symbols #
                    if attr["size"] > 0:
                        origAddr = hex(vstart + attr["value"]).rstrip("L")
                        linkInfo = convColor("ORIGIN(%s)" % origAddr, "CYAN")

                        # add copy flag for reference variable #
                        """
                        When using dlopen() to load shared objects,
                        The address of variables with the same name
                        declared using the extern keyword can be different.
                        The default operation is to search the previously
                        defined symbol in the global area first.
                        But if the RTLD_DEEPBIND flag is set,
                        The shared objects with dependencies are searched first.
                        RTLD_DEEPBIND flag changes the search order for symbol
                        lookup in shared objects.
                        """
                        if rtype and rtype.endswith("_COPY"):
                            linkInfo += convColor("[COPY]", "RED")
                    # linked symbols #
                    elif attr["value"] > 0:
                        slotAddr = vstart + attr["value"]

                        # get reference address #
                        linkAddr = dobj.readWord(slotAddr)
                        if type(linkAddr) is not long:
                            linkAddr = UtilMgr.convWord2Str(linkAddr)

                        # get dereference address #
                        if fcache.isInPlt(linkAddr):
                            linkInfo = "PLT(%s)" % hex(linkAddr)
                        else:
                            linkData = dobj.getSymbolInfo(
                                linkAddr, onlyFunc=False, onlyExec=False
                            )
                            if linkData:
                                if UtilMgr.isNumber(
                                    linkData[2]
                                ) and fcache.isInPlt(long(linkData[2], 16)):
                                    linkInfo = convColor(
                                        "PLT(%s)" % linkData[2], "RED"
                                    )
                                else:
                                    linkSym = linkData[0]
                                    if linkData[0] != "??":
                                        linkSym = convColor(linkSym, "GREEN")
                                    linkInfo = "%s/%s[%s/%s]" % (
                                        linkSym,
                                        hex(linkAddr).rstrip("L"),
                                        convColor(linkData[1], "WARNING"),
                                        linkData[2],
                                    )
                            else:
                                linkInfo = convColor("ORIGIN", "CYAN")
                    else:
                        linkInfo = "NONE"

                    # register link info to list #
                    linkList.setdefault(fpath, [])
                    linkList[fpath].append(
                        (
                            convColor(sym, "YELLOW"),
                            attr["bind"],
                            attr["vis"],
                            attr["type"],
                            linkInfo,
                        )
                    )

                    continue

                # check target symbol #
                pureSymbol = sym.split("@")[0]
                if not pureSymbol in hookHash:
                    continue

                item = hookHash[pureSymbol]

                # hook info #
                hook = item[1][0]
                hookAddr, hookSym, hookBin = hook[:3]

                # target info #
                target = item[0][0]
                targetAddr, targetSym, targetBin = target[:3]

                # read original address for target #
                slotAddr = vstart + attr["value"]
                origAddr = dobj.readWord(slotAddr)

                mprotected = False
                while 1:
                    # write hook address for target #
                    if slotAddr % ConfigMgr.wordSize == 0:
                        ret = dobj.accessMem(dobj.pokeIdx, slotAddr, hookAddr)
                    else:
                        ret = dobj.writeMem(slotAddr, hookAddr)

                    # change access permission on the page #
                    if ret == -1:
                        if mprotected:
                            break
                        else:
                            dobj.mprotect(slotAddr)
                    else:
                        break

                # read updated address for verification #
                newAddr = dobj.readWord(slotAddr)

                # set symbol info #
                srcInfo = '"%s[%s@%s]"' % (targetSym, hex(targetAddr), fpath)
                desInfo = '"%s[%s@%s]"' % (hookSym, hex(hookAddr), hookBin)

                # check update result #
                if hookAddr == newAddr:
                    nrUpdated += 1
                    SysMgr.printInfo(
                        "updated %s to %s for %s"
                        % (srcInfo, desInfo, procInfo),
                        prefix=False,
                    )
                else:
                    SysMgr.printErr(
                        "failed to update %s to %s for %s"
                        % (srcInfo, desInfo, procInfo)
                    )

        # continue target #
        SysMgr.sendSignalProcs(signal.SIGCONT, [pid], verb=False)

        if not linkList:
            if not nrUpdated:
                SysMgr.printErr("no hooked function")
            return

        # set pager #
        if not SysMgr.findOption("Q"):
            SysMgr.streamEnable = False

        # print title for bind info #
        SysMgr.printPipe(
            "\n[Function Bind Info] [Target: %s]\n%s" % (procInfo, twoLine)
        )

        SysMgr.printPipe(
            "{0:6} {1:>7} {2:1} => {3:1}".format(
                "Path", "Type", "Sym[Bind/Vis]", "Link"
            )
        )

        path = None
        direct = convColor("=>", "BLUE")
        for path, links in linkList.items():
            SysMgr.printPipe("%s\n[%s]" % (oneLine, path))

            for item in sorted(links):
                source = "%s[%s/%s]" % (item[0], item[1], item[2])

                string = "{0:6} {1:>7} {2:1} {3:1} {4:1}".format(
                    " ", item[3], source, direct, item[4]
                )

                if filterList:
                    if UtilMgr.isValidStr(string, filterList):
                        SysMgr.printPipe(string)
                else:
                    SysMgr.printPipe(string)
        SysMgr.printPipe(oneLine)

    @staticmethod
    def getGlobalLock(name=None, size=0, exit=True):
        if Debugger.gLockObj:
            return Debugger.gLockObj

        # create a global lock based on file #
        try:
            SysMgr.importPkgItems("fcntl")

            if os.path.isdir(SysMgr.tmpPath):
                dirpath = SysMgr.tmpPath
            else:
                dirpath = SysMgr.cacheDirPath

            if not name:
                name = SysMgr.pid

            Debugger.gLockPath = "%s/guider_%s.lock" % (dirpath, name)
            Debugger.gLockObj = open(Debugger.gLockPath, "w")
            os.chmod(Debugger.gLockPath, 0o777)

            if size != 0:
                Debugger.gLockObj.truncate(size)

        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to create %s for lock" % Debugger.gLockPath, True
            )

            if exit and not SysMgr.forceEnable:
                sys.exit(-1)

        return Debugger.gLockObj

    def readArgs(self):
        arch = self.arch
        regs = self.regs

        if arch == "aarch64":
            ret = (
                regs.x0,
                regs.x1,
                regs.x2,
                regs.x3,
                regs.x4,
                regs.x5,
                regs.x6,
                regs.x7,
            )
        elif arch == "arm":
            ret = (
                regs.r0,
                regs.r1,
                regs.r2,
                regs.r3,
                regs.r4,
                regs.r5,
                regs.r6,
            )
        elif arch == "x64":
            ret = (regs.rdi, regs.rsi, regs.rdx, regs.rcx, regs.r8, regs.r9)
        elif arch == "x86":
            ret = (regs.ebx, regs.ecx, regs.edx, regs.esi, regs.edi, regs.ebp)
        elif arch == "powerpc":
            ret = (
                regs.gpr3,
                regs.gpr4,
                regs.gpr5,
                regs.gpr6,
                regs.gpr7,
                regs.gpr8,
            )
        else:
            return None

        return tuple(map(lambda x: -1 if c_int(x).value == -1 else x, ret))

    def writeArgs(self, argList):
        arch = self.arch
        nrArg = len(argList)

        if not argList:
            return

        for idx, val in enumerate(argList):
            if val is None or val == "":
                continue

            if arch == "aarch64":
                if idx == 0:
                    self.regs.x0 = val
                elif idx == 1:
                    self.regs.x1 = val
                elif idx == 2:
                    self.regs.x2 = val
                elif idx == 3:
                    self.regs.x3 = val
                elif idx == 4:
                    self.regs.x4 = val
                elif idx == 5:
                    self.regs.x5 = val
                elif idx == 6:
                    self.regs.x6 = val
                elif idx == 7:
                    self.regs.x7 = val
            elif arch == "x64":
                if idx == 0:
                    self.regs.rdi = val
                elif idx == 1:
                    self.regs.rsi = val
                elif idx == 2:
                    self.regs.rdx = val
                elif idx == 3:
                    self.regs.rcx = val
                elif idx == 4:
                    self.regs.r8 = val
                elif idx == 5:
                    self.regs.r9 = val
            elif arch == "arm":
                if idx == 0:
                    self.regs.r0 = val
                elif idx == 1:
                    self.regs.r1 = val
                elif idx == 2:
                    self.regs.r2 = val
                elif idx == 3:
                    self.regs.r3 = val
                elif idx == 4:
                    self.regs.r4 = val
                elif idx == 5:
                    self.regs.r5 = val
                elif idx == 6:
                    self.regs.r6 = val
            elif arch == "x86":
                if idx == 0:
                    self.regs.ebx = val
                elif idx == 1:
                    self.regs.ecx = val
                elif idx == 2:
                    self.regs.edx = val
                elif idx == 3:
                    self.regs.esi = val
                elif idx == 4:
                    self.regs.edi = val
                elif idx == 5:
                    self.regs.ebp = val
            elif arch == "powerpc":
                if idx == 0:
                    self.regs.gpr3 = val
                elif idx == 1:
                    self.regs.gpr4 = val
                elif idx == 2:
                    self.regs.gpr5 = val
                elif idx == 3:
                    self.regs.gpr6 = val
                elif idx == 4:
                    self.regs.gpr7 = val
                elif idx == 5:
                    self.regs.gpr8 = val
            else:
                return

    def setPid(self, pid):
        if self.checkPid(pid) < 0:
            SysMgr.printErr("failed to set PID %s" % pid)
            return -1

        self.pid = pid
        return 0

    def getPid(self):
        return self.pid

    def convRetArgs(self, argList):
        for idx, item in enumerate(deepcopy(argList)):
            if type(item) is str and item.startswith("@"):
                try:
                    argList[idx] = self.retList[item[1:]]
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

        return argList

    def executeCmd(self, cmdList, sym=None, fname=None, args=[], force=False):
        def _flushPrint(newline=True):
            if SysMgr.outPath:
                if SysMgr.showAll:
                    self.callPrint.append(SysMgr.bufferString[1:])

                # print to stdout #
                if SysMgr.streamEnable:
                    sys.stdout.write(SysMgr.bufferString)
            else:
                SysMgr.printPipe(
                    SysMgr.bufferString, flush=True, newline=newline
                )

                if self.bufferedStr:
                    SysMgr.printPipe(
                        self.bufferedStr, flush=True, newline=newline
                    )
                    self.bufferedStr = ""

            SysMgr.clearPrint()

        def _printCmdErr(cmdset, cmd):
            cmdsetList = {
                "acc": "NAME:VAR|REG|VAL",
                "add": "SYM;",
                "check": "VAR|NAME|ADDR|REG:OP(EQ/DF/INC/BT/LT):VAL:SIZE:EVT",
                "condexit": "",
                "dist": "NAME:VAR|REG|VAL",
                "dump": "NAME|ADDR:FILE",
                "event": "MESSAGE",
                "exec": "COMMAND",
                "exit": "",
                "getarg": "REG:REG",
                "getenv": "VAR",
                "getret": "CMD",
                "hide": "",
                "inter": "VAL",
                "interval": "FUNC",
                "jump": "SYMBOL|ADDR#ARG0#ARG1",
                "load": "PATH",
                "log": "MESSAGE",
                "map": "",
                "print": "VAR",
                "pyfile": "PATH:SYNC",
                "pyscript": "PATH:FUNC:ARGS",
                "pystr": "CODE:SYNC",
                "rdmem": "VAR|ADDR|REG:SIZE",
                "remove": "SYM;",
                "repeat": "CNT",
                "ret": "VAL",
                "save": "VAR:VAL:TYPE",
                "setarg": "REG#VAL:REG#VAL",
                "setenv": "VAR#VAR|VAL",
                "setret": "VAL:CMD",
                "show": "",
                "start": "",
                "stop": "",
                "syscall": "SYSCALL#ARG0#ARG1",
                "thread": "",
                "proctop": "PID|COMM",
                "proctopg": "PID|COMM",
                "thrtop": "PID|COMM",
                "thrtopg": "PID|COMM",
                "usercall": "FUNC#ARG0#ARG1",
                "wrmem": "VAR|ADDR|REG:VAL:SIZE",
            }

            if cmd in cmdsetList:
                cmdformat = cmdsetList[cmd]
            else:
                cmdformat = ""

            if cmdformat:
                cmdformat = ":%s" % cmdformat

            SysMgr.printErr(
                "wrong command '%s', input in the format {%s%s}"
                % (cmdset, cmd, cmdformat)
            )
            sys.exit(-1)

        def _addPrint(string):
            if self.showStatus and not sym in self.hiddenList:
                SysMgr.addPrint(string)

        def _execFunc(func, *args):
            # get previous stats #
            if Debugger.envFlags["PRINTDIFF"]:
                prevTime, prevCpu, prevMem, prevIo = _getStats()

            ret = func(*args)

            # print diff stats #
            if Debugger.envFlags["PRINTDIFF"]:
                _printDiff(prevTime, prevCpu, prevMem, prevIo)

            return ret

        def _getStats():
            prevTime = time.time()
            prevCpu = self.getTotalCpuTick()
            prevMem = SysMgr.getMemStat(self.pid)
            prevIo = SysMgr.readFile("%s/%s/io" % (SysMgr.procPath, self.pid))
            return prevTime, prevCpu, prevMem, prevIo

        def _printDiff(prevTime, prevCpu, prevMem, prevIo):
            # time diff #
            diff = time.time() - prevTime

            # CPU diff #
            afterCpu = self.getTotalCpuTick()
            cpu = afterCpu[0] - prevCpu[0]
            if cpu:
                cpu = "+%d" % cpu

            prevMem = SysMgr.convMemStat(prevMem)
            afterMem = SysMgr.getMemStat(self.pid)
            afterMem = SysMgr.convMemStat(afterMem)

            # VSS diff #
            vss = UtilMgr.convSize2Unit(afterMem["vss"] - prevMem["vss"])
            if vss != "0" and not vss.startswith("-"):
                vss = "+" + vss

            # RSS diff #
            rss = UtilMgr.convSize2Unit(afterMem["rss"] - prevMem["rss"])
            if rss != "0" and not rss.startswith("-"):
                rss = "+" + rss

            # I/O diff #
            readIo = writeIo = 0
            if prevIo:

                def _getIoStats(iodata):
                    ioStats = {}
                    for line in iodata.split("\n"):
                        # get stats #
                        ios = line.split()
                        if len(ios) != 2:
                            continue

                        # check stats #
                        name, val = ios
                        if not name in ("read_bytes:", "write_bytes:"):
                            continue

                        ioStats[name[:-1]] = long(val)
                    return ioStats

                afterIo = SysMgr.readFile(
                    "%s/%s/io" % (SysMgr.procPath, self.pid)
                )
                if afterIo:
                    beforeIoStats = _getIoStats(prevIo)
                    afterIoStats = _getIoStats(afterIo)

                    def _getIoDiff(name):
                        diff = afterIoStats[name] - beforeIoStats[name]
                        if diff:
                            diff = "+%s" % UtilMgr.convSize2Unit(diff)
                        return diff

                    readIo = _getIoDiff("read_bytes")
                    writeIo = _getIoDiff("write_bytes")

            self.bufferedStr += UtilMgr.convColor(
                (
                    "\n%s<stat> TIME: %.6f Sec, CPU: %s%%, VSS: %s, "
                    "RSS: %s, READ: %s, WRITE: %s"
                )
                % (" " * 11, diff, cpu, vss, rss, readIo, writeIo),
                "YELLOW",
            )

        def _handleCmd(cmdset, cmd):
            repeat = True

            # check repeat #
            if cmd == "oneshot":
                repeat = False
                if len(cmdset) == 1:
                    return repeat
                cmdset = cmdval.split(":", 2)[1:]
                cmd = cmdset[0]

            convColor = UtilMgr.convColor

            # pick a command #
            cmdstr = convColor(cmd, "PINK", 8)

            if cmd == "print":
                if SysMgr.showAll and not force:
                    pass
                elif len(cmdset) == 1:
                    self.printContext(newline=True, brief=True)
                else:
                    var = cmdset[1]
                    try:
                        data = self.retList[var]
                    except:
                        data = "N/A"

                    _addPrint("\n[%s] %s = %s" % (cmdstr, var, data))

            elif cmd == "ret":
                if len(cmdset) == 1:
                    _printCmdErr(cmdval, cmd)

                # get return value #
                ret = UtilMgr.convStr2Num(cmdset[1])
                if ret is None:
                    SysMgr.printErr("wrong return value %s" % cmdset[1])
                    return repeat

                # get return address #
                wordSize = ConfigMgr.wordSize
                if self.lr:
                    targetAddr = self.lr
                else:
                    targetAddr = self.fp + wordSize
                    if targetAddr % wordSize == 0:
                        targetAddr = self.accessMem(self.peekIdx, targetAddr)
                    else:
                        targetAddr = self.readMem(targetAddr, retWord=True)

                retval = "0x%x" % ret
                _addPrint("\n[%s] %s(%s)" % (cmdstr, ret, retval))

                # set register values #
                self.setRet(ret)
                self.setPC(targetAddr)
                self.setRegs()
                self.updateRegs()

            elif cmd == "getret":
                if len(cmdset) > 1:
                    cmd = cmdset[1].split("$")
                else:
                    cmd = None

                # set breakpoint to return address #
                ret = self.setRetBp(sym, fname, cmd)
                if not ret:
                    SysMgr.printErr(
                        (
                            "failed to set breakpoint to "
                            "return address for %s"
                        )
                        % sym
                    )
                    return repeat

            elif cmd == "setret":
                if len(cmdset) == 1:
                    _printCmdErr(cmdval, cmd)

                memset = cmdset[1].split(":", 1)
                if len(memset) > 1:
                    cmd = memset[1].split("$")
                else:
                    cmd = None

                # convert return type #
                try:
                    val = memset[0]
                    num = long(val, 16)
                except:
                    num = long(val)

                # inject the new breakpoint for return #
                if self.mode == "syscall":
                    setattr(self.regs, self.retreg, num)
                    self.setRegs()
                else:
                    ret = self.setRetBp(sym, fname, cmd)
                    if not ret:
                        SysMgr.printErr(
                            (
                                "failed to set breakpoint to "
                                "return address for %s"
                            )
                            % sym
                        )
                        return repeat

                    # register a return value #
                    newSym = sym + Debugger.RETSTR
                    self.setRetList.setdefault(newSym, [])
                    self.setRetList[newSym].append(num)

                # print return value #
                _addPrint("\n[%s] %s" % (cmdstr, val))

            elif cmd == "setarg":
                if len(cmdset) == 1:
                    _printCmdErr(cmdval, cmd)

                # get argument info #
                nrMax = 0
                argStr = ""
                argSet = {}
                origArgs = args
                argList = cmdset[1].split(":")

                # convert args for previous return #
                argList = self.convRetArgs(argList)

                for item in argList:
                    idx, val = item.split("#")
                    idx = long(idx)
                    val = UtilMgr.convStr2Num(val)
                    argSet[idx] = val
                    if nrMax < idx:
                        nrMax = idx
                    argStr += "%s: %s(%s) -> %s(%s), " % (
                        idx,
                        hex(origArgs[idx]).rstrip("L"),
                        origArgs[idx],
                        hex(val).rstrip("L"),
                        val,
                    )

                # complete output string #
                if not argStr:
                    res = ""
                else:
                    res = argStr[: argStr.rfind(",")]

                # make a new argument list #
                argList = [None] * (nrMax + 1)
                for idx, val in argSet.items():
                    # convert args for previous return #
                    val = self.convRetArgs([val])

                    argList[long(idx)] = val[0]

                _addPrint("\n[%s] %s" % (cmdstr, res))

                # set register values #
                self.writeArgs(argList)
                self.setRegs()
                self.updateRegs()

            elif cmd == "getarg":
                if len(cmdset) == 1:
                    _printCmdErr(cmdval, cmd)

                # get argument info #
                argStr = ""
                argList = cmdset[1].split(":")

                # convert args for previous return #
                argList = self.convRetArgs(argList)

                for item in argList:
                    if not str(item):
                        continue

                    try:
                        val = args[long(item)]
                    except SystemExit:
                        sys.exit(0)
                    except:
                        val = "None"

                    # update return #
                    self.prevReturn = str(val)

                    argStr += "%s: %s(%s), " % (
                        item,
                        hex(val).rstrip("L"),
                        val,
                    )

                # complete output string #
                if not argStr:
                    res = ""
                else:
                    res = argStr[: argStr.rfind(",")]

                _addPrint("\n[%s] %s" % (cmdstr, res))

            elif cmd == "event":
                if len(cmdset) == 1:
                    _printCmdErr(cmdval, cmd)

                name = ":".join(cmdset[1:])

                SysMgr.writeEvent(
                    "EVENT_%s(%s)/%.6f" % (name, sym, self.vdiff), False
                )

                _addPrint("\n[%s] EVENT_%s" % (cmdstr, name))

            elif cmd in ("proctop", "proctopg", "thrtop", "thrtopg"):
                if len(cmdset) == 1:
                    target = "ALL"
                    filterOpt = ""
                else:
                    target = ":".join(cmdset[1:])
                    filterOpt = "-g %s" % target

                if cmd.startswith("proctop"):
                    gcmd = "top"
                elif cmd.startswith("thrtop"):
                    gcmd = "ttop"

                _addPrint("\n[%s] %s" % (cmdstr, target))
                _flushPrint()

                rcmd = ["GUIDER", gcmd, "-eTb", "-dL", "-R1", "-qfastinit"]
                if filterOpt:
                    rcmd += [filterOpt]
                if cmd.endswith("g"):
                    rcmd += ["-P"]

                SysMgr.execBgCmd(rcmd, mute=False)

            elif cmd == "rdmem":
                if len(cmdset) == 1:
                    _printCmdErr(cmdval, cmd)

                # get argument info #
                memset = cmdset[1].split(":")
                if len(memset) != 1 and len(memset) != 2:
                    _printCmdErr(cmdval, cmd)

                # convert args for previous return #
                memset = self.convRetArgs(memset)

                # get addr #
                addr = UtilMgr.convStr2Num(memset[0])
                if addr is None:
                    return repeat

                # get size #
                if len(memset) == 2:
                    fixed = True
                    size = UtilMgr.convStr2Num(memset[1])
                    if size is None:
                        return repeat
                else:
                    fixed = False
                    size = 32

                # convert address from registers #
                try:
                    addr = args[addr]
                except:
                    pass

                # get address #
                if UtilMgr.isNumber(addr):
                    addr = UtilMgr.convStr2Num(addr)
                    if addr is None:
                        return repeat
                else:
                    SysMgr.printErr("wrong addr %s" % addr)
                    return repeat

                # get memory value #
                ret = self.readMem(addr, size)
                if ret is None or ret == -1:
                    SysMgr.printErr(
                        "failed to read from %s" % hex(addr).rstrip("L")
                    )
                    return repeat

                # update return #
                try:
                    ret = ret.decode()
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

                self.retList[addr] = ret
                self.prevReturn = ret

                # strip garbage #
                if ret and not fixed:
                    try:
                        ret = ret.split("\x00")[0]
                        size = len(ret)
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass

                # convert to binary #
                try:
                    binary = struct.unpack("%sB" % len(ret), ret)
                    binstr = " [0x"
                    for item in binary:
                        binstr += "%x" % item
                    binstr += "]"
                except SystemExit:
                    sys.exit(0)
                except:
                    binstr = ""

                _addPrint(
                    "\n[%s] %s: %s(%sbyte)%s"
                    % (cmdstr, hex(addr).rstrip("L"), repr(ret), size, binstr)
                )

            elif cmd == "wrmem":
                if len(cmdset) == 1:
                    _printCmdErr(cmdval, cmd)

                # get argument info #
                memset = cmdset[1].split(":")
                if len(memset) != 2 and len(memset) != 3:
                    _printCmdErr(cmdval, cmd)

                # convert args for previous return #
                memset = self.convRetArgs(memset)

                # get addr #
                addr = UtilMgr.convStr2Num(memset[0])
                if addr is None:
                    return repeat

                # get value #
                val = memset[1].encode()

                # get size #
                if len(memset) == 3:
                    size = UtilMgr.convStr2Num(memset[2])
                else:
                    size = len(val)

                # increase size #
                if len(val) < size:
                    val += b" " * (size - len(val))

                # convert address from registers #
                try:
                    addr = args[addr]
                except:
                    pass

                # get address #
                addr = UtilMgr.convStr2Num(addr)
                if addr is None:
                    return repeat

                _addPrint(
                    "\n[%s] %s: %s(%sbyte)"
                    % (cmdstr, hex(addr).rstrip("L"), repr(val[:size]), size)
                )

                # set register values #
                ret = self.writeMem(addr, val, size)
                if ret is None or ret == -1:
                    SysMgr.printErr(
                        "failed to write '%s' to %s"
                        % (val.decode(), hex(addr).rstrip("L"))
                    )
                    return repeat

            elif cmd == "check":
                cmds = ":".join(cmdset)
                ret = self.checkFilterCond(cmds, args, sym, fname)

                # broadcast event #
                if ret:
                    skip = False
                    params = cmdset[1].split(":")
                    if len(params) > 4:
                        SysMgr.broadcastEvent(params[4])
                else:
                    skip = True

                # change color for False #
                if ret:
                    ret = convColor(ret, "GREEN")
                else:
                    ret = convColor(ret, "RED")

                _addPrint("\n[%s] %s = %s" % (cmdstr, cmdset[1], ret))

                if skip:
                    raise UserWarning
                else:
                    return ret

            elif cmd == "setinter":
                if len(cmdset) == 1:
                    _printCmdErr(cmdval, cmd)

                # set timestamp #
                func = cmdset[1]

                if not func in self.intervalList:
                    # get function addr #
                    ret = self.getAddrBySymbol(func)
                    if not ret:
                        SysMgr.printErr("no function named %s" % func)
                        sys.exit(-1)

                    # check breakpoint #
                    addr = ret[0][0]
                    if not addr in self.bpList:
                        SysMgr.printErr("no breakpoint for %s" % func)
                        sys.exit(-1)

                    # set command for last function #
                    if not self.bpList[addr]["cmd"]:
                        self.bpList[addr]["cmd"] = []
                    if not "_interval" in self.bpList[addr]["cmd"]:
                        self.bpList[addr]["cmd"].append("getinter")

                    _addPrint(
                        "\n[%s] %s ~ %s(%s)"
                        % (cmdstr, sym, func, hex(addr).rstrip("L"))
                    )

                    self.intervalList.setdefault(func, {})

                self.intervalList[func][sym] = self.vdiff

            elif cmd == "getinter":
                if sym in self.intervalList:
                    for name, ts in self.intervalList[sym].items():
                        diff = self.vdiff - ts
                        diffstr = "%.6f" % diff

                        # convert time color #
                        if diff > self.retTime:
                            diffstr = UtilMgr.convColor(diffstr, "RED")
                        else:
                            diffstr = UtilMgr.convColor(diffstr, "CYAN")

                        _addPrint(
                            "\n[%s] %s -> %s ~ %s"
                            % (cmdstr, diffstr, name, sym)
                        )

            elif cmd == "inter":
                # get diff #
                if sym in self.interList:
                    val = self.vdiff - self.interList[sym]["time"]
                    self.interList[sym]["time"] = self.vdiff
                    self.interList[sym]["total"] += val
                else:
                    val = 0

                # accumulate values #
                self.interList.setdefault(
                    sym,
                    dict(
                        {
                            "time": self.vdiff,
                            "cnt": 0,
                            "total": val,
                            "min": float(val),
                            "max": float(val),
                        }
                    ),
                )

                self.interList[sym]["cnt"] += 1
                if (
                    self.interList[sym]["min"] == 0
                    or self.interList[sym]["min"] > val
                ):
                    self.interList[sym]["min"] = val
                if self.interList[sym]["max"] < val:
                    self.interList[sym]["max"] = val

                # get variables #
                cnt = self.interList[sym]["cnt"]
                total = self.interList[sym]["total"]
                avg = total / cnt
                vmin = self.interList[sym]["min"]
                vmax = self.interList[sym]["max"]

                # convert time color #
                itime = "%.6f" % val
                if val > self.retTime:
                    itime = UtilMgr.convColor(itime, "RED")

                _addPrint(
                    (
                        "\n[%s] %s {cnt: %s / avg: %.6f / "
                        "min: %.6f / max: %.6f / total %.6f}"
                    )
                    % (cmdstr, itime, convNum(cnt), avg, vmin, vmax, total)
                )

            elif cmd in ("acc", "dist"):
                if len(cmdset) == 1:
                    _printCmdErr(cmdval, cmd)

                # get argument info #
                memset = cmdset[1].split(":")

                # get name #
                name = memset[0]

                # convert args for previous return #
                memset = self.convRetArgs(memset)

                # get value #
                if len(memset) > 1:
                    data = memset[1]

                    # args #
                    if isinstance(data, (int, long)):
                        pass
                    elif data.isdigit() and long(data) < len(args):
                        data = args[long(data)]
                else:
                    data = "1"

                # convert value #
                val = UtilMgr.convStr2Num(data)
                if val is None:
                    return repeat

                # accumulate values #
                self.accList.setdefault(
                    name, dict({"cnt": 0, "total": 0, "min": val, "max": val})
                )

                self.accList[name]["cnt"] += 1
                self.accList[name]["total"] += val
                if self.accList[name]["min"] > val:
                    self.accList[name]["min"] = val
                if self.accList[name]["max"] < val:
                    self.accList[name]["max"] = val

                # get variables #
                cnt = self.accList[name]["cnt"]
                total = self.accList[name]["total"]
                avg = long(total / cnt)
                vmin = self.accList[name]["min"]
                vmax = self.accList[name]["max"]

                if cmd == "dist":
                    try:
                        idx = long(
                            math.sqrt(  # pylint: disable=used-before-assignment
                                val
                            )
                        )
                    except SystemExit:
                        sys.exit(0)
                    except:
                        try:
                            import math

                            idx = long(math.sqrt(val))
                        except SystemExit:
                            sys.exit(0)
                        except:
                            SysMgr.printErr(
                                "failed to import python package: math"
                            )
                            idx = 0
                    finally:
                        self.accList[name].setdefault("dist", {})
                        self.accList[name]["dist"].setdefault(idx, 0)
                        self.accList[name]["dist"][idx] += 1
                        dist = self.accList[name]["dist"]
                else:
                    dist = ""

                _addPrint(
                    (
                        "\n[%s] %s: %s(%s) "
                        "{cnt: %s / total: %s / avg: %s / "
                        "min: %s / max: %s} %s"
                    )
                    % (
                        cmdstr,
                        name,
                        hex(val).rstrip("L"),
                        val,
                        convNum(cnt),
                        convNum(total),
                        convNum(avg),
                        convNum(vmin),
                        convNum(vmax),
                        dist,
                    )
                )

            elif cmd == "pyscript":
                if len(cmdset) == 1:
                    _printCmdErr(cmdval, cmd)

                # get argument info #
                memset = cmdset[1].split(":")
                if len(memset) < 2:
                    _printCmdErr(cmdval, cmd)

                # get function items #
                path, func = memset[:2]
                if len(memset) > 2:
                    argset = memset[2:]
                else:
                    argset = []

                # call function #
                ret = _execFunc(UtilMgr.callPyFunc, path, func, argset)
                if res:
                    res = UtilMgr.convColor(res, "GREEN")
                else:
                    res = UtilMgr.convColor(res, "RED")

                output = "\n[%s] %s(%s)[%s] = %s" % (
                    cmdstr,
                    func,
                    argset,
                    path,
                    res,
                )
                _addPrint(output)

            elif cmd == "start":
                _addPrint("\n[%s]\n" % (cmdstr))
                _flushPrint(newline=False)

                # update status flag #
                self.startProfTime = self.vdiff

                # inject breakpoints #
                self.loadSymbols()
                self.updateBpList()

                repeat = False

            elif cmd == "show":
                if self.showStatus:
                    prevStr = ""
                else:
                    isRet = True if sym.endswith(Debugger.RETSTR) else False

                    (
                        tinfo,
                        diffstr,
                        arg,
                        argstr,
                        btstr,
                        indent,
                        symColor,
                    ) = self.getBpContext(sym, self.pc, self.readArgs(), isRet)

                    prevStr = " %s %s%s%s" % (
                        diffstr,
                        tinfo,
                        UtilMgr.convColor(sym, symColor),
                        argstr,
                    )

                # show tracing #
                self.showStatus = True

                _addPrint("\n[%s]%s" % (cmdstr, prevStr))
                _flushPrint(newline=False)

            elif cmd == "hidden":
                if not sym in self.hiddenList:
                    _addPrint("\n[%s]" % (cmdstr))
                    _flushPrint(newline=False)

                    # hide function #
                    self.hiddenList[sym] = True

            elif cmd == "hide":
                _addPrint("\n[%s]" % (cmdstr))
                _flushPrint(newline=False)

                # hide tracing #
                self.showStatus = False

            elif cmd == "repeat":
                if sym in self.repeatCntList:
                    pass
                elif len(cmdset) == 2:
                    cnt = long(cmdset[1]) + 1
                    self.repeatCntList.setdefault(sym, cnt)

                again = True

                # check repeat count #
                try:
                    self.repeatCntList[sym] -= 1
                    if self.repeatCntList[sym] == 0:
                        self.repeatCntList.pop(sym, None)
                        again = False
                    rstr = ": %s" % convNum(self.repeatCntList[sym])
                except SystemExit:
                    sys.exit(0)
                except:
                    rstr = ""

                # set breakpoint again #
                if again:
                    # save register set #
                    self.regList[sym] = self.getRegs(new=True)

                    # set a breakpoint at return address #
                    ret = self.setRetBp(sym, fname)
                    if not ret:
                        SysMgr.printErr(
                            (
                                "failed to set breakpoint to "
                                "return address for %s"
                            )
                            % sym
                        )

                output = "\n[%s] %s%s" % (cmdstr, sym, rstr)
                _addPrint(output)

            elif cmd == "map":
                SysMgr.addPrint("\n[%s]" % cmdstr)
                _flushPrint(False)
                PageAnalyzer.printMemoryArea(
                    self.pid,
                    comm=self.comm,
                    lastLine=True,
                    showall=SysMgr.showAll,
                )

            elif cmd == "exec":
                if len(cmdset) == 1:
                    _printCmdErr(cmdval, cmd)

                _addPrint("\n[%s] %s\n" % (cmdstr, "; ".join(cmdset[1:])))
                _flushPrint(newline=False)

                # execute commands #
                for item in cmdset[1].split(";"):
                    command = item.strip()
                    if command.endswith("&"):
                        command = command[:-1]
                        wait = False
                    else:
                        wait = True

                    param = command.split()
                    ret = _execFunc(SysMgr.execBgCmd, param, False, wait)

            elif cmd == "thread":
                ret = self.loadPyLib()
                if not ret:
                    return

                self.initPyLib()

                # init thread objects #
                origPid = self.pid
                self.remoteUsercall("PyEval_InitThreads")
                mainState = self.remoteUsercall("PyEval_SaveThread")
                gilState = self.remoteUsercall("PyGILState_Ensure")

                # create a new python thread #
                string = (
                    "import sys, time, threading\n"
                    "def func():\n"
                    "\twhile 1:\n"
                    "\t\ttime.sleep(1)\n"
                    "tobj = threading.Thread(target=func)\n"
                    "tobj.daemon = True\n"
                    "tobj.start();"
                )
                self.remotePyCall(string=string, wait=True)

                # release thread objects #
                if self.pid == origPid:
                    self.remoteUsercall("PyGILState_Release", [gilState])
                    self.remoteUsercall("PyEval_RestoreThread", [mainState])
                    self.finishPyLib()
                else:
                    _addPrint("\n[%s] %s(%s)" % (cmdstr, self.comm, self.pid))

            elif cmd == "add":
                if len(cmdset) == 1:
                    _printCmdErr(cmdval, cmd)

                # get argument info #
                memset = cmdset[1].split(";")

                _addPrint("\n[%s] %s\n" % (cmdstr, cmdset[1]))
                _flushPrint(newline=False)

                # inject specific brea points #
                self.loadSymbols()
                self.injectBpList(memset)

            elif cmd == "remove":
                if len(cmdset) == 1:
                    _printCmdErr(cmdval, cmd)

                # get argument info #
                memset = cmdset[1].split(";")

                _addPrint("\n[%s] %s\n" % (cmdstr, cmdset[1]))
                _flushPrint(newline=False)

                self.removeAllBp(target=memset)

            elif cmd in ("pystr", "pyfile"):
                if len(cmdset) == 1:
                    _printCmdErr(cmdval, cmd)

                # get argument info #
                memset = cmdset[1].split(":")
                source = memset[0]
                if len(memset) > 1:
                    sync = memset[1]
                    if not sync:
                        sync = True
                    elif sync.upper() == "FALSE":
                        sync = False
                    else:
                        sync = True
                else:
                    sync = True

                # remove all breakpoints #
                self.removeAllBp(verb=False)

                ret = self.loadPyLib()
                if not ret:
                    return

                self.initPyLib()

                _addPrint("\n[%s] %s [sync=%s]" % (cmdstr, source, sync))

                # call python #
                if cmd == "pystr":
                    self.remotePyCall(string=source, wait=sync)
                elif cmd == "pyfile":
                    self.remotePyCall(script=source, wait=sync)

                self.finishPyLib()

                # inject all breakpoints again #
                self.loadSymbols()
                self.updateBpList(verb=False)

            elif cmd == "dump":
                if len(cmdset) == 1:
                    _printCmdErr(cmdval, cmd)

                # get argument info #
                memset = cmdset[1].split(":")
                if len(memset) != 2:
                    _printCmdErr(cmdval, cmd)

                # dump memory #
                meminfo, output = memset
                size = self.dumpMemory(meminfo, output, verb=False)
                if size == 0:
                    res = "fail"
                else:
                    res = "success"

                sizestr = UtilMgr.convSize2Unit(size)

                _addPrint(
                    "\n[%s] %s(%s)->%s (%s)"
                    % (cmdstr, meminfo, sizestr, output, res)
                )

            elif cmd == "save":
                if len(cmdset) == 1:
                    _printCmdErr(cmdval, cmd)

                cmdlist = cmdset[1].split(":")
                var = cmdlist[0]

                if len(cmdlist) == 1:
                    data = self.prevReturn
                else:
                    data = cmdlist[1]
                    if not data:
                        data = self.prevReturn

                    # convert type #
                    if len(cmdlist) == 3:
                        dtype = cmdlist[2]
                        if dtype == "arg":
                            data = args[long(data)]
                        elif dtype == "float" or dtype == "double":
                            data = float(data)
                        elif dtype == "string":
                            data = str(data)

                self.retList[var] = data

                # convert to hex format #
                try:
                    hexData = "(%s)" % hex(long(data)).rstrip("L")
                except SystemExit:
                    sys.exit(0)
                except:
                    hexData = ""

                # convert data format #
                try:
                    data = repr(data)
                except:
                    pass

                output = "\n[%s] %s = %s%s" % (cmdstr, var, data, hexData)
                _addPrint(output)

            elif cmd == "load":
                if len(cmdset) == 1:
                    _printCmdErr(cmdval, cmd)

                # remove all breakpoints #
                self.removeAllBp(verb=False)

                # convert args for previous return #
                cmdset = self.convRetArgs(cmdset)

                # get function info #
                binary = cmdset[1]
                ret = _execFunc(self.dlopen, binary)
                if ret is None:
                    ret = "FAIL"
                else:
                    # update return #
                    self.prevReturn = str(ret)
                    ret = hex(ret).rstrip("L")

                output = "\n[%s] %s [%s]" % (cmdstr, binary, ret)
                _addPrint(output)
                _flushPrint(newline=False)

                # inject all breakpoints again #
                self.loadSymbols()
                self.updateBpList(verb=False)

            elif cmd == "syscall":
                if len(cmdset) == 1:
                    _printCmdErr(cmdval, cmd)

                # get function info #
                func = cmdset[1].split("#")
                val = func[0]
                if len(func) > 1:
                    argList = func[1:]

                    # convert args for previous return #
                    argList = self.convRetArgs(argList)

                    argStr = ", ".join(list(map(str, argList)))
                    argStr = "(%s)" % argStr
                else:
                    argList = []
                    argStr = "()"

                output = "\n[%s] %s%s" % (cmdstr, val, argStr)
                _addPrint(output)
                _flushPrint(newline=False)

                # remove a breakpoint for syscall #
                self.removeBp(self.getSyscallAddr(), lock=True)

                # call function #
                ret = _execFunc(self.remoteSyscall, val, argList)
                if ret is None:
                    ret = 0

                # update return #
                self.retList[val] = str(ret)
                self.prevReturn = str(ret)

                _addPrint(" = %s(%s)" % (hex(ret).rstrip("L"), ret))
                _flushPrint(newline=False)

                # inject a breakpoint for syscall again #
                self.injectBp(self.getSyscallAddr())

            elif cmd == "usercall":
                if len(cmdset) == 1:
                    _printCmdErr(cmdval, cmd)

                # get function info #
                func = cmdset[1].split("#")
                val = func[0]
                if len(func) > 1:
                    argList = func[1:]

                    # convert args for previous return #
                    argList = self.convRetArgs(argList)

                    argStr = ", ".join(list(map(str, argList)))
                    argStr = "(%s)" % argStr
                else:
                    argList = []
                    argStr = "()"

                # get address #
                addr = UtilMgr.convStr2Num(val, verb=False)
                if addr is None:
                    ret = self.getAddrBySymbol(val, one=True)
                    if not ret:
                        SysMgr.printErr("no found %s" % val)
                        return repeat
                    addr = ret

                output = "\n[%s] %s[0x%x]%s" % (cmdstr, val, addr, argStr)

                if sym == val or self.pc == addr:
                    skip = True
                    output = "%s (SKIP)" % output
                else:
                    skip = False

                # remove all breakpoints #
                if not skip:
                    self.removeAllBp(verb=False)

                _addPrint(output)
                _flushPrint(newline=False)

                if not skip:
                    # call function #
                    ret = _execFunc(self.remoteUsercall, addr, argList)
                    if ret is None:
                        ret = 0

                    # update return #
                    self.retList[val] = str(ret)
                    self.prevReturn = str(ret)

                    _addPrint(" = %s(%s)" % (hex(ret).rstrip("L"), ret))
                    _flushPrint(newline=False)

                    # inject all breakpoints again #
                    self.updateBpList(verb=False)

            elif cmd == "jump":
                if len(cmdset) == 1:
                    _printCmdErr(cmdval, cmd)

                # get function info #
                func = cmdset[1].split("#")
                val = func[0]
                if len(func) > 1:
                    argList = func[1:]

                    # convert args for previous return #
                    argList = self.convRetArgs(argList)

                    argStr = ", ".join(list(map(str, argList)))
                    argStr = "(%s)" % argStr
                else:
                    argList = []
                    argStr = "()"

                # convert arguments #
                argList, freelist = self.convRemoteArgs(argList)
                argList = list(map(long, argList))

                # get address #
                addr = UtilMgr.convStr2Num(val, verb=False)
                if addr is None:
                    ret = self.getAddrBySymbol(val, one=True)
                    if not ret:
                        SysMgr.printErr("no found %s" % val)
                        return repeat
                    addr = ret

                ret = self.getSymbolInfo(self.pc)
                if ret:
                    symbol = ret[0]
                else:
                    symbol = "??"

                output = "\n[%s] %s[0x%x] -> %s[0x%x]%s" % (
                    cmdstr,
                    symbol,
                    self.pc,
                    val,
                    addr,
                    args,
                )

                if sym == val or self.pc == addr:
                    skip = True
                    output = "%s (SKIP)" % output
                else:
                    skip = False

                _addPrint(output)

                # set register values #
                if not skip:
                    self.setPC(addr)
                    self.writeArgs(argList)
                    self.setRegs()
                    self.updateRegs()

            elif cmd == "sleep":
                if len(cmdset) == 1:
                    val = 1
                else:
                    val = float(cmdset[1])

                _addPrint(
                    "\n[%s] %s sec" % (cmdstr, UtilMgr.convFloat2Str(val))
                )
                _flushPrint(newline=False)

                time.sleep(val)

                # add elapsed time #
                self.dvalue += val

            elif cmd == "setenv":
                if len(cmdset) == 1:
                    _printCmdErr(cmdval, cmd)

                # get env info #
                envs = cmdset[1].split("#")
                if len(envs) != 2:
                    _printCmdErr(cmdval, cmd)
                else:
                    val = envs[0]
                    argList = envs

                # convert args for previous return #
                argList = self.convRetArgs(argList)
                argStr = " = ".join(list(map(str, argList)))

                output = "\n[%s] %s" % (cmdstr, argStr)

                # remove all breakpoints #
                self.removeAllBp(verb=False)

                _addPrint(output)
                _flushPrint(newline=False)

                # call function #
                ret = self.setenv(argList[0], argList[1])
                if ret == 0:
                    res = "success"
                else:
                    res = "fail"

                # update return #
                self.retList[val] = str(ret)
                self.prevReturn = str(ret)

                _addPrint(" (%s)" % res)
                _flushPrint(newline=False)

                # inject all breakpoints again #
                self.updateBpList(verb=False)

            elif cmd == "getenv":
                if len(cmdset) == 1:
                    _printCmdErr(cmdval, cmd)

                # get env #
                val = cmdset[1]
                argList = [val]

                # convert args for previous return #
                argList = self.convRetArgs(argList)
                val = argList[0]

                output = "\n[%s] %s" % (cmdstr, val)

                # remove all breakpoints #
                self.removeAllBp(verb=False)

                _addPrint(output)
                _flushPrint(newline=False)

                # call function #
                ret = self.getenv(val)

                # update return #
                self.retList[val] = str(ret)
                self.prevReturn = str(ret)

                _addPrint(" = %s" % ret)
                _flushPrint(newline=False)

                # inject all breakpoints again #
                self.updateBpList(verb=False)

            elif cmd == "stop":
                if len(cmdset) > 1:
                    memset = cmdset[1].split(";")
                else:
                    memset = None

                _addPrint("\n[%s]\n" % (cmdstr))
                _flushPrint(newline=False)

                SysMgr.blockSignal(act="unblock")

                if memset:
                    SysMgr.sendSignalProcs(signal.SIGSTOP, memset)

                SysMgr.waitEvent(exit=True)

            elif cmd == "kill":
                _addPrint("\n[%s]\n" % (cmdstr))
                _flushPrint(newline=False)
                self.kill()
                sys.exit(0)

            elif cmd == "log":
                if len(cmdset) == 1:
                    _printCmdErr(cmdval, cmd)

                # get message #
                val = cmdset[1]

                _addPrint("\n[%s] %s" % (cmdstr, val))

            elif cmd == "condexit":
                if self.startProfTime:
                    diff = self.vdiff - self.startProfTime
                    diff = convColor("%.6f" % diff, "RED")
                    _addPrint("\n[%s] %s\n" % (cmdstr, diff))
                    sys.exit(0)

            elif cmd == "exit":
                _addPrint("\n[%s]\n" % (cmdstr))
                sys.exit(0)

            else:
                raise Exception("no command supported")

            return repeat

        # check command list #
        if type(cmdList) is not list:
            return cmdList

        newCmdList = []

        convNum = UtilMgr.convNum

        # disable stream #
        origin = SysMgr.streamEnable
        if origin and SysMgr.outPath:
            SysMgr.streamEnable = False

        for cmdval in cmdList:
            # parse cmd set #
            cmdset = cmdval.split(":", 1)
            cmd = cmdset[0]

            # execute a command #
            try:
                repeat = _handleCmd(cmdset, cmd)
            except UserWarning:
                newCmdList.append(cmdval)
                break
            except SystemExit:
                _flushPrint()
                sys.exit(0)
            except Exception as ex:
                _flushPrint()
                SysMgr.printErr("failed to handle '%s' command" % cmd, True)
                sys.exit(-1)

            # re-register command #
            if repeat:
                newCmdList.append(cmdval)

        # recovery stream #
        SysMgr.streamEnable = origin

        _flushPrint(False)

        return newCmdList

    def setTraceme(self):
        # WARN: This requires CAP_SYS_PTRACE with PTRACE_TRACEME #
        cmd = ConfigMgr.PTRACE_TYPE.index("PTRACE_TRACEME")
        ret = self.ptrace(cmd)
        if ret != 0:
            if not self.comm:
                self.comm = SysMgr.getComm(self.pid, cache=True, save=True)
            SysMgr.printWarn(
                "failed to apply PTRACE_TRACEME for %s(%s) because %s"
                % (self.comm, self.pid, self.errmsg),
                True,
            )
        return ret

    def execute(self, execCmd, mute=True):
        # check mute flag #
        if Debugger.envFlags["NOMUTE"]:
            mute = False

        # create a new process #
        pid = SysMgr.createProcess()
        if pid == 0:
            # update pid #
            self.pid = os.getpid()

            # set tracee flag #
            self.setTraceme()

            # execute #
            # WARN: This requires CAP_SYS_PTRACE with PTRACE_TRACEME #
            SysMgr.executeProcess(cmd=execCmd, mute=mute)

            # execute fail #
            os._exit(0)
        else:
            self.pid = pid

    def removeBpFileByAddr(self, addr):
        fname = self.getFileFromMap(addr)
        if not fname:
            return

        fcache = ElfAnalyzer.getObject(fname)
        if not fcache:
            return

        for item in fcache.sortedAddrTable:
            self.removeBp(addr + item, lock=True)

    def removeAllBp(self, tgid=None, verb=True, target=[]):
        if not self.bpList:
            return
        # check fault flag from shared memory #
        elif self.getFaultFlag():
            return

        # get tgid #
        if not tgid:
            tgid = self.pid

        if verb:
            SysMgr.printStat(
                r"start removing %s breakpoints from %s(%s) process..."
                % (
                    UtilMgr.convNum(len(self.bpList)),
                    SysMgr.getComm(tgid, cache=True),
                    tgid,
                )
            )

        # remove all breakpoints #
        for idx, addr in enumerate(list(self.bpList)):
            if verb:
                UtilMgr.printProgress(idx, len(self.bpList))

            # check target filter #
            if target and self.bpList[addr]["symbol"]:
                skip = False
                sym = self.bpList[addr]["symbol"]

                for item in target:
                    if item.startswith("^"):
                        if UtilMgr.isValidStr(sym, [item[1:]]):
                            skip = True
                            break
                    else:
                        if not UtilMgr.isValidStr(sym, [item]):
                            skip = True
                            break

                if skip:
                    continue

            self.removeBp(addr)

        if verb:
            UtilMgr.deleteProgress()

    def removeBp(self, addr, lock=False):
        if addr in self.bpList:
            savedData = self.bpList[addr]["data"]
        else:
            SysMgr.printWarn(
                "no breakpoint with addr %s" % hex(addr).rstrip("L")
            )
            return None

        # lock between processes #
        if lock and addr in self.bpList:
            nrLock = self.bpList[addr]["number"]
            self.lock(nrLock)
        else:
            lock = False

        # write original data #
        if savedData and not savedData.startswith(self.brkInst):
            self.writeMem(addr, savedData, skipCheck=True)

        if lock:
            self.unlock(nrLock)

        # change breakpoint status #
        self.bpList[addr]["set"] = False

        data = self.bpList[addr]
        symbol = data["symbol"]
        filename = data["filename"]
        reins = data["reins"]

        if Debugger.envFlags["TRACEBP"]:
            SysMgr.printWarn(
                "removed the breakpoint %s(%s) by %s(%s)"
                % (hex(addr).rstrip("L"), symbol, self.comm, self.pid),
                True,
            )

        return (symbol, filename, reins)

    def convFilterValue(self, origCmdSet):
        cmdSet = []
        for cmd in origCmdSet:
            cmds = cmd.split(":")
            if cmds[0] != "filter" or len(cmds) < 4 or cmds[1].startswith("*"):
                cmdSet.append(cmd)
                continue

            val = cmds[3]
            if val.isdigit():
                val = long(val)
            else:
                try:
                    val = long(val, 16)
                except SystemExit:
                    sys.exit(0)
                except:
                    try:
                        val = float(val)
                    except SystemExit:
                        sys.exit(0)
                    except:
                        SysMgr.printErr(
                            "failed to recognize '%s' as a number" % val, True
                        )
                        sys.exit(-1)

            cmds[3] = str(val)
            newCmds = ":".join(cmds)
            cmdSet.append(newCmds)

        return cmdSet

    def injectDefaultBp(self):
        # add default breakpoints such as mmap #
        for lib in list(self.dftBpFileList):
            # add all symbols of loader #
            if (
                not self.isRunning
                and not self.ldInjected
                and os.path.basename(lib).startswith("ld-")
            ):
                ret = self.getAddrBySymbol("", binary=[lib], inc=True)

                for item in ret:
                    ldaddr, ldsym, ldlib = item
                    ret = self.injectBp(ldaddr, ldsym, fname=ldlib, reins=True)
                    if ret:
                        # register exceptional address #
                        self.exceptBpList[ldaddr] = 0

                self.ldInjected = True
                continue

            # add specific default symbols #
            for dsym in list(self.dftBpSymList):
                ret = self.getAddrBySymbol(dsym, binary=[lib])
                if not ret:
                    continue

                addr = ret[0][0]
                ret = self.injectBp(addr, dsym, fname=lib, reins=True)
                if ret:
                    # register exceptional address #
                    self.exceptBpList[addr] = 0

    def getBpList(self, symlist, binlist=None, verb=True):
        if not symlist:
            symlist.append("**")
        else:
            oldlist = list(symlist)
            symlist = []
            for sym in oldlist:
                if sym.startswith("|"):
                    symlist.append("**%s" % sym)
                else:
                    symlist.append(sym)

        cmdList = []
        newlist = []
        addrList = []

        # check start command #
        if self.startProfTime:
            for value in symlist:
                valueList = value.split("|")
                if len(valueList) > 1 and valueList[1].startswith("start"):
                    pass
                else:
                    newlist.append(value)
        else:
            for value in symlist:
                valueList = value.split("|")
                if len(valueList) > 1 and valueList[1].startswith("start"):
                    newlist.append(value)

        # update symbol list #
        if newlist:
            symlist = newlist

        # add breakpoints requested by user #
        for value in symlist:
            # parse symbol and commands #
            valueList = value.split("|")
            value = valueList[0]
            if len(valueList) > 1:
                # convert value to decimal #
                cmdSet = self.convFilterValue(valueList[1:])
            else:
                cmdSet = None

            # address #
            if UtilMgr.isNumber(value):
                try:
                    addr = long(value, 16)
                except:
                    addr = long(value)
                ret = self.getSymbolInfo(addr)
                addrList.append([addr, ret[0], ret[1]])
                cmdList.append(cmdSet)
                continue

            # symbol #
            symbol, inc, start, end = ElfAnalyzer.getFilterFlags(value)
            ret = self.getAddrBySymbol(
                symbol, binary=binlist, inc=inc, start=start, end=end
            )
            if ret:
                addrList += ret
                for _ in xrange(len(ret)):
                    cmdList.append(cmdSet)
                continue

            # execution mode #
            if self.execCmd or value == "" or value in self.dftBpSymList:
                continue

            # no binary on map #
            if binlist:
                if not (set(binlist) & set(self.pmap)):
                    SysMgr.printErr(
                        "failed to find '%s' on memory map for %s(%s)"
                        % (", ".join(binlist), self.comm, self.pid)
                    )

                    PageAnalyzer.printMemoryArea(
                        self.pid, comm=self.comm, lastLine=True
                    )

                    sys.exit(-1)

            # no symbol #
            SysMgr.printErr("failed to find address for symbol '%s'" % value)
            sys.exit(-1)

        return addrList, cmdList

    def injectBpList(self, symList, binList=None, verb=True):
        exceptList = []
        if symList:
            newList = []
            for symbol in symList:
                if not symbol.startswith("^"):
                    newList.append(symbol)
                    continue
                exceptList.append(symbol[1:])
            symList = newList

        # get address list for breakpoints #
        addrList, cmdList = self.getBpList(symList, binList, verb)
        if not addrList:
            self.injectDefaultBp()
            return

        # get exceptional address list for breakpoints #
        exceptAddrList = []
        if exceptList:
            exceptList = self.getBpList(exceptList, binList, verb)[0]
            for item in exceptList:
                exceptAddrList.append(item[0])

        # print target process name #
        if verb:
            tgid = SysMgr.getTgid(self.pid)
            SysMgr.printStat(
                r"start injecting %s breakpoints for %s(%s)..."
                % (
                    UtilMgr.convNum(len(addrList)),
                    SysMgr.getComm(tgid, cache=True),
                    tgid,
                )
            )

        # add new breakpoints #
        for idx, item in enumerate(addrList):
            UtilMgr.printProgress(idx, len(addrList))

            if type(item) is list:
                addr, symbol, fname = item
                if addr in exceptAddrList:
                    continue
            else:
                continue

            # inject a breakpoint #
            self.injectBp(
                addr, symbol, fname=fname, reins=True, cmd=cmdList[idx]
            )

            # remove the address from exception list #
            self.exceptBpList.pop(addr, None)

        UtilMgr.deleteProgress()

        # inject default breakpoints #
        self.injectDefaultBp()

        return True

    def checkFilterCond(self, filterCmd, args, sym=None, fname=None):
        def _printErr(cmd):
            SysMgr.printErr(
                "wrong command '%s', input in the format {%s:%s}"
                % (cmd, "filter|check", "ADDR|REG:OP:VAL:SIZE")
            )

        if not filterCmd:
            return True

        if type(filterCmd) is not list:
            filterCmd = [filterCmd]

        result = True
        for cmd in filterCmd:
            cmdset = cmd.split(":", 1)
            if len(cmdset) == 1:
                _printErr(cmd)
                result = False
                continue

            # get argument info #
            memset = cmdset[1].split(":")
            if len(memset) < 3:
                _printErr(cmd)
                result = False
                continue

            # handle return filter #
            if memset[0] == "RETTIME" or memset[0] == "RETVAL":
                if cmdset[0] != "filter":
                    SysMgr.printErr(
                        "wrong command '%s' with '%s'" % (cmdset[0], memset[0])
                    )
                    sys.exit(-1)

                # check multiple return filter #
                if sym in self.retFilterList:
                    SysMgr.printWarn(
                        "return filter is overwritten for %s" % sym
                    )

                # get return command #
                if len(memset) > 2:
                    retcmd = ":".join(memset[3:])
                else:
                    retcmd = None

                # set return filter #
                self.retFilterList[sym] = [memset, None, retcmd]
                ret = self.setRetBp(sym, fname, cmd)
                if not ret:
                    SysMgr.printErr(
                        (
                            "failed to set breakpoint to "
                            "return address for %s"
                        )
                        % sym
                    )

                # update filter result #
                if len(filterCmd) == 1:
                    result = False
                continue

            # convert args for previous return #
            memset = self.convRetArgs(memset)
            ref = False
            addr = memset[0]
            op = memset[1]
            val = memset[2]

            # convert 1st data #
            try:
                if addr[0] == "*":
                    ref = True
                    addr = long(addr[1:])
                elif addr.isdigit():
                    addr = long(addr)
                    if addr < len(args):
                        addr = args[addr]
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "failed to convert %s to number in filter" % addr
                )
                continue

            if len(memset) == 4:
                size = long(memset[3])
            else:
                size = None

            # convert 1st value to number #
            if UtilMgr.isNumber(addr):
                try:
                    addr = long(addr, 16)
                except SystemExit:
                    sys.exit(0)
                except:
                    addr = long(addr)

            # convert 2nd value to number #
            if UtilMgr.isNumber(val):
                try:
                    val = long(val, 16)
                except SystemExit:
                    sys.exit(0)
                except:
                    val = long(val)

            # get value from memory #
            if ref:
                ret = self.readMem(addr, size)
                if ret is None or ret == -1:
                    SysMgr.printErr("failed to read from %s" % addr)
                    result = False
                    continue

                ret = ret.decode()
            # get value from register #
            else:
                ret = addr

            # check value #
            # == #
            if op.upper() == "EQ":
                if ref:
                    if ret[:size] != val:
                        result = False
                        continue
                else:
                    val = str(val)[:size]
                    ret = str(ret)[:size]

                    if ret != val:
                        result = False
                        continue
            # != #
            elif op.upper() == "DF":
                if ref:
                    if ret[:size] == val:
                        result = False
                        continue
                else:
                    val = str(val)[:size]
                    ret = str(ret)[:size]

                    if ret == val:
                        result = False
                        continue

            # in #
            elif op.upper() == "INC":
                if ref:
                    if not val in ret[:size]:
                        result = False
                        continue

            # <= or >= #
            elif op.upper() == "BT" or op.upper() == "LT":
                if not UtilMgr.isNumber(val):
                    _printErr(cmd)
                    result = False
                    continue

                try:
                    val = long(val)
                except SystemExit:
                    sys.exit(0)
                except:
                    val = long(val, 16)

                if op.upper() == "BT" and ret <= val:
                    result = False
                    continue
                elif op.upper() == "LT" and ret >= val:
                    result = False
                    continue

            else:
                SysMgr.printErr(
                    "failed to recognize operator '%s' for filter" % op
                )
                result = False
                continue

        return result

    def loadInst(self, fname, offset):
        try:
            if fname == "vdso":
                fobj = SysMgr.getVDSO(elf=False)
            else:
                fobj = SysMgr.getFd(fname)

            if not fobj:
                raise Exception("N/A")

            fobj.seek(offset)

            return fobj.read(ConfigMgr.wordSize)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to read original data from %s" % fname, reason=True
            )
            sys.exit(-1)

    def injectBp(
        self,
        addr,
        sym=None,
        fname=None,
        size=1,
        reins=False,
        cmd=None,
        origWord=None,
    ):

        procInfo = "%s(%s)" % (self.comm, self.pid)

        # skip no symbol function #
        if sym and Debugger.envFlags["ONLYSYM"] and sym.startswith("0x"):
            SysMgr.printWarn(
                "skip injecting breakpoint for no symbol function %s" % sym
            )
            return False

        # get original instruction #
        if addr in self.bpList:
            if self.bpList[addr]["set"]:
                # update symbol for the breakpoint address #
                if sym:
                    self.bpList[addr]["symbol"] = sym

                # print fail message #
                if Debugger.envFlags["TRACEBP"]:
                    if not sym:
                        sym = self.bpList[addr]["symbol"]
                    SysMgr.printWarn(
                        (
                            "failed to inject a breakpoint to %s(%s) for %s "
                            "because it is already injected by this task"
                        )
                        % (hex(addr).rstrip("L"), sym, procInfo),
                        True,
                    )
                    return False

            # update flags #
            origWord = self.bpList[addr]["data"]
            if self.bpList[addr]["reins"] != reins:
                self.bpList[addr]["reins"] = reins
            self.bpList[addr]["set"] = True

            # update command #
            if cmd and not self.bpList[addr]["cmd"]:
                filterCmd = []
                newCmd = list(cmd)
                for item in list(newCmd):
                    if item.startswith("filter"):
                        filterCmd.append(item)
                        newCmd.remove(item)
                cmd = newCmd

                self.bpList[addr]["cmd"] = cmd
                self.bpList[addr]["filter"] = filterCmd

        # the new breakpoint #
        else:
            # read data #
            if origWord:
                pass
            elif addr % ConfigMgr.wordSize:
                origWord = self.readMem(addr)
            else:
                origWord = self.accessMem(self.peekIdx, addr)
                if origWord > 0:
                    origWord = UtilMgr.convWord2Str(origWord)
                else:
                    origWord = None

            # check data #
            if not origWord:
                return False
            elif origWord.startswith(self.brkInst):
                SysMgr.printWarn(
                    (
                        "failed to inject a breakpoint to %s(%s) for %s "
                        "because no original code"
                    )
                    % (hex(addr).rstrip("L"), sym, procInfo)
                )

                ret = self.getSymbolInfo(addr)
                fname = ret[1]
                try:
                    offset = long(ret[2], 16)
                except:
                    SysMgr.printErr(
                        (
                            "failed to inject a breakpoint to %s(%s) for %s"
                            % (hex(addr).rstrip("L"), sym, procInfo)
                        ),
                        reason=True,
                    )
                    return

                # load original data from storage #
                origWord = self.loadInst(fname, offset)

            # check filter command #
            filterCmd = []
            if cmd:
                newCmd = list(cmd)
                for item in list(newCmd):
                    if item.startswith("filter"):
                        filterCmd.append(item)
                        newCmd.remove(item)
                cmd = newCmd

            # register the breakpoint #
            self.bpList[addr] = {
                "data": origWord,
                "number": len(self.bpList),
                "symbol": sym,
                "reins": reins,
                "filename": fname,
                "cmd": cmd,
                "filter": filterCmd,
                "set": True,
            }

            # register the new breakpoint after fork #
            if self.forked:
                self.bpNewList[addr] = self.bpList[addr]

        # build trap instruction #
        if size == 1:
            inst = self.brkInst
        else:
            inst = self.brkInst * size

        # update symbol #
        if not sym:
            sym = self.bpList[addr]["symbol"]

        # check instructions whether it is already injected #
        if origWord.startswith(inst):
            if addr in self.bpList and self.bpList[addr]["data"] != inst:
                origWord = self.bpList[addr]["data"]
            else:
                SysMgr.printWarn(
                    (
                        "failed to inject a breakpoint to %s(%s) for %s "
                        "because it is already injected by another task"
                    )
                    % (hex(addr).rstrip("L"), sym, procInfo)
                )
                return False

        # inject trap code #
        # WARNING: this code may cause SIGTRAP fault for other tasks #
        ret = self.writeMem(addr, inst, skipCheck=True)
        if ret < 0:
            if not self.isAlive():
                reason = "because of target termination"
            else:
                reason = "because of remote write failure"

            SysMgr.printErr(
                "failed to inject a breakpoint to %s(%s) for %s %s"
                % (hex(addr).rstrip("L"), sym, procInfo, reason)
            )

            return False
        elif ret == 0 and Debugger.envFlags["TRACEBP"]:
            SysMgr.printWarn(
                "added the new breakpoint %s(%s)[%s] by %s"
                % (hex(addr).rstrip("L"), sym, fname, procInfo),
                True,
            )

        return True

    def attach(self, pid=None, verb=False, cont=False):
        if not pid:
            pid = self.pid

        if not self.comm:
            self.comm = SysMgr.getComm(self.pid, cache=True, save=True)

        if self.checkPid(pid) < 0:
            SysMgr.printWarn(
                (
                    "failed to attach %s(%s) to guider(%s) "
                    "because of wrong pid"
                )
                % (self.comm, pid, SysMgr.pid),
                verb,
            )
            return -1

        # attach to the thread #
        plist = ConfigMgr.PTRACE_TYPE
        cmd = plist.index("PTRACE_ATTACH")
        doExit = False

        while 1:
            ret = self.ptrace(cmd)
            if ret != 0:
                tracer = SysMgr.getTracerId(pid)
                if tracer > 0:
                    reason = " because it is being traced by %s(%s)" % (
                        SysMgr.getComm(tracer),
                        tracer,
                    )
                elif not SysMgr.isRoot():
                    reason = " because of no root permission"
                    doExit = True
                else:
                    reason = " because %s" % self.errmsg

                    # check exit condition #
                    if not self.isAlive():
                        doExit = True

                # print error message #
                warnMsg = "failed to attach %s(%s) to guider(%s)%s" % (
                    self.comm,
                    pid,
                    SysMgr.pid,
                    reason,
                )

                # print solution for docker #
                if tracer == 0:
                    warnMsg += (
                        "\n\tif you use docker then attach "
                        "'--cap-add=SYS_PTRACE --security-opt "
                        "seccomp=unconfined' option to the run command"
                    )

                SysMgr.printWarn(warnMsg, verb)

                # check return #
                if doExit:
                    sys.exit(-1)
                elif not cont:
                    return -1
                elif self.isAlive():
                    time.sleep(SysMgr.waitDelay)
                    continue
                else:
                    sys.exit(-1)
            else:
                self.attached = True

                SysMgr.printWarn(
                    "attached %s(%s) to guider(%s)"
                    % (self.comm, pid, SysMgr.pid)
                )

                return 0

    def stop(self, pid=None, thread=True, check=False):
        if not pid:
            pid = self.pid

        try:
            # thread #
            if thread:
                ret = SysMgr.syscall(self.tkillIdx, pid, signal.SIGSTOP)
                if not check:
                    return ret

                # wait for stop status #
                if not self.isStopped():
                    SysMgr.waitChild(self.pid)

                return ret
            # process #
            else:
                os.kill(pid, signal.SIGSTOP)

                return 0
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printSigError(pid, "SIGSTOP")
            return -1

    def free(self, addr):
        # get function address #
        symbol = "free"
        func = self.getAddrBySymbol(symbol, one=True)
        if not func:
            return None

        # set args #
        args = [addr]

        # call free $
        ret = self.remoteUsercall(func, args)
        if ret < 0:
            SysMgr.printErr(
                "failed to free %s memory for %s(%s)"
                % (hex(addr), self.comm, self.pid)
            )
            return None

        return ret

    def convRemoteArgs(self, args):
        freelist = []
        for idx, item in enumerate(deepcopy(args)):
            if type(item) is not str:
                continue
            elif not item.isdigit() or (
                item.startswith('"') and item.endswith('"')
            ):
                try:
                    args[idx] = long(item, 16)
                except SystemExit:
                    sys.exit(0)
                except:
                    addr = self.calloc(string=item, temp=False)
                    if not addr:
                        sys.exit(-1)

                    args[idx] = long(addr)
                    freelist.append(addr)
            else:
                args[idx] = long(item)

        return args, freelist

    def calloc(self, size=None, string=None, temp=False):
        # get function address #
        symbol = "calloc"
        func = self.getAddrBySymbol(symbol, one=True)
        if not func:
            return None

        # check size #
        if not size:
            if string:
                string = string.strip('"')
                string = string.replace("\\n", "\n")
                size = len(string) + 1
            else:
                SysMgr.printErr(
                    "failed to alloc memory for %s(%s) because no size"
                    % (self.comm, self.pid)
                )
                return None

        # use a temporary page #
        if temp:
            addr = self.getTempPage()
        else:
            addr = None

        # use a new memory segment #
        if not addr:
            # set args #
            args = [1, size]

            # call calloc $
            addr = self.remoteUsercall(func, args)
            if addr < 0:
                SysMgr.printErr(
                    "failed to alloc %s size of memory for %s(%s)"
                    % (UtilMgr.convNum(size), self.comm, self.pid)
                )
                return None

        # copy string to memory #
        if addr and string:
            ret = self.writeMem(addr, string.encode(), skipCheck=True)
            if ret == -1:
                SysMgr.printErr(
                    "failed to write '%s' to %s" % (string, hex(addr))
                )
                return None

        return addr

    def getTempPage(self):
        if not self.tempPage:
            self.tempPage = self.mmap()
            if self.tempPage < 0:
                self.tempPage = None

        return self.tempPage

    def dlclose(self, addr):
        # get function address #
        func = "__libc_dlclose"

        # set args #
        args = [addr]

        # call dlclose #
        ret = self.remoteUsercall(func, args)

        return ret

    def getMapFilePathFast(self, fname):
        self.loadSymbols()
        if not self.pmap:
            return None

        for path in list(self.pmap):
            if os.path.basename(path).startswith(fname):
                return path

        return None

    def isPyLoaded(self):
        if self.pyLibPath:
            return True

        # check python program #
        try:
            exePath = SysMgr.getExeName(self.pid)
            exeName = os.path.basename(exePath)
            if exeName.startswith("python"):
                self.pyLibPath = exePath
                return True
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # check memory map #
        self.pyLibPath = self.getMapFilePathFast("libpython")
        if self.pyLibPath:
            return True
        else:
            return False

    def remotePyCall(self, string=None, script=None, wait=True):
        if string:
            """
            # set args #
            self.remoteUsercall(
                "PySys_SetArgvEx", [len(sys.argv), sys.argv, 0], wait=wait)

            # check import #
            pname = self.remoteUsercall(
                "PyUnicode_FromString", [string], wait=wait)
            pmodule = self.remoteUsercall(
                "PyImport_Import", [pname], wait=wait)

            # append system path #
            paths = SysMgr.getPyConfig('path')
            paths = list(map(lambda x: "'%s'" % x, list(paths.values())))
            pystr = "import sys; sys.path.append([%s]);" % ','.join(paths)
            string = pystr + string
            if not string.endswith(';'):
                string += ';'
            """

            # execute source #
            return self.remoteUsercall(
                "PyRun_SimpleString", [string], wait=wait
            )

        if script:
            path = os.path.expanduser(script)

            # convert path #
            if not path.startswith("/"):
                current = os.path.realpath(".")
                path = "%s/%s" % (current, path)

            # check file #
            if not os.path.exists(path):
                SysMgr.printErr("failed to access %s" % path)
                return None

            if sys.version_info >= (3, 0):
                # open script #
                fp = self.remoteUsercall("_Py_fopen", [path, "r"])
                if not fp:
                    SysMgr.printErr("failed to call _Py_fopen")
                    return

                # execute file #
                return self.remoteUsercall(
                    "PyRun_SimpleFile", [fp, path], wait=wait
                )
            else:
                # open file #
                po = self.remoteUsercall("PyFile_FromString", [path, "r"])
                if not po:
                    SysMgr.printErr("failed to call PyFile_FromString")
                    return
                fp = self.remoteUsercall("PyFile_AsFile", [po])
                if not fp:
                    SysMgr.printErr("failed to call PyFile_AsFile")
                    return

                # execute file #
                return self.remoteUsercall(
                    "PyRun_SimpleFileEx", [fp, path, 1], wait=wait
                )

    def initPyLib(self):
        if self.pyInit:
            return

        # initialization #
        self.remoteUsercall("Py_Initialize")

        # set argv #
        self.remoteUsercall("PySys_SetArgv", [0, 0])

        self.pyInit = True

    def finishPyLib(self):
        self.remoteUsercall("Py_Finalize")

    def loadPyLib(self):
        if self.isPyLoaded():
            return True

        # set environment #
        if "PYTHONHOME" in os.environ:
            self.setenv("PYTHONHOME", os.environ["PYTHONHOME"], False)

        # get libpython path #
        if "LIBPYTHON" in SysMgr.environList:
            pylib = SysMgr.environList["LIBPYTHON"]
        elif SysMgr.getPyLibPath():
            pylib = SysMgr.pyLibPath
        else:
            libName = SysMgr.getPyLibPath(load=False)
            platDir = SysMgr.getPyConfig(None, "LIBPL")
            pylib = "%s/%s.so" % (platDir, libName)
            if not os.path.exists(pylib):
                SysMgr.printErr("failed to get path for python library")
                return False

        if type(pylib) is not list:
            pylib = [pylib]

        # load the library #
        for lib in pylib:
            ret = self.dlopen(lib)
            if self.isPyLoaded():
                return True

        SysMgr.printErr(
            "failed to load %s for %s(%s)"
            % (",".join(pylib), self.comm, self.pid)
        )
        return False

    def dlopen(self, fname, flags=None):
        # check fname #
        if not os.path.exists(fname):
            SysMgr.printErr(
                "failed to find %s for %s(%s)" % (fname, self.comm, self.pid)
            )
            return None

        # handle android #
        if SysMgr.isAndroid:
            libcPath = FileAnalyzer.getMapFilePath(
                self.pid, SysMgr.libcObj._name, self.mapFd
            )

            # get ELF object #
            fcache = ElfAnalyzer.getObject(libcPath)
            if not hasattr(fcache, "attr"):
                SysMgr.printErr(
                    "failed to find attr from the cache for %s" % libcPath
                )
                return None

            # get mapping info #
            func = 0
            targetSym = "dlopen"
            if not self.pmap or not libcPath in self.pmap:
                self.loadSymbols()
            vstart = self.pmap[libcPath]["vstart"]

            # get mapping info #
            for sym, attr in sorted(
                fcache.attr["dynsymTable"].items(),
                key=lambda x: x[1]["size"],
                reverse=False,
            ):
                if attr["size"] > 0:
                    break
                elif sym != targetSym and sym.split("@")[0] != targetSym:
                    continue

                # read original address for target #
                slotAddr = vstart + attr["value"]
                if slotAddr % ConfigMgr.wordSize == 0:
                    func = self.accessMem(self.peekIdx, slotAddr)
                else:
                    func = self.readMem(slotAddr, retWord=True)
        else:
            # get function address #
            func = "__libc_dlopen_mode"

            """
            # alloc a memory segment for file name string #
            addr = self.getTempPage()
            if not addr:
                SysMgr.printErr("failed to allocate a new page")
                return None

            # copy file name string to the new page #
            fname += '\0'
            ret = self.writeMem(addr, fname.encode())
            if ret == -1:
                SysMgr.printErr(
                    "failed to write '%s' to %s" % (fname, hex(addr)))
                return None
            """

        # RTLD_LAZY | RTLD_GLOBAL #
        if not flags:
            flags = 0x00001 | 0x00100

        # set args #
        args = [fname, flags]

        # call dlopen #
        ret = self.remoteUsercall(func, args, inc=True)
        if ret:
            self.loadSymbols()

        return ret

    def getSyscallAddr(self):
        if not self.syscallAddr:
            self.syscallAddr = self.getAddrBySymbol("syscall", one=True)
            if not self.syscallAddr:
                self.syscallFound = False

        return self.syscallAddr

    def remoteUsercall(self, usercall, args=[], wait=True, inc=False):
        # convert arguments in advance to prevent nested remote calls #
        args, freelist = self.convRemoteArgs(args)

        # get target info #
        procInfo = "%s(%s)" % (self.comm, self.pid)

        # get original regset #
        if not self.updateRegs():
            return None

        # get backup regset #
        self.backupRegs()
        origPc = self.pc

        """
        # change access permission on a page pointed by PC #
        ret = self.mprotect(self.pc)
        if ret == -1:
            return None
        """

        # set usercall address #
        if isinstance(usercall, (int, long)):
            func = usercall
        elif type(usercall) is str:
            # get function address #
            func = self.getAddrBySymbol(usercall, inc=inc, one=True)
            if not func:
                return None
        else:
            SysMgr.printErr(
                "failed to recognize '%s' as a function for %s"
                % (usercall, procInfo),
                True,
            )
            return None
        setattr(self.regs, self.retreg, func)

        # set args #
        self.writeArgs(args)

        # set trap for return #
        if self.arch == "arm" or self.arch == "aarch64":
            self.setLR(0)

            # set CPSR for ARM #
            if func & 0x1:
                func &= ~1
                if self.arch == "arm":
                    self.regs.r16 |= 1 << 5  # pylint: disable=no-member
                else:
                    self.regs.x16 |= 1 << 5  # pylint: disable=no-member
            else:
                if self.arch == "arm":
                    self.regs.r16 &= ~(1 << 5)  # pylint: disable=no-member
                else:
                    self.regs.x16 &= ~(1 << 5)  # pylint: disable=no-member
        elif self.arch == "x64":
            # align sp - wordSize to a multiple of 16
            wordSize = ConfigMgr.wordSize
            newSP = self.sp
            while 1:
                if (newSP - wordSize * 2) & 0xF == 0:
                    break
                newSP -= wordSize
            newSP -= wordSize
            self.setSP(newSP)
            ret = self.writeMem(newSP, b"\x00" * wordSize)
        elif self.arch == "x86":
            # TODO: save all args to stack and install the trap finally #
            SysMgr.printErr(
                "failed to set trap for return because %s is not supported"
                % self.arch
            )
            sys.exit(-1)

        # update PC to target function addr #
        self.setPC(func)

        # apply register set #
        self.setRegs()

        # call function #
        self.cont(check=True)
        if not wait:
            return None

        while 1:
            # wait process #
            rid, ostat = self.waitpid()

            # handle clone event #
            if SysMgr.cloneEnable and self.isCloned(ostat):
                pid = self.handoverNewTarget()
                if pid == 0:
                    return None
                continue

            break

        # read regs to check results #
        if not self.updateRegs():
            return None

        # get return #
        retVal = self.getRet()

        # restore regs #
        self.setRegs(temp=True)
        self.restoreRegs()

        # free memory for string #
        for addr in freelist:
            self.free(addr)

        return retVal

    def remoteSyscall(self, syscall, args=[], verb=True):
        # check syscall function #
        if not self.syscallFound:
            return -1

        # get original regset #
        if not self.updateRegs():
            return -1

        # get backup regset #
        self.backupRegs()

        # set syscall number #
        if isinstance(syscall, (int, long)):
            sysid = syscall
        elif type(syscall) is str:
            syscall = syscall.lower()
            if not syscall.startswith("sys_"):
                syscall = "sys_%s" % syscall

            if syscall == "sys_mmap":
                sysid = ConfigMgr.getMmapId()
            else:
                try:
                    sysid = SysMgr.getNrSyscall(syscall)
                except:
                    SysMgr.printErr("failed to find %s" % syscall, True)
                    return -1
        else:
            SysMgr.printErr("failed to recognize syscall %s" % syscall, True)
            return -1
        setattr(self.regs, self.retreg, sysid)

        # convert arguments #
        args, freelist = self.convRemoteArgs(args)

        # set args #
        self.writeArgs([sysid] + args)

        # set PC to syscall function addr #
        addr = self.getSyscallAddr()
        if not addr:
            if verb:
                SysMgr.printErr(
                    "failed to find the address for syscall function"
                )
            return -1
        else:
            self.setPC(addr)

        # apply register set #
        self.setRegs()

        # execute syscall #
        self.ptrace(self.syscallCmd)
        self.waitpid()

        # read regs and change the 6th argument #
        if not self.updateRegs():
            return -1
        self.writeArgs(args)
        self.setRegs()

        # continue and stop at return #
        self.ptrace(self.syscallCmd)
        self.waitpid()

        # read regs to check results #
        if not self.updateRegs():
            return -1
        ret = self.getRet()

        # restore regs #
        self.setRegs(temp=True)
        self.restoreRegs()

        # free memory for string #
        for addr in freelist:
            self.free(addr)

        return ret

    def getenv(self, name):
        ret = self.remoteUsercall("getenv", [name])
        if ret:
            return self.readString(ret)

    def setenv(self, name, value, overwrite=True):
        if overwrite:
            overwrite = 1
        else:
            overwrite = 0

        ret = self.remoteUsercall("setenv", [name, value, overwrite])
        if ret == -1:
            procInfo = "%s(%s)" % (self.comm, self.pid)
            SysMgr.printErr(
                "failed to set %s(%s) environment variable for %s"
                % (name, value, procInfo)
            )
        return ret

    def mmap(self, size=4096, perm="rwx"):
        # set prot #
        prot = 0
        perm = perm.lower()
        if "r" in perm:
            prot |= 0x1
        if "w" in perm:
            prot |= 0x2
        if "x" in perm:
            prot |= 0x4

        # set flags #
        flags = 0x22

        return self.remoteSyscall(
            "mmap", [0, size, prot, flags, 0, 0], verb=False
        )

    def mprotect(self, maddr, size=0, perm="rwx"):
        # check size #
        if not size:
            size = SysMgr.PAGESIZE

        # align address #
        offset = maddr % SysMgr.PAGESIZE
        if offset > 0:
            maddr -= offset

        # set prot #
        prot = 0
        perm = perm.lower()
        if "r" in perm:
            prot |= 0x1
        if "w" in perm:
            prot |= 0x2
        if "x" in perm:
            prot |= 0x4

        ret = self.remoteUsercall("mprotect", [maddr, size, prot])
        if ret != 0:
            procInfo = "%s(%s)" % (self.comm, self.pid)
            SysMgr.printWarn(
                "failed to change access permission to %s page for %s"
                % (hex(maddr), procInfo)
            )
        return ret

    def kill(self):
        plist = ConfigMgr.PTRACE_TYPE
        cmd = plist.index("PTRACE_KILL")
        ret = self.ptrace(cmd)
        if ret != 0:
            SysMgr.printWarn(
                "failed to kill %s(%s) because %s"
                % (self.comm, self.pid, self.errmsg)
            )
            return -1
        else:
            SysMgr.printWarn("killed %s(%s)" % (self.comm, self.pid))
            return 0

    def cont(self, pid=None, check=False, sig=0):
        if not pid:
            pid = self.pid

        # check target is running #
        try:
            os.kill(pid, 0)
        except SystemExit:
            sys.exit(0)
        except:
            if not self.isAlive():
                errMsg = (
                    "failed to continue %s(%s) because it is terminated"
                    % (self.comm, pid)
                )
                SysMgr.printWarn(errMsg)
                return -1

        # check target status #
        if check:
            cnt = 1000
            while 1:
                ret = self.ptrace(self.contCmd, 0, sig)
                if ret == 0:
                    return 0

                cnt -= 1
                if cnt < 0:
                    break
                elif not self.isAlive():
                    SysMgr.printWarn(
                        (
                            "failed to continue %s(%s) "
                            "because it is terminated"
                        )
                        % (self.comm, pid)
                    )
                    return -1

                time.sleep(0.001)

        # continue target thread #
        ret = self.ptrace(self.contCmd, 0, sig)
        if ret != 0:
            SysMgr.printWarn(
                "failed to continue %s(%s) because %s"
                % (self.comm, pid, self.errmsg)
            )
            return -1

        return 0

    def doDetach(self, pid, check=False):
        if not pid:
            pid = self.pid

        self.attached = False

        plist = ConfigMgr.PTRACE_TYPE
        cmd = plist.index("PTRACE_DETACH")

        while 1:
            ret = self.ptrace(cmd, pid=pid)
            if ret != 0:
                SysMgr.printWarn(
                    "failed to detach %s(%s) from guider(%s) because %s"
                    % (self.comm, pid, SysMgr.pid, self.errmsg)
                )

                # check return #
                if not check:
                    return -1
                elif self.isAlive():
                    time.sleep(SysMgr.waitDelay)
                    continue
                else:
                    sys.exit(-1)
            else:
                SysMgr.printWarn(
                    "detached %s(%s) from guider(%s)"
                    % (self.comm, pid, SysMgr.pid)
                )
                return 0

    def detach(self, only=False, pid=None, check=False):
        if only:
            return self.doDetach(pid, check=check)

        if hasattr(self, "pid"):
            pid = self.pid
        else:
            return 0

        # kill target process executed #
        if self.execCmd:
            try:
                # kill process group #
                if os.getpgid(self.pid) == self.pid:
                    os.killpg(self.pid, signal.SIGTERM)
                # kill target process #
                else:
                    os.kill(self.pid, signal.SIGKILL)
            except:
                SysMgr.printSigError(pid, "SIGKILL")

            return 0

        # check the process is running #
        try:
            os.kill(pid, 0)
        except:
            return -1

        return self.doDetach(pid, check=check)

    def checkPid(self, pid):
        if not pid:
            return -1
        elif not UtilMgr.isNumber(pid):
            return -1
        elif long(pid) <= 0:
            return -1
        else:
            return 0

    def accessMem(self, cmd, addr, data=0):
        wordSize = ConfigMgr.wordSize

        if addr < wordSize:
            SysMgr.printWarn(
                (
                    "failed to access memory address %s for %s(%s) "
                    "because of wrong address"
                )
                % (hex(addr).rstrip("L"), self.comm, self.pid)
            )
            return -1

        if addr % wordSize:
            SysMgr.printWarn(
                (
                    "failed to access memory address %s for %s(%s) "
                    "because of unaligned address"
                )
                % (hex(addr).rstrip("L"), self.comm, self.pid)
            )
            return -1

        return self.ptrace(cmd, addr, data)

    def writeMem(self, addr, data, size=0, skipCheck=False):
        ret = 0
        wordSize = ConfigMgr.wordSize

        if addr < wordSize:
            SysMgr.printWarn(
                "failed to write to %s memory because of wrong address"
                % hex(addr).rstrip("L")
            )
            return None

        # update size #
        if size == 0 or size > len(data):
            size = len(data)

        if self.supportProcessVmWr:
            try:
                # prepare process_vm_writev syscall #
                process_vm_writev = SysMgr.libcObj.process_vm_writev

                if not self.initPvw:
                    SysMgr.libcObj.process_vm_writev.restype = c_size_t
                    SysMgr.libcObj.process_vm_writev.argtypes = [
                        c_int,
                        self.iovec_ptr,
                        c_size_t,
                        self.iovec_ptr,
                        c_size_t,
                        c_ulong,
                    ]
                    self.initPvw = True

                # create params #
                pid = self.pid

                try:
                    lbuf = (c_char * size)()
                    memmove(byref(lbuf), data, len(data))
                    liov = (self.iovec * 1)()[0]
                    liov.iov_base = cast(lbuf, c_void_p)
                    liov.iov_len = size

                    riov = (self.iovec * 1)()[0]
                    riov.iov_base = c_void_p(addr)
                    riov.iov_len = size
                except SystemExit:
                    sys.exit(0)
                except:
                    return None

                # do syscall #
                ret = process_vm_writev(pid, liov, 1, riov, 1, 0)
                if c_long(ret).value == -1:
                    self.errmsg = SysMgr.getErrReason()
                    SysMgr.printWarn(
                        "failed to process_vm_writev for %s(%s) because %s"
                        % (self.comm, self.pid, self.errmsg)
                    )
                    raise Exception()
                return ret
            except SystemExit:
                sys.exit(0)
            except:
                self.supportProcessVmWr = False

        # check address alignment #
        offset = addr % wordSize

        # handle integer-type data #
        if not skipCheck:
            if UtilMgr.isNumber(data):
                if offset == 0:
                    if size == 0:
                        size = 1
                    for idx in xrange(size):
                        ret = self.accessMem(
                            self.pokeIdx, addr + (idx * wordSize), data
                        )
                        if ret < 0:
                            break
                    return ret
                else:
                    data = UtilMgr.convWord2Str(UtilMgr.convStr2Num(data))
                    if not data:
                        return -1

                    # converting integer-type data #
                    if 0 <= size <= 1:
                        size = wordSize
                    elif size > 1:
                        data = data * size
                        size *= wordSize

            # convert string to bytes #
            if UtilMgr.isString(data):
                data = UtilMgr.encodeStr(data)
            elif type(data) is not bytes:
                SysMgr.printErr(
                    (
                        "failed to recognize data to write because "
                        "%s type is not supported"
                    )
                    % type(data)
                )
                return -1

        # trim data #
        modWord = len(data) % wordSize
        if modWord > 0:
            data += b"0" * (wordSize - modWord)

        # back up data #
        origData = data[:size]
        origSize = size

        # handle not aligned part #
        if offset > 0:
            addr -= offset
            size += offset

        # read words from target address space #
        data = b""
        tempAddr = addr
        while size > 0:
            word = self.readMem(tempAddr)
            if word is None:
                return -1

            data += word

            size -= wordSize
            tempAddr += wordSize

        # update original data #
        fdata = data[:offset] + origData + data[offset + origSize :]

        # convert type from bytes to word #
        for idx in xrange(0, len(fdata), wordSize):
            data = UtilMgr.convStr2Word(fdata[idx : idx + wordSize])

            ret = self.accessMem(self.pokeIdx, addr + idx, data)
            if ret == -1:
                break

        return ret

    def updateFileList(self):
        fileList = SysMgr.getOption("T")
        if fileList:
            fileList = list(set(fileList.split(",")))
            fileList = SysMgr.convRealPath(fileList)

            for path in fileList:
                if path.startswith("^"):
                    self.exceptBpFileList[path[1:]] = 0
                else:
                    self.targetBpFileList[path] = 0
        return list(self.targetBpFileList)

    def updateBpList(self, verb=True):
        if not self.isBreakMode:
            return

        # update file list #
        fileList = self.updateFileList()

        # update symbol list #
        if not SysMgr.customCmd:
            funcFilter = []
        else:
            funcFilter = list(set(SysMgr.customCmd))
            self.targetBpList.update(dict.fromkeys(funcFilter, 0))

        # add per-process breakpoints #
        return self.injectBpList(
            symList=funcFilter, binList=fileList, verb=verb
        )

    def readMem(self, addr, size=0, retWord=False, verb=True):
        wordSize = ConfigMgr.wordSize

        if not addr:
            return None

        if addr < wordSize:
            SysMgr.printWarn(
                (
                    "failed to read memory address %s for %s(%s) "
                    "because of wrong address"
                )
                % (hex(addr).rstrip("L"), self.comm, self.pid)
            )
            return None

        # check size #
        if not size:
            size = wordSize

        if self.supportProcessVmRd:
            try:
                # prepare process_vm_readv syscall #
                process_vm_readv = SysMgr.libcObj.process_vm_readv

                if not self.initPvr:
                    SysMgr.libcObj.process_vm_readv.restype = c_size_t
                    SysMgr.libcObj.process_vm_readv.argtypes = [
                        c_int,
                        self.iovec_ptr,
                        c_size_t,
                        self.iovec_ptr,
                        c_size_t,
                        c_ulong,
                    ]
                    self.initPvr = True

                # create params #
                pid = self.pid

                try:
                    lbuf = (c_char * size)()
                    liov = (self.iovec * 1)()[0]
                    liov.iov_base = cast(byref(lbuf), c_void_p)
                    liov.iov_len = size

                    riov = (self.iovec * 1)()[0]
                    riov.iov_base = c_void_p(addr)
                    riov.iov_len = size
                except SystemExit:
                    sys.exit(0)
                except:
                    return None

                # do syscall #
                ret = process_vm_readv(pid, liov, 1, riov, 1, 0)
                ret = c_long(ret).value
                if ret == 0:
                    return None
                elif ret == -1:
                    self.errmsg = SysMgr.getErrReason()
                    SysMgr.printWarn(
                        "failed to process_vm_readv for %s(%s) because %s"
                        % (self.comm, self.pid, self.errmsg)
                    )
                    raise Exception()

                data = memoryview(lbuf).tobytes()
                if retWord:
                    return UtilMgr.convStr2Word(data)
                else:
                    return data
            except SystemExit:
                sys.exit(0)
            except:
                self.supportProcessVmRd = False

        # define return list #
        data = bytes()

        # handle not aligned part #
        offset = addr % wordSize
        if offset > 0:
            addr -= offset
            size += offset

        # read words from target address space #
        while size > 0:
            # read a word #
            word = self.accessMem(self.peekIdx, addr)
            if word == -1:
                # failed to read partial area #
                if data:
                    break

                # failed to read whole area #
                if verb:
                    SysMgr.printErr(
                        "failed to read memory address %s for %s(%s)"
                        % (hex(addr).rstrip("L"), self.comm, self.pid)
                    )

                return None

            if retWord and offset == 0:
                return word

            # convert a word to a byte string #
            word = UtilMgr.convWord2Str(word)
            if not word:
                return None

            if size < wordSize:
                data += word[:size]
            else:
                data += word

            size -= wordSize
            addr += wordSize

        # return data #
        ret = data[offset:]
        if retWord:
            return UtilMgr.convStr2Word(ret)
        else:
            return ret

    def readStrList(self, pos, maxsize=sys.maxsize):
        strList = []

        while 1:
            try:
                # read start address for a string #
                addr = self.readWord(pos)
                if not addr:
                    break

                # read a string #
                string = self.readString(addr)
                if not string:
                    break

                strList.append(string.decode())
                pos += ConfigMgr.wordSize
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn(
                    "failed to read string from list for %s(%s)"
                    % (self.comm, self.pid),
                    reason=True,
                )
                break

        return strList

    def readString(self, addr, chunk=256, maxsize=sys.maxsize):
        cnt = 0
        ret = b""
        maxCnt = SysMgr.maxRdCnt
        while 1:
            string = self.readMem(addr, chunk)
            if not string:
                return ret

            # check read count #
            cnt += 1
            if cnt > maxCnt:
                SysMgr.printWarn(
                    "read %s time from %s for %s(%s)"
                    % (
                        UtilMgr.convNum(cnt),
                        hex(long(addr)),
                        self.comm,
                        self.pid,
                    ),
                    True,
                )
                maxCnt *= 2

            # check string size #
            if len(ret) > maxsize:
                SysMgr.printWarn(
                    "exceed maximum size %s to read string for %s(%s)"
                    % (UtilMgr.convSize2Unit(maxsize), self.comm, self.pid),
                    True,
                )
                return ret

            # read string from target #
            try:
                idx = string.index(b"\0")
                ret += string[:idx]
                return ret
            except SystemExit:
                sys.exit(0)
            except:
                if string:
                    ret += string

                if len(ret) > SysMgr.PAGESIZE:
                    return ret

    def readMultiMsgHdr(self, addr, vlen):
        msgInfo = {}
        for idx in xrange(vlen):
            offset = idx * sizeof(self.mmsghdr)
            # read msghdr structure #
            ret = self.readMem(addr + offset, sizeof(self.mmsghdr))
            if not ret:
                continue

            # cast struct mmsghdr #
            header = cast(ret, self.mmsghdr_ptr)

            # get msg info #
            msglen = header.contents.msg_len
            msgaddr = addressof(header.contents.msg_hdr)
            ret = self.readMsgHdr(obj=msgaddr)
            if not ret:
                continue

            # add msghdr to list #
            msgInfo[idx] = ret

        if not msgInfo:
            return addr

        return msgInfo

    def readIoVec(self, addr, cnt):
        iov = {}

        # get iov header info #
        iovaddr = cast(addr, c_void_p).value

        # get iov info #
        for idx in xrange(cnt):
            offset = idx * sizeof(self.iovec)

            iov[idx] = {}

            # get iov object #
            iovobj = self.readMem(iovaddr + offset, sizeof(self.iovec))
            iovobj = cast(iovobj, self.iovec_ptr)

            # get iov size #
            iovobjlen = long(iovobj.contents.iov_len)
            iov[idx]["iov_len"] = iovobjlen
            if iovobjlen == 0:
                iov[idx]["iov_base"] = ""
                continue

            # strip data #
            if not SysMgr.outPath and not Debugger.envFlags["NOSTRIP"]:
                iovobjdata = "STRIP"
            else:
                # get iov data #
                iovobjbase = iovobj.contents.iov_base
                iovobjdata = self.readMem(iovobjbase, iovobjlen)

            iov[idx]["iov_base"] = iovobjdata

        return iov

    def readMsgHdr(self, addr=None, obj=None):
        if not addr and not obj:
            return None

        # read msghdr structure #
        if not obj:
            ret = self.readMem(addr, sizeof(self.msghdr))
            if not ret:
                return addr
        else:
            ret = obj

        # cast struct msghdr #
        msginfo = {}
        header = cast(ret, self.msghdr_ptr)

        # get msg info #
        namelen = long(header.contents.msg_namelen)
        msginfo["msg_namelen"] = namelen
        if Debugger.dbusEnable or namelen == 0 or not header.contents.msg_name:
            msginfo["msg_name"] = "NULL"
        else:
            msginfo["msg_name"] = self.readMem(
                header.contents.msg_name, namelen
            ).decode("latin-1")

        # get iov header info #
        iovaddr = cast(header.contents.msg_iov, c_void_p).value
        iovlen = long(header.contents.msg_iovlen)

        if not SysMgr.showAll:
            msginfo["msg_iov"] = "0x{0:02x}".format(iovaddr)
        else:
            msginfo["msg_iov"] = {}

            # get iov info #
            for idx in xrange(iovlen):
                offset = idx * sizeof(self.iovec)

                # get iov object #
                iovobj = self.readMem(iovaddr + offset, sizeof(self.iovec))
                iovobj = cast(iovobj, self.iovec_ptr)

                # get iov size #
                iovobjlen = long(iovobj.contents.iov_len)
                if iovobjlen == 0:
                    continue

                msginfo["msg_iov"][idx] = {}

                # get iov data #
                iovobjbase = iovobj.contents.iov_base
                iovobjdata = self.readMem(iovobjbase, iovobjlen)

                # erase message #
                skip = False
                for ignoreName in SysMgr.ignoreItemList:
                    if not ignoreName in iovobjdata:
                        continue

                    iovobjdata = iovobjdata.replace(
                        ignoreName, b"\x00" * len(ignoreName)
                    )
                    self.writeMem(iovobjbase, iovobjdata)
                    skip = True
                    break
                if skip:
                    continue

                # encode to base64 #
                if Debugger.dbusEnable:
                    iovobjdata = UtilMgr.encodeBase64(iovobjdata)
                    if sys.version_info >= (3, 0):
                        iovobjdata = iovobjdata.decode("latin-1")
                # strip data #
                elif not SysMgr.outPath and not Debugger.envFlags["NOSTRIP"]:
                    iovobjdata = "STRIP"

                # save size and data #
                msginfo["msg_iov"][idx]["len"] = iovobjlen
                msginfo["msg_iov"][idx]["data"] = iovobjdata

        # get msg_flags #
        flag = header.contents.msg_flags
        msginfo["msg_flags"] = flag

        # ignore cmsg info #
        if Debugger.dbusEnable:
            return msginfo

        # get socket object #
        if not self.sockObj:
            socket = SysMgr.getPkg("socket", False)
            if not socket:
                return msginfo
            else:
                self.sockObj = socket

        # get control info #
        control = header.contents.msg_control
        controllen = long(header.contents.msg_controllen)
        msginfo["msg_control"] = {}
        msginfo["msg_control"]["len"] = controllen

        if not SysMgr.showAll:
            msginfo["msg_control"]["addr"] = control
        elif controllen >= sizeof(self.cmsghdr):
            # read cmsghdr #
            control = self.readMem(header.contents.msg_control, controllen)
            controlobj = cast(control, self.cmsghdr_ptr)

            # cmsg_len #
            cmsglen = long(controlobj.contents.cmsg_len)
            msginfo["msg_control"]["cmsglen"] = cmsglen

            # cmsg_level #
            cmsglevel = controlobj.contents.cmsg_level
            if cmsglevel == self.sockObj.SOL_SOCKET:
                msginfo["msg_control"]["cmsg_level"] = "SOL_SOCKET"
            else:
                msginfo["msg_control"]["cmsg_level"] = cmsglevel

            # cmsg_type #
            try:
                cmsgtype = controlobj.contents.cmsg_type
                msginfo["msg_control"]["cmsg_type"] = ConfigMgr.CMSG_TYPE[
                    cmsgtype
                ]
            except:
                msginfo["msg_control"]["cmsg_type"] = cmsgtype

            # cmsg_data #
            datasize = controllen - cmsglen
            if datasize > 0:
                try:
                    cmsgdata = bytes()
                    cmsgdata = self.readMem(
                        header.contents.msg_control + sizeof(self.cmsghdr),
                        datasize,
                    )

                    if len(cmsgdata) == 4:
                        cmsgdata = struct.unpack("I", cmsgdata)[0]
                    elif len(cmsgdata) == 8:
                        cmsgdata = struct.unpack("Q", cmsgdata)[0]
                    else:
                        raise Exception()
                except:
                    pass
                finally:
                    msginfo["msg_control"]["cmsg_data"] = cmsgdata

        return msginfo

    def convSyscallParam(
        self,
        argtype,
        argname,
        value,
        seq=0,
        ref=True,
        argset={},
        buf=False,
        retval=None,
    ):

        syscall = self.syscall

        """
        TODO:
        1. convert a integer or mask values
        2. process_vm_readv
        """

        # handle syscalls #
        if syscall == "sendmsg" or syscall == "recvmsg":
            if ref and argname == "msg":
                try:
                    return self.readMsgHdr(value)
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printWarn(
                        "failed to get msghdr for %s" % syscall,
                        True,
                        reason=True,
                    )
                    return value
        elif syscall == "sendmmsg" or syscall == "recvmmsg":
            if ref and argname == "vlen":
                try:
                    if "msg" in argset:
                        ret = self.readMultiMsgHdr(argset["msg"], value)
                        if ret != argset["msg"]:
                            self.changeArg("msg", ret)
                    return value
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printWarn(
                        "failed to get mmsghdr for %s" % syscall,
                        True,
                        reason=True,
                    )
                    return value
        elif syscall == "open" or syscall == "accept4":
            if argname == "flags":
                return UtilMgr.getFlagString(
                    value, ConfigMgr.OPEN_TYPE, num="oct"
                )
        elif syscall == "execve":
            # ignore envp arg #
            if argname == "argv":
                strList = self.readStrList(value)
                if strList:
                    return " [%s] " % (", ".join(strList))
                else:
                    return value
        elif syscall.startswith("mmap") or syscall == "mprotect":
            if argname == "prot":
                return UtilMgr.getFlagString(value, ConfigMgr.PROT_TYPE)
            elif argname == "flags":
                return UtilMgr.getFlagString(value, ConfigMgr.MAP_TYPE)
        elif syscall.startswith("fcntl"):
            if argname == "cmd":
                return ConfigMgr.FCNTL_TYPE[value]
        elif syscall.startswith("futex"):
            if argname == "op":
                if value < len(ConfigMgr.FUTEX_TYPE):
                    return ConfigMgr.FUTEX_TYPE[value]

                # check _PRIVATE FLAG #
                value = value & 0xF
                if value < len(ConfigMgr.FUTEX_TYPE):
                    return ConfigMgr.FUTEX_TYPE[value] + "_PRIVATE"
        elif syscall == "ptrace" and argname == "request":
            try:
                return ConfigMgr.PTRACE_TYPE[value]
            except SystemExit:
                sys.exit(0)
            except:
                return value
        elif syscall == "socketcall":
            if argname == "call":
                try:
                    return ConfigMgr.SOCKETCALL[value]
                except SystemExit:
                    sys.exit(0)
                except:
                    return value
            elif argname == "args":
                # TODO: handle socket call args #
                return value
        elif syscall == "access":
            if argname == "mode":
                return UtilMgr.getFlagString(value, ConfigMgr.PERM_TYPE)
        elif syscall == "clone":
            if argname == "flags":
                return UtilMgr.getFlagString(value, ConfigMgr.CLONE_TYPE)
        elif (
            syscall == "epoll_ctl"
            or syscall == "epoll_wait"
            or syscall == "epoll_pwait"
        ):
            if argname == "op":
                try:
                    return ConfigMgr.EPOLL_CMD_TYPE[value]
                except SystemExit:
                    sys.exit(0)
                except:
                    return value
            elif ref and argname.startswith("event"):
                try:
                    value = self.readMem(value)
                    value = struct.unpack(self.decChar, value)[0]
                    return UtilMgr.getFlagString(
                        value, ConfigMgr.EPOLL_EVENT_TYPE
                    )
                except SystemExit:
                    sys.exit(0)
                except:
                    return value
        elif syscall == "bpf":
            if argname == "cmd":
                try:
                    return ConfigMgr.BPF_CMD[value]
                except SystemExit:
                    sys.exit(0)
                except:
                    return value
        elif syscall == "prctl":
            if argname == "option":
                try:
                    return ConfigMgr.PRCTL_TYPE[value]
                except SystemExit:
                    sys.exit(0)
                except:
                    return value
        elif syscall.startswith("madvise"):
            if argname == "behavior":
                try:
                    return ConfigMgr.MADV_TYPE[c_int(value).value]
                except SystemExit:
                    sys.exit(0)
                except:
                    return value
        elif syscall == "mount":
            if argname == "flags":
                if not ConfigMgr.MOUNT_TYPE_REVERSE:
                    for name, value in ConfigMgr.MOUNT_TYPE.items():
                        ConfigMgr.MOUNT_TYPE_REVERSE[value] = name

                return UtilMgr.getFlagString(
                    value, ConfigMgr.MOUNT_TYPE_REVERSE
                )
        elif syscall.startswith("umount"):
            if argname == "flags":
                if not ConfigMgr.UMOUNT_TYPE_REVERSE:
                    for name, value in ConfigMgr.UMOUNT_TYPE.items():
                        ConfigMgr.UMOUNT_TYPE_REVERSE[value] = name

                return UtilMgr.getFlagString(
                    value, ConfigMgr.UMOUNT_TYPE_REVERSE
                )

        # convert fd to name #
        if ref and (argname == "fd" or argname == "sockfd"):
            try:
                path = os.readlink(
                    "%s/%s/fd/%s" % (SysMgr.procPath, self.pid, value)
                )
                return "%s>%s" % (value, path)
            except SystemExit:
                sys.exit(0)
            except:
                return str(value)

        # convert pointer to string #
        if (
            ref
            and argtype == "const char *"
            and (
                argname.endswith("name")
                or argname.endswith("path")
                or argname.endswith("type")
            )
        ):
            addr = self.values[seq]
            # redundant call after execve #
            if addr == 0:
                return value
            else:
                ret = self.readString(addr)
                if not ret:
                    ret = addr
                return ret

        # convert iov #
        if ref and argname == "vlen" and "vec" in argset:
            vaddr = argset["vec"]
            cnt = value
            try:
                ret = self.readIoVec(vaddr, cnt)
                if ret != argset["vec"]:
                    self.changeArg("vec", ret)
                return value
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn(
                    "failed to read iovector for %s" % syscall,
                    True,
                    reason=True,
                )
                return value

        # convert position #
        if argname == "whence":
            return ConfigMgr.SEEK_TYPE[c_int(value).value]

        # convert at #
        if argname == "dfd":
            try:
                return ConfigMgr.FAT_TYPE[c_int(value).value]
            except:
                return "AT_FDCWD"

        # convert pointer to buffer #
        if buf and argname == "buf" and syscall in ConfigMgr.SYSCALL_REFBUF:
            # set try size #
            size = self.values[2]

            # handle read buffer #
            if syscall in ConfigMgr.SYSCALL_DEFFERABLE:
                if retval == 0:
                    return ""
                elif retval:
                    size = retval

            # set op length #
            if size > self.pbufsize:
                length = self.pbufsize
            else:
                length = size

            # set print length #
            if SysMgr.outPath:
                cutLen = sys.maxsize
            else:
                cutLen = length

            # read string from address #
            ret = self.readMem(value, length)
            if ret:
                value = ret

            try:
                return repr(value)[1:-1][:cutLen]
            except SystemExit:
                sys.exit(0)
            except:
                return repr(value)

        # convert socket flag #
        if argname == "flags" and value:
            if syscall.startswith("send") or syscall.startswith("recv"):
                return UtilMgr.getFlagString(value, ConfigMgr.MSG_TYPE)

        # convert signal #
        if argname == "signum" or argname == "sig":
            return ConfigMgr.SIG_LIST[c_int(value).value]

        # remove const prefix #
        if argtype.startswith("const "):
            argtype = argtype[6:]

        # TODO: handle pointer data type #
        if argtype[-1] == "*":
            return value

        return value

    @staticmethod
    def makeSvgString(callTree, callCnt):
        # create palette for colors #
        palette = Timeline.Config().PALETTE

        def _iterNode(
            array, target, callCnt, depth=0, pos=0, height=36, hsize=15
        ):
            for node, value in sorted(
                target.items(), key=lambda x: x[1]["cnt"], reverse=True
            ):
                # get stats #
                totalCnt = callCnt[0]
                cnt = value["cnt"]
                per = cnt / float(totalCnt) * 100

                # iterate children #
                if value["child"]:
                    _iterNode(
                        array,
                        value["child"],
                        callCnt,
                        depth + 1,
                        pos,
                        height + 16,
                    )

                # build tags #
                indent = "    "
                tagStr = "<g>\n"
                name = UtilMgr.convHtmlChar(node)
                color = palette[len(array) % len(palette)]
                tagStr += "%s<title>%s (%s samples, %.1f%%)</title>\n" % (
                    indent,
                    name,
                    UtilMgr.convNum(cnt),
                    per,
                )
                tagStr += (
                    '%s<rect x="%.4f%%" y="%s" width="%.4f%%" '
                    'height="%s" fill="%s"/>\n'
                ) % (indent, pos, height, per, hsize, color)
                tagStr += '%s<text x="%.4f%%" y="%.2f"></text>\n' % (
                    indent,
                    pos + 0.25,
                    height + 10.5,
                )
                tagStr += "</g>"

                # append tag #
                array.append(tagStr)

                pos += per

        tagList = []
        _iterNode(tagList, callTree, callCnt)
        return "\n".join(tagList)

    @staticmethod
    def drawFlame(
        inputFile=None, callList={}, title="", suffix=False, outFile=None
    ):
        if not inputFile and not callList:
            SysMgr.printErr("no input for flamegraph")
            sys.exit(-1)

        # convert input value type to list #
        if not inputFile:
            fileName = "guider"
            inputName = "N/A"
            inputList = []
        elif type(inputFile) is list:
            if SysMgr.outPath:
                fileName = SysMgr.outPath
            else:
                fileName = "merged"
            inputName = ", ".join(inputFile)
            inputList = inputFile
        else:
            fileName = inputFile
            inputName = inputFile
            inputList = [inputFile]

        # set output path #
        if inputList:
            outputPath = UtilMgr.getDrawOutputPath(
                fileName, "flamegraph", suffix=suffix
            )
        elif outFile:
            outputPath = outFile
            if not outputPath.endswith(".svg"):
                outputPath += ".svg"
        else:
            outputPath = "flamegraph.svg"

        # set verbose flag #
        if len(inputList) > 1:
            verb = True
        else:
            verb = False

        # load call samples #
        if not callList:
            for fname in inputList:
                # get list for call samples #
                try:
                    # get samples #
                    sampleList, newTitle = Debugger.getCallStatsFile(
                        fname, verb=verb
                    )
                    if not sampleList:
                        SysMgr.printErr("no call sample for '%s'" % fname)
                        continue

                    # add a new title #
                    title += '<tspan x="0" dy="1.2em">%s</tspan>' % newTitle

                    # merge samples #
                    for sample, cnt in sampleList.items():
                        if sample in callList:
                            callList[sample] += cnt
                        else:
                            callList[sample] = cnt
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(
                        "failed to get call sample from '%s'" % fname, True
                    )
                    sys.exit(-1)

        # remove samples in WAIT status #
        if "EXCEPTWAIT" in SysMgr.environList:
            newList = {}
            for item in callList:
                if item.startswith("WAIT{"):
                    continue
                newList[item] = callList[item]
            callList = newList

        # check call samples #
        if not callList:
            SysMgr.printErr("no call sample to draw flame graph")
            sys.exit(-1)

        # convert list to tree for call samples #
        try:
            callTree, callCnt, depth = Debugger.convCallList2Tree(callList)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to convert call samples from '%s'" % inputName, True
            )
            sys.exit(-1)

        # make svg string #
        try:
            svgStr = Debugger.makeSvgString(callTree, callCnt)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to make flame graph from '%s'" % inputName, True
            )
            sys.exit(-1)

        # write svg code to the file #
        try:
            UtilMgr.writeFlamegraph(outputPath, svgStr, title, depth)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to save flamegraph from '%s' to '%s'"
                % (inputName, SysMgr.outPath),
                True,
            )
            sys.exit(-1)

    @staticmethod
    def convCallList2Tree(callList):
        def _getObj():
            return dict(cnt=0, child={})

        tree = {}
        totals = {}
        pos = None
        maxLevel = 0

        # iterate calls #
        for sample, count in callList.items():
            level = 0
            pos = tree
            calls = reversed(sample.split(" <- "))

            # iterate functions #
            for call in calls:
                # remove multiple info #
                items = call.split("] * ")
                if len(items) > 1:
                    call = "%s]" % items[0]

                pos.setdefault(call, _getObj())
                pos[call]["cnt"] += count
                pos = pos[call]["child"]
                totals.setdefault(level, 0)
                totals[level] += count
                level += 1

                # update max depth #
                if level >= maxLevel:
                    maxLevel = level

        return tree, totals, maxLevel

    @staticmethod
    def getCallStatsFile(logFile, verb=False):
        # get file handle #
        try:
            fd = UtilMgr.getTextLines(logFile, verb=verb, retfd=True)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to read %s\n" % logFile)
            sys.exit(-1)

        stack = ""
        main = ""
        mainCnt = 0
        context = None
        samples = {}
        title = None

        # check backtrace stacks #
        if "ONLYBTSTACK" in SysMgr.environList:
            onlybt = True
        else:
            onlybt = False

        for line in fd:
            # get start keyword #
            if line.startswith("[Top ") or line.startswith("[Trace "):
                if not " Summary]" in line or context:
                    return samples, title

                title = line.strip()
                context = "start"
                continue
            elif context is None:
                continue

            # split line #
            sline = line.split("|")
            slen = len(sline)

            if slen == 2:
                per = sline[0].strip()
                if not per[0].isdigit():
                    continue

                string = sline[1].lstrip()
                # backtraces #
                if string.startswith("<-"):
                    # parse backtraces #
                    last = string.split("<Cnt: ")
                    if not stack:
                        stack = main
                    if len(last) == 2:
                        stack = "%s %s" % (stack, last[0].strip())
                        count = long(last[1].strip().replace(",", "")[:-1])
                        samples.setdefault(stack, 0)
                        samples[stack] += count
                        stack = ""
                    else:
                        stack = "%s %s" % (stack, last[0].strip())
                # PC #
                else:
                    # no backtrace call #
                    if not onlybt and stack:
                        samples.setdefault(stack, 0)
                        samples[stack] += mainCnt

                    last = string.split("<Cnt: ")
                    stack = last[0].strip()
                    mainCnt = long(last[1].strip().replace(",", "")[:-1])
                    main = stack

            elif line.lstrip().startswith("<-"):
                # parse backtraces #
                last = line.split("<Cnt: ")
                if len(last) == 2:
                    stack = "%s %s" % (stack, last[0].strip())
                    count = long(last[1].strip().replace(",", "")[:-1])
                    samples.setdefault(stack, 0)
                    samples[stack] += count
                    stack = ""
                else:
                    stack = "%s %s" % (stack, last[0].strip())

            else:
                # no backtrace call #
                if not onlybt and stack:
                    samples.setdefault(stack, 0)
                    samples[stack] += mainCnt
                    stack = ""

        return samples, title

    @staticmethod
    def updateCommFlag(flag=True):
        if not Debugger.globalEvent:
            return

        # set flag value #
        if flag is True:
            value = 1
        else:
            value = 0

        if sys.version_info < (3, 0, 0):
            value = bytes(value)

        Debugger.globalEvent[  # pylint: disable=unsupported-assignment-operation
            0
        ] = value

    @staticmethod
    def needUpdateComm():
        if not Debugger.globalEvent:
            return False

        ret = Debugger.globalEvent[0]  # pylint: disable=unsubscriptable-object
        if ret == b"1" or ret == 1:
            return True
        else:
            return False

    @staticmethod
    def setFaultFlag(flag=True):
        if not Debugger.globalEvent:
            return

        # set flag value #
        if flag is True:
            value = 1
        else:
            value = 0

        if sys.version_info < (3, 0, 0):
            value = bytes(value)

        Debugger.globalEvent[  # pylint: disable=unsupported-assignment-operation
            1
        ] = value

    @staticmethod
    def getFaultFlag():
        if not Debugger.globalEvent:
            return False

        ret = Debugger.globalEvent[1]  # pylint: disable=unsubscriptable-object
        if ret == b"1" or ret == 1:
            return True
        else:
            return False

    @staticmethod
    def onAlarm(signum, frame):
        if Debugger.dbgInstance:
            Debugger.dbgInstance.printIntervalSummary()

        SysMgr.updateTimer()

    def printIntervalSummary(self):
        def _resetStats():
            # merge syscall stats #
            for syscall in self.syscallStat:
                self.syscallTotalStat.setdefault(syscall, [0, 0])
                # update maximum elapsed time #
                if (
                    self.syscallTotalStat[syscall][1]
                    < self.syscallStat[syscall][1]
                ):
                    self.syscallTotalStat[syscall][1] = self.syscallStat[
                        syscall
                    ][1]
                self.syscallTotalStat[syscall][0] += self.syscallStat[syscall][
                    0
                ]

            # initialize syscall timetable #
            self.syscallStat = {}
            self.syscallInterStat = {}
            self.bpcallStat = {}
            self.bpcallInterStat = {}

            # reset data #
            self.totalCall = 0
            self.callTable = {}
            self.errCnt = 0
            SysMgr.clearPrint()

        def _checkInterval():
            if SysMgr.repeatCount == 0:
                return

            # check uptime deadline #
            meetDeadline = (
                SysMgr.deadlineUptime > 0
                and SysMgr.deadlineUptime <= SysMgr.uptime
            )

            # update and check progress #
            SysMgr.progressCnt += 1
            if SysMgr.repeatCount <= SysMgr.progressCnt or meetDeadline:
                SysMgr.printWarn("terminated by timer\n", True)
                sys.exit(0)

        def _printHist(items, title):
            itemList = UtilMgr.convList2Histo(items, mult=1000000)
            UtilMgr.printHist(itemList, title, "us", SysMgr.addPrint, "\n")

        def _finishPrint(self, needStop=False, term=False, flush=True):
            # flush print buffer #
            if flush:
                SysMgr.printTopStats()

            # check and update repeat count #
            _checkInterval()

            # reset stats #
            _resetStats()

            # stop target to return original status #
            if needStop:
                self.stop(check=True)

            # terminate tracing #
            if term:
                sys.exit(0)

        # define term variable #
        term = False

        # check master process #
        if (
            SysMgr.masterPid > 0
            and not Debugger.envFlags["CONTALONE"]
            and not SysMgr.isAlive(SysMgr.masterPid)
        ):
            SysMgr.printWarn(
                "terminated the master process for %s" % __module__
            )
            if self.callTable:
                term = True
            else:
                sys.exit(0)

        # update comm #
        origComm = self.comm
        self.comm = SysMgr.getComm(self.pid)
        if not self.comm:
            self.comm = origComm

        # check samples #
        if not self.callTable:
            if not self.traceStatus:
                SysMgr.printWarn(
                    "no sample data for %s(%s)" % (self.comm, self.pid),
                    False if SysMgr.masterPid > 0 else True,
                )

            # check and update repeat count #
            _checkInterval()

            # reset stats #
            _resetStats()

            return

        # check user input #
        SysMgr.waitUserInput(wait=0.000001, msg="DEFAULT")

        # define stop flag #
        needStop = False

        # update time #
        SysMgr.updateUptime()
        current = time.time()
        diff = current - self.last
        self.last = current

        # check comm filter for child #
        if (self.execCmd and SysMgr.filterGroup) or Debugger.targetNums:
            # check filter #
            if SysMgr.filterGroup and UtilMgr.isValidStr(self.comm):
                pass
            # check thread sequence #
            elif self.myNum in Debugger.targetNums:
                pass
            # check break mode #
            elif self.mode == "break":
                # reset stats #
                _resetStats()

                # check term condition #
                if term:
                    sys.exit(0)
                else:
                    return
            else:
                # print status #
                SysMgr.printWarn(
                    "stopped tracing %s(%s) because it is not targeted"
                    % (self.comm, self.pid)
                )

                # disable alarm #
                self.status = "wait"
                signal.alarm(0)

                # disable file output #
                SysMgr.outPath = None

                # continue target #
                if self.isStopped():
                    self.cont()

                # reset stats #
                _resetStats()

                # check term condition #
                if term:
                    sys.exit(0)
                else:
                    return

        # get CPU usage for target #
        cpuUsage = self.getCpuUsage(system=True)
        ttime = cpuUsage[0] / diff
        utime = cpuUsage[1] / diff
        stime = cpuUsage[2] / diff
        ttimeStr = UtilMgr.convCpuColor(ttime, "%d%%" % ttime)
        cpuStr = "%s(U%d%%+S%d%%)" % (ttimeStr, utime, stime)

        # get memory usage for target #
        rssStr = self.getMemUsage()

        # get CPU usage for system #
        ctime = 100 - (cpuUsage[3] / diff)
        ctime = ctime if ctime > 0 else 0
        sysCpuStr = "%d%%" % ctime
        sysCpuStr = UtilMgr.convCpuColor(ctime, sysCpuStr)

        # get available memory for system #
        sysMemStr = SysMgr.getAvailMemInfo()

        # check CPU threshold #
        if Debugger.cpuCond > -1 and Debugger.cpuCond > ttime:
            # reset stats #
            _resetStats()

            # check term condition #
            if term:
                sys.exit(0)
            else:
                return

        # define variables #
        nrTotal = float(self.totalCall)
        convert = UtilMgr.convNum
        convColor = UtilMgr.convColor
        convFloat = UtilMgr.convFloat2Str

        # set table name #
        if self.mode == "syscall":
            ctype = "Syscall"
            if Debugger.envFlags["INTERCALL"]:
                addInfo = "<Interval>"
            else:
                addInfo = "<Elapsed>"
            sampleStr = ""
        elif self.mode == "break":
            ctype = "Breakcall"
            addInfo = "[PATH] <Interval/Elapsed[RET]>"
            sampleStr = ""
        elif self.mode == "pycall":
            ctype = "Pycall"
            addInfo = "[PATH] <Sample>"
            sampleStr = " [Freq: %s]" % convFloat(self.sampleTime)
        elif self.mode == "kernel":
            ctype = "Kernelcall"
            addInfo = "<Sample>"
            sampleStr = " [Freq: %s]" % convFloat(self.sampleTime)
        else:
            ctype = "Usercall"
            addInfo = "[PATH] <Sample>"
            sampleStr = " [Freq: %s]" % convFloat(self.sampleTime)

            # continue target to prevent too long freezing #
            if self.traceStatus and self.isAlive():
                try:
                    sig = 0
                    ret = os.waitpid(self.pid, os.WNOHANG)
                    if ret and ret[1] > 0:
                        sig = self.getStatus(ret[1])
                    if (
                        sig != signal.SIGSTOP
                        and self.cont(check=True, sig=sig) == 0
                    ):
                        needStop = True
                except:
                    pass

        # update resource usage for myself #
        cpuUsage = Debugger.tracerInstance.getCpuUsage()
        mttime = cpuUsage[0] / diff
        mcpuStr = "%d%%" % mttime
        mcpuStr = UtilMgr.convCpuColor(mttime, mcpuStr)
        mrssStr = Debugger.tracerInstance.getMemUsage()

        # add CPU time info #
        self.cpuUsageList.append([ttime, utime, stime, ctime])
        self.selfCpuUsageList.append(mttime)

        # calculate average for CPU usage #
        if not SysMgr.showAll and SysMgr.cpuEnable:
            floatTotalUsage = ttime / 100
            floatUserUsage = utime / 100
            floatSysUsage = stime / 100
        else:
            floatTotalUsage = 1
            floatUserUsage = 1
            floatSysUsage = 1

        # set comm #
        if self.comm:
            comm = self.comm
        else:
            comm = "??"

        # JSON-format stats #
        if SysMgr.jsonEnable:
            jsonData = {
                "type": ctype,
                "uptime": SysMgr.uptime,
                "interval": diff,
                "samples": self.totalCall,
                "nrError": self.errCnt,
                "sysCpu": sysCpuStr,
                "sysMem": sysMemStr,
                "comm": comm,
                "pid": self.pid,
                "cpu": cpuStr,
                "rss": rssStr,
                "tracerComm": Debugger.tracerInstance.comm,
                "tracerPid": Debugger.tracerInstance.pid,
                "tracerCpu": mcpuStr,
                "tracerRss": mrssStr,
                "stats": {},
            }
        # string-format stats #
        else:
            # set error count #
            if self.errCnt:
                errstr = "[Err: %s] " % convColor(convert(self.errCnt), "RED")
            else:
                errstr = ""

            # print top stat #
            ret = SysMgr.addPrint(
                (
                    "[Top %s Info] [Time: %.3f] [Inter: %.3f] [Sample: %s] "
                    "%s[SYS: %s/%s] [%s(%s): %s/%s] [%s(%s): %s/%s]%s \n%s\n"
                )
                % (
                    ctype,
                    SysMgr.uptime,
                    diff,
                    convert(self.totalCall),
                    errstr,
                    sysCpuStr,
                    sysMemStr,
                    comm,
                    self.pid,
                    cpuStr,
                    rssStr,
                    Debugger.tracerInstance.comm,
                    Debugger.tracerInstance.pid,
                    mcpuStr,
                    mrssStr,
                    sampleStr,
                    twoLine,
                ),
                newline=2,
            )
            if not ret:
                # flush print buffer #
                _finishPrint(self, needStop, term)
                return

            # print menu #
            ret = SysMgr.addPrint(
                "{0:^7} | {1:<144}\n{2:<1}\n".format(
                    "Usage", "Function %s" % addInfo, twoLine
                ),
                newline=2,
            )
            if not ret:
                # flush print buffer #
                _finishPrint(self, needStop, term)
                return

        # print functions #
        totalCnt = 0
        isBtPrinted = False
        for sym, value in sorted(
            self.callTable.items(), key=lambda x: x[1]["cnt"], reverse=True
        ):
            # get count #
            cnt = value["cnt"]
            cntstr = convert(cnt)

            # check percentage #
            try:
                per = cnt / nrTotal * 100 * floatTotalUsage
            except:
                break

            # SYSCALL #
            if self.mode == "syscall":
                try:
                    total, tmax = self.syscallStat[sym]
                    average = total / cnt
                except:
                    total = average = tmax = 0

                # color err #
                err = value["err"]
                if err > 0:
                    errstr = UtilMgr.convColor(convert(err), "RED")
                else:
                    errstr = convert(err)

                # handle stdev #
                if (
                    Debugger.envFlags["STDEV"]
                    and sym in self.syscallInterStat
                    and self.syscallInterStat[sym]
                ):
                    stdev = UtilMgr.getStdev(self.syscallInterStat[sym])
                    if Debugger.envFlags["PRINTHIST"]:
                        _printHist(self.syscallInterStat[sym], sym)
                else:
                    stdev = -1

                # merge stats #
                if SysMgr.jsonEnable:
                    jsonData["stats"][sym] = {
                        "count": cnt,
                        "totalTime": total,
                        "avgTime": average,
                        "maxTime": tmax,
                        "error": err,
                        "stdev": stdev,
                    }
                else:
                    avgtime = "%.6f" % average
                    maxtime = "%.6f" % tmax

                    # convert time color #
                    if average > self.retTime:
                        avgtime = UtilMgr.convColor(avgtime, "RED")
                    if tmax > self.retTime:
                        maxtime = UtilMgr.convColor(maxtime, "RED")

                    # convert stdev #
                    if stdev > -1:
                        stdevstr = ", Std: %.6f" % stdev
                    else:
                        stdevstr = ""

                    addVal = (
                        "<Cnt: %s, Tot: %.6f, Avg: %s, Max: %s, Err: %s%s>"
                        % (
                            convColor(cntstr, "YELLOW"),
                            total,
                            avgtime,
                            maxtime,
                            convColor(errstr, "RED") if err else errstr,
                            stdevstr,
                        )
                    )
            # BREAKPOINT #
            elif self.mode == "break":
                try:
                    prev, total, tmin, tmax = self.bpcallStat[sym]
                    average = total / cnt
                except:
                    prev = total = tmin = tmax = average = 0

                # handle stdev #
                if (
                    Debugger.envFlags["STDEV"]
                    and sym in self.bpcallInterStat
                    and self.bpcallInterStat[sym]
                ):
                    stdev = UtilMgr.getStdev(self.bpcallInterStat[sym])
                    if Debugger.envFlags["PRINTHIST"]:
                        _printHist(self.bpcallInterStat[sym], sym)
                else:
                    stdev = -1

                # merge stats #
                if SysMgr.jsonEnable:
                    jsonData["stats"][sym] = {
                        "path": value["path"],
                        "count": cnt,
                        "avgTime": average,
                        "minTime": tmin,
                        "maxTime": tmax,
                        "stdev": stdev,
                    }
                else:
                    avgtime = "%.6f" % average
                    maxtime = "%.6f" % tmax

                    # convert time color #
                    if average > self.retTime:
                        avgtime = UtilMgr.convColor(avgtime, "RED")
                    if tmax > self.retTime:
                        maxtime = UtilMgr.convColor(maxtime, "RED")

                    # convert stdev #
                    if stdev > -1:
                        stdevstr = ", Std: %.6f" % stdev
                    else:
                        stdevstr = ""

                    addVal = (
                        "[%s] <Cnt: %s, Avg: %s, Min: %.6f, Max: %s%s>"
                        % (
                            value["path"],
                            convColor(cntstr, "YELLOW"),
                            avgtime,
                            tmin,
                            maxtime,
                            stdevstr,
                        )
                    )
            # OTHERS #
            else:
                # merge stats #
                if SysMgr.jsonEnable:
                    jsonData["stats"][sym] = {
                        "path": value["path"],
                        "count": cnt,
                    }
                else:
                    addVal = "[%s] <Cnt: %s>" % (
                        value["path"],
                        convColor(cntstr, "YELLOW"),
                    )

            if not SysMgr.jsonEnable:
                # check cut condition #
                if SysMgr.checkCutCond():
                    break

                # convert path to symbol #
                if sym[0] == "/":
                    targetSym = "??"
                else:
                    targetSym = sym

                ret = SysMgr.addPrint(
                    "{0:>7} | {1:<144}\n".format(
                        convColor("%.1f%%" % per, "YELLOW", 7),
                        "%s %s" % (convColor(targetSym, "CYAN"), addVal),
                    )
                )
                if not ret:
                    break

            totalCnt += 1

            # print backtraces #
            if value["backtrace"]:
                if SysMgr.outPath:
                    self.btTable.setdefault(sym, dict())

                for bt, bcnt in sorted(
                    value["backtrace"].items(),
                    key=lambda x: x[1],
                    reverse=True,
                ):

                    # set percent #
                    bper = bcnt / float(cnt) * 100

                    # JSON format output #
                    if SysMgr.jsonEnable:
                        jsonData["stats"][sym].setdefault("backtraces", [])
                        jsonData["stats"][sym]["backtraces"].append(
                            {
                                "stack": UtilMgr.cleanItem(
                                    bt.replace("\n", "").split(" <- ")
                                ),
                                "count": bcnt,
                                "per": bper,
                            }
                        )
                        continue

                    # merge backtraces #
                    if SysMgr.outPath:
                        self.btTable[sym].setdefault(bt, 0)
                        self.btTable[sym][bt] += bcnt

                    nline = bt.count("\n") + 1
                    if SysMgr.checkCutCond(nline):
                        # flush print buffer #
                        _finishPrint(self, needStop, term)
                        return

                    ret = SysMgr.addPrint(
                        "{0:>17} | {1:<1} <Cnt: {2:1}>\n".format(
                            convColor("%.1f%%" % bper, "BLUE", 17),
                            bt,
                            convColor(convert(bcnt), "YELLOW"),
                        ),
                        newline=nline,
                    )
                    if not ret:
                        break

            # handle rest jobs #
            if SysMgr.jsonEnable:
                continue
            elif SysMgr.funcDepth > 0:
                isBtPrinted = True
                ret = SysMgr.addPrint("%s\n" % oneLine)
                if not ret:
                    break

        # print status #
        if SysMgr.jsonEnable:
            # stop target again #
            _finishPrint(self, needStop, term, False)

            # print JSON-format output #
            SysMgr.printPipe(
                UtilMgr.convDict2Str(jsonData, pretty=not SysMgr.streamEnable)
            )
        else:
            if ret:
                if totalCnt == 0:
                    SysMgr.addPrint("\tNone\n")

                if not isBtPrinted:
                    SysMgr.addPrint("%s\n" % oneLine)

            # flush print buffer #
            _finishPrint(self, needStop, term)

            # print progress #
            if ret and SysMgr.repeatCount > 0:
                UtilMgr.printProgress(SysMgr.progressCnt, SysMgr.repeatCount)

    def changeArg(self, name, value):
        for idx, item in enumerate(self.args):
            if item[1] == name:
                self.args[idx][2] = value
                return True
        return False

    def addArg(self, type, name, value):
        self.args.append([type, name, value])

    def clearArgs(self):
        self.args = []

    def getAnonRangeByOffset(self, offset, fname=None):
        if not fname in self.pmap:
            return

        vstart = self.pmap[fname]["vstart"]
        vend = self.pmap[fname]["vend"]

        # get ELF object #
        fcache = ElfAnalyzer.getObject(fname)
        if not fcache:
            return [0, 0]

        ret = fcache.getAnonRangeByOffset(offset)
        if not ret:
            return [0, 0]

        # check executable type #
        if not ElfAnalyzer.isRelocFile(fname):
            start = ret[0]
            end = ret[1]
        else:
            start = vstart + ret[0]
            end = vstart + ret[1]

        return [start, end]

    def getRangeBySym(self, symbol, fname=None):
        if not fname in self.pmap:
            return

        vstart = self.pmap[fname]["vstart"]
        vend = self.pmap[fname]["vend"]

        # get ELF object #
        fcache = ElfAnalyzer.getObject(fname)
        if not fcache:
            return [0, 0]

        ret = fcache.getRangeBySymbol(symbol)
        if not ret:
            return [0, 0]

        # check executable type #
        if not ElfAnalyzer.isRelocFile(fname):
            start = ret[0]
            end = ret[1]
        else:
            start = vstart + ret[0]
            end = vstart + ret[1]

        return [start, end]

    def updateProcMap(self, onlyExec=True):
        # get original map #
        try:
            mapstr = FileAnalyzer.procMapStrCache[self.pid]
        except:
            mapstr = None

        # update file-mapped memory map #
        self.pmap = FileAnalyzer.getProcMapInfo(
            self.pid, self.mapFd, onlyExec=onlyExec
        )

        # check map change #
        try:
            if mapstr == FileAnalyzer.procMapStrCache[self.pid]:
                return False
        except SystemExit:
            sys.exit(0)
        except:
            pass
        finally:
            self.prevPmap = self.pmap

        # get anonymous executable memory map #
        self.amap = FileAnalyzer.getAnonMapInfo(self.pid, self.mapFd)

        return True

    def getJITSymbolByOffset(self, offset):
        # check symbol table #
        if not self.jmapSymTable:
            return "??", "??", "??"

        try:
            if UtilMgr.isString(offset):
                try:
                    offset = long(offset, 16)
                except:
                    offset = long(offset)

            addrTable = self.jmapAddrTable
            symTable = self.jmapSymTable

            # get target index from address table #
            idx = UtilMgr.bisect_left(addrTable, offset) - 1
            if idx < 0:
                idx = 0

            while 1:
                if addrTable[idx] > offset:
                    return "??", "??", "??"

                size = symTable[idx][1]
                path = symTable[idx][2]

                # set symbol scope to it's size #
                maxAddr = addrTable[idx] + size

                if offset >= addrTable[idx] and offset <= maxAddr:
                    return symTable[idx][0], size, path

                idx += 1
        except SystemExit:
            sys.exit(0)
        except:
            return "??", "??", "??"

    def loadJITSymbols(self):
        if not self.jmapPath:
            tgid = long(SysMgr.getTgid(self.pid))
            if not tgid:
                return False
            self.jmapPath = "%s/perf-%s.map" % (SysMgr.tmpPath, tgid)

        if not self.jmapFd:
            try:
                self.jmapFd = open(self.jmapPath, "r")
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenWarn(self.jmapPath)
                return False

        # get map size #
        try:
            mapSize = os.fstat(self.jmapFd.fileno()).st_size
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn(
                "failed to get size for '%s' for %s(%s)"
                % (self.jmapPath, self.comm, self.pid)
            )
            return False

        # check map update and update JIT-compiled symbols #
        if mapSize != self.jmapSize:
            try:
                SysMgr.printWarn(
                    "start updating JIT-compiled symbols for %s(%s)"
                    % (self.comm, self.pid)
                )

                # update size #
                self.jmapSize = mapSize

                # reset symbol and address table #
                jmapTable = []
                self.jmapAddrTable = []
                self.jmapSymTable = []

                # parse and sort items #
                for item in self.jmapFd.readlines():
                    symInfo = item.rstrip().split(" ", 2)
                    if len(symInfo) == 3:
                        addr, size, sym = symInfo
                    else:
                        SysMgr.printWarn(
                            "failed to parse JIT-compiled symbol info '%s' "
                            "for %s(%s)" % (item, self.comm, self.pid)
                        )
                        continue

                    jmapTable.append([long(addr, 16), sym, long(size, 16)])

                # register symbols #
                for item in sorted(jmapTable, key=lambda x: x[0]):
                    addr, sym, size = item
                    self.jmapAddrTable.append(addr)
                    self.jmapSymTable.append([sym, size, "??"])
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn(
                    (
                        "failed to load JIT-compiled symbols "
                        "from '%s' for %s(%s)"
                    )
                    % (self.jmapPath, self.comm, self.pid),
                    reason=True,
                )
                return False

            return True

    def loadSymbols(self, onlyFunc=True, onlyExec=True, tpath=None):
        ret = self.updateProcMap(onlyExec=onlyExec)
        if not ret and self.fileList:
            return False

        # update overlayfs info #
        if not self.overlayfsList:
            self.overlayfsList = SysMgr.getOverlayfsInfo(self.pid)

        # update JIT-compiled symbols #
        if "JITSYM" in SysMgr.environList:
            self.loadJITSymbols()

        # check STOP condition #
        if "STOPTARGET" in SysMgr.environList:
            needStop = True
            self.stop()
        else:
            needStop = False

        # get file list #
        targetFileList, exceptFileList = SysMgr.getTargetFileList()

        # register default libraries #
        for fpath in list(self.pmap):
            # update start address #
            startAddr = self.pmap[fpath]["vstart"]
            if self.startAddr is None:
                self.startAddr = startAddr
            elif self.startAddr > startAddr:
                self.startAddr = startAddr

            # update load status #
            fname = os.path.basename(fpath)
            if fname.startswith("ld-"):
                self.dftBpFileList[fpath] = 0
            elif fname.startswith("libc-") or fname == "libc.so":
                self.libcLoaded = True
                self.dftBpFileList[fpath] = 0
            elif fname.startswith("libpthread"):
                self.dftBpFileList[fpath] = 0

        # load memory-mapped file objects #
        ret = False
        printLog = True
        prevRss = 0
        for mfile in list(self.pmap):
            try:
                # check file filter #
                if SysMgr.isExceptFile(mfile, targetFileList, exceptFileList):
                    continue

                # check file validation #
                if (
                    mfile in ElfAnalyzer.cachedFiles
                    or not FileAnalyzer.isValidFile(mfile, special=True)
                ):
                    continue
                # check the target file #
                elif tpath and mfile == tpath:
                    pass
                # skip files except for the target file #
                elif "LAZYCACHE" in SysMgr.environList:
                    continue

                # load object #
                if mfile in ElfAnalyzer.preloadedFiles:
                    eobj = ElfAnalyzer.preloadedFiles[mfile]
                    ElfAnalyzer.cachedFiles[mfile] = eobj
                else:
                    eobj = ElfAnalyzer.getObject(
                        mfile, overlay=self.overlayfsList, log=printLog
                    )
                if eobj:
                    ret = True
                    eobj.mergeSymTable(onlyFunc=onlyFunc)
                    if printLog:
                        printLog = False

                continue

                # print ELF object size on RAM for test #
                curRss = Debugger.tracerInstance.getMemUsage(False)
                rssDiff = UtilMgr.convSize2Unit(curRss - prevRss)
                print(UtilMgr.convColor("[%s] %s" % (mfile, rssDiff), "CYAN"))
                prevRss = curRss
            except SystemExit:
                # continue target #
                if needStop:
                    self.cont()

                sys.exit(0)
            except:
                pass

        # update file and addr lists from memory map #
        self.fileList, self.addrList = self.getAddrLists()
        if not self.fileList:
            SysMgr.printWarn("failed to get file list on memory map")

        # continue target #
        if needStop:
            self.cont()

        return ret

    @staticmethod
    def getRealOffsetInfo(fileList, filePath):
        magicstr = SysMgr.magicStr
        totalDiff = 0

        origPath, number = filePath.split(magicstr)
        if not number:
            return origPath, fileList[origPath]["startAddr"], 0

        number = long(number)
        prevPath = curPath = None

        # walk to previous segments #
        while 1:
            if not prevPath:
                if number > 0:
                    prevPath = "%s%s%s" % (origPath, magicstr, number - 1)
                else:
                    prevPath = origPath
            else:
                prevPath = curPath

            curPath = "%s%s%s" % (origPath, magicstr, number)

            # add diff by hole #
            curStart = long(fileList[curPath]["vstart"])
            prevEnd = long(fileList[prevPath]["vend"])
            totalDiff += curStart - prevEnd

            if number == 0:
                break

            number -= 1

        # set startAddr and filePath to 1st segment's one #
        startAddr = fileList[origPath]["vstart"]
        filePath = origPath

        # disable diff by hole #
        totalDiff = 0

        return filePath, startAddr, totalDiff

    def getSymbolInfo(self, vaddr, onlyFunc=True, onlyExec=True):
        # get symbol info from cache list #
        if vaddr in self.symbolCacheList:
            return self.symbolCacheList[vaddr]

        # check exceptional cases #
        if not vaddr or vaddr < 0:
            return None
        elif not self.pid:
            SysMgr.printErr("failed to get PID to get symbol")
            return None
        elif vaddr in self.failedAddrList and self.failedAddrList[vaddr]:
            return None

        # open memory map file #
        if not self.mapFd:
            self.mapFd = FileAnalyzer.getMapFd(self.pid)
            if not self.mapFd:
                return None

        # scan process memory map #
        if self.needMapScan:
            if self.loadSymbols(onlyFunc=onlyFunc, onlyExec=onlyExec):
                self.updateBpList(verb=False)
            self.needMapScan = False

        # get file name by address #
        fname = self.getFileFastFromMap(vaddr)
        if not fname:
            # set variable to rescan process map #
            self.needMapScan = True

            # print error message and return #
            if SysMgr.warnEnable:
                SysMgr.printWarn(
                    (
                        "failed to get symbol via %s for %s(%s) "
                        "because of no file mapped to the address"
                    )
                    % (hex(vaddr).rstrip("L"), self.comm, self.pid)
                )

            return None

        # get real offset for memory hole #
        totalDiff = 0
        if SysMgr.magicStr in fname:
            fname, vstart, totalDiff = Debugger.getRealOffsetInfo(
                self.pmap, fname
            )
        else:
            vstart = self.pmap[fname]["vstart"]

        vend = self.pmap[fname]["vend"]

        # get offset in the file #
        offset = vaddr - vstart + totalDiff
        if offset < 0:
            # update anon map #
            if not self.amap:
                self.amap = FileAnalyzer.getAnonMapInfo(self.pid, self.mapFd)

            # check JIT-compiled code #
            for addrs in self.amap:
                if not addrs[0] <= vaddr <= addrs[1]:
                    continue

                # get JIT-compiled symbol #
                symInfo = self.getJITSymbolByOffset(vaddr)
                if symInfo[0] != "??":
                    # set path #
                    if symInfo[2] == "??":
                        path = "JIT"
                    else:
                        path = symInfo[2]

                    # return symbol info #
                    ret = [symInfo[0], path, "??", "??", "??", "??"]
                    self.symbolCacheList[vaddr] = ret
                    return ret

                # convert address #
                if SysMgr.showAll:
                    addr = hex(vaddr).rstrip("L")
                else:
                    addr = "JIT"

                # return #
                return [addr, "JIT", "??", "??", "??", "??"]

            # set variable to rescan process map #
            self.needMapScan = True

            # register failed address #
            if vaddr in self.failedAddrList:
                self.failedAddrList[vaddr] = True
            else:
                self.failedAddrList.setdefault(vaddr, False)

            # print error message and return #
            if SysMgr.warnEnable:
                SysMgr.printWarn(
                    (
                        "failed to get symbol via %s for %s(%s) "
                        "because of wrong offset"
                    )
                    % (hex(vaddr).rstrip("L"), self.comm, self.pid)
                )

            return None

        # remove suffix in file name #
        fname = fname.rsplit(SysMgr.magicStr, 1)[0]

        # get ELF object #
        fcache = ElfAnalyzer.getObject(fname)
        if not fcache:
            ret = ["??", fname, "??", "??", "??", "??"]
            self.symbolCacheList[vaddr] = ret
            return ret

        # check executable type #
        if not ElfAnalyzer.isRelocFile(fname):
            offset = vaddr

        # get native symbol #
        try:
            sym, size = fcache.getSymbolByOffset(offset, onlyFunc=onlyFunc)
            ret = [sym, fname, hex(offset).rstrip("L"), vstart, vend, size]
            self.symbolCacheList[vaddr] = ret
            return ret
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn(
                "failed to get symbol via %s for %s(%s)"
                % (hex(offset).rstrip("L"), self.comm, self.pid),
                reason=True,
            )

            # return #
            return [hex(offset).rstrip("L"), fname, "??", "??", "??", "??"]

    def getAddrLists(self):
        fileList = []
        addrList = []

        if not self.pmap:
            return [], []

        for f, item in sorted(self.pmap.items(), key=lambda x: x[1]["vend"]):
            fileList.append(f)
            addrList.append(item["vend"])

        return fileList, addrList

    def getFileFromMap(self, vaddr):
        if not self.pmap:
            return None

        try:
            vaddr = long(vaddr)
        except:
            return None

        for fname, value in self.pmap.items():
            if value["vstart"] == vaddr:
                return fname

        return None

    def getFileFastFromMap(self, vaddr):
        try:
            idx = UtilMgr.bisect_left(self.addrList, vaddr)
            return self.fileList[idx]
        except SystemExit:
            sys.exit(0)
        except:
            return None

    def printContext(
        self,
        regs=True,
        bt=True,
        sig=True,
        deref=True,
        args=None,
        newline=False,
        brief=False,
    ):

        # check skip condition #
        if not regs and not bt:
            return
        elif not SysMgr.printEnable:
            return
        elif "NOCONTEXT" in SysMgr.environList:
            return

        if newline:
            prefix = "\n"
        else:
            prefix = ""

        try:
            taskInfo = "%s(%s)" % (self.comm, self.pid)
        except:
            taskInfo = "??(%s)" % self.pid

        isPrinted = False

        # update regs #
        if self.pc is None:
            self.updateRegs()

        # print register #
        if regs:
            # set regsdict #
            self.regsDict = self.regs._getdict()

            if not isPrinted:
                SysMgr.addPrint("%s%s\n" % (prefix, twoLine))
                isPrinted = True

            SysMgr.addPrint("\tRegister Info [%s]\n%s\n" % (taskInfo, oneLine))

            regstr = ""
            regstrline = ""
            for reg, val in sorted(self.regsDict.items()):
                rvalue = ""
                if deref and val:
                    rvalue = self.readMem(val, verb=False)
                    if rvalue:
                        try:
                            rvalue = '"%s"' % rvalue.decode("utf-8")
                            rvalue = re.sub("\W+", "", rvalue)
                        except SystemExit:
                            sys.exit(0)
                        except:
                            rvalue = hex(UtilMgr.convStr2Word(rvalue))
                            rvalue = rvalue.rstrip("L")

                # convert reference value #
                if rvalue:
                    rvalue = "[%s]" % rvalue
                else:
                    rvalue = ""

                # print register value #
                if brief:
                    newline = "%s(0x%x%s)" % (reg, val, rvalue)
                    if len(newline) + len(regstrline) >= SysMgr.ttyCols:
                        if regstr:
                            regstr = "%s\n%s" % (regstr, regstrline)
                        else:
                            regstr = regstrline
                        regstrline = newline
                    else:
                        if regstrline:
                            regstrline = "%s | %s" % (regstrline, newline)
                        else:
                            regstrline = newline
                else:
                    SysMgr.addPrint("%13s: 0x%x%s\n" % (reg, val, rvalue))

            if brief:
                SysMgr.addPrint("%s\n%s\n" % (regstr, regstrline))
            SysMgr.addPrint("%s\n" % twoLine)

        # print signal #
        if sig:
            try:
                signame = ConfigMgr.SIG_LIST[long(self.lastSig)]
                SysMgr.addPrint(
                    "\tSignal Info [%s]\n%s\n" % (taskInfo, oneLine)
                )
                SysMgr.addPrint(
                    "%s: %s\n%s\n" % (self.lastSig, signame, twoLine)
                )
            except SystemExit:
                sys.exit(0)
            except:
                pass

        # print backtrace #
        if bt:
            backtrace = self.getBacktrace(cur=True, force=True)
            if backtrace:
                if not isPrinted:
                    SysMgr.addPrint("%s%s\n" % (prefix, twoLine))
                    isPrinted = True

                SysMgr.addPrint(
                    "\tBacktrace Info [%s]\n%s\n" % (taskInfo, oneLine)
                )

                for item in backtrace:
                    if item[0]:
                        addr = hex(item[0]).rstrip("L")
                    else:
                        addr = item[0]

                    SysMgr.addPrint("%s(%s)[%s]\n" % (addr, item[1], item[2]))

                SysMgr.addPrint("%s\n" % twoLine)

        if SysMgr.outPath:
            self.callPrint.append(SysMgr.bufferString)
        else:
            SysMgr.doPrint(newline=False, clear=True)

        SysMgr.clearPrint()

    def setRet(self, val, temp=False, update=False):
        try:
            if temp:
                ret = setattr(self.tempRegs, self.retreg, val)
            else:
                ret = setattr(self.regs, self.retreg, val)

            if update:
                self.setRegs()
                self.updateRegs()

            return True
        except SystemExit:
            sys.exit(0)
        except:
            return False

    def getRet(self, temp=False):
        try:
            if temp:
                ret = getattr(self.tempRegs, self.retreg)
            else:
                ret = getattr(self.regs, self.retreg)

            return c_long(ret).value
        except SystemExit:
            sys.exit(0)
        except:
            return None

    def setSyscall(self, syscall):
        try:
            if UtilMgr.isNumber(syscall):
                nrSyscall = long(syscall)
            else:
                nrSyscall = SysMgr.getNrSyscall(syscall)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to get syscall number", reason=True)
            sys.exit(-1)

        self.setRegs()

    def getNrSyscall(self):
        try:
            return getattr(self.regs, self.sysreg)
        except SystemExit:
            sys.exit(0)
        except:
            return None

    def addCall(self, sym):
        self.callstack.append([self.sp, sym])

    def updateStack(self, sym):
        while 1:
            if not self.callstack:
                return
            elif (
                self.callstack[-1][0] > self.sp
                or self.callstack[-1][0] >= self.prevSp
                or self.callstack[-1][1] == sym
            ):
                self.callstack.pop()
            else:
                return

    def popSample(self, sym):
        if self.callList:
            self.callList.pop(-1)

        if sym in self.callTable:
            self.callTable[sym]["cnt"] -= 1
            if self.callTable[sym]["cnt"] == 0:
                self.callTable.pop(sym, None)

        if self.totalCall > 0:
            self.totalCall -= 1

    def addSample(
        self, sym, filename, realtime=False, bt=None, err=None, elapsed=None
    ):
        if not self.runStatus and Debugger.envFlags["EXCEPTWAIT"]:
            return

        # increase err count #
        if err:
            try:
                self.callTable[sym]["err"] += 1
            except:
                pass
            finally:
                return

        # add sample #
        if not realtime:
            self.callList.append([sym, self.current, filename])
            return

        self.totalCall += 1

        if Debugger.envFlags["ONLYSYM"] and bt and type(bt[0]) is list:
            # remove anonymous symbol #
            while 1:
                if sym != "??":
                    break
                elif not bt:
                    break
                elif bt[0][1] == "??":
                    bt.pop(0)
                    continue
                else:
                    sym = bt[0][1]
                    filename = bt[0][2]
                    bt.pop(0)
                    break

            # remove contiguous symbol #
            while 1:
                if not bt or not SysMgr.showAll:
                    break
                elif sym == bt[0][1] and filename == bt[0][2]:
                    bt.pop(0)
                    continue
                break

        # convert anonymous symbol to filename to prevent call table corruption #
        if sym == "??":
            sym = filename

        # check wait status #
        if not self.runStatus and self.mode in ("sample", "kernel", "pycall"):
            sym = "WAIT{%s}" % sym

        # add backtrace #
        if bt:
            btStr = self.getBtStr(bt)
        else:
            btStr = None

        # add symbol table #
        if sym in self.callTable:
            self.callTable[sym]["cnt"] += 1
        else:
            self.callTable[sym] = {
                "cnt": 1,
                "path": filename,
                "err": 0,
                "backtrace": {},
                "elapsed": 0.0,
                "min": 0.0,
                "max": 0.0,
            }

        # increase count of callstack #
        if btStr:
            try:
                self.callTable[sym]["backtrace"][btStr] += 1
            except SystemExit:
                sys.exit(0)
            except:
                if sym in self.callTable:
                    self.callTable[sym]["backtrace"][btStr] = 1

        # calculate elapsed time #
        if elapsed:
            self.callTable[sym]["elapsed"] += elapsed
            if (
                self.callTable[sym]["min"] == 0
                or self.callTable[sym]["min"] > elapsed
            ):
                self.callTable[sym]["min"] = elapsed
            if (
                self.callTable[sym]["max"] == 0
                or self.callTable[sym]["max"] < elapsed
            ):
                self.callTable[sym]["max"] = elapsed

        # add file table #
        try:
            self.fileTable[filename]["cnt"] += 1
        except:
            self.fileTable[filename] = {"cnt": 1}

        if not SysMgr.outPath:
            return

        self.callList.append([sym, self.current, filename])

    def checkSymbol(self, sym, newline=False, exceptFilter=[]):
        if not SysMgr.customCmd or SysMgr.outPath:
            return

        # check filter #
        needNewline = False
        isPaused = False
        for cmd in SysMgr.customCmd:
            item = cmd.split("|")
            # skip #
            if not UtilMgr.isValidStr(sym, [item[0]]):
                continue
            # set pause flag #
            elif len(item) == 1:
                isPaused = True
                break

            for command in item[1:]:
                # check skip condition #
                if not exceptFilter:
                    pass
                elif UtilMgr.isValidStr(command, exceptFilter):
                    continue

                # execute commands #
                args = self.readArgs()
                self.executeCmd([command], sym, None, args)
                needNewline = True

        # check return #
        if not isPaused:
            if needNewline:
                SysMgr.printPipe()
            return

        sys.stdout.write("\n")

        if SysMgr.showAll:
            # print register set #
            self.printContext(newline=newline)

        # disable timer #
        signal.alarm(0)

        SysMgr.waitUserInput(
            wait=0, msg="\n%s() is detected! press ENTER to continue..." % sym
        )

        # enable timer #
        SysMgr.updateTimer()

    def getBtStr(self, bt, indent=None, maximum=0, force=False):
        if not force and self.btStr:
            return self.btStr
        elif not bt:
            self.btStr = ""
            return self.btStr

        btStr = ""
        prevSym = None
        prevFile = None
        cnt = 0

        # set default indentation #
        if indent is None:
            indentStr = " " * self.indentLen
            pos = self.indentLen
        else:
            indentStr = " " * indent
            pos = indent

        # set maximum depth #
        if maximum == 0:
            if len(oneLine) < SysMgr.ttyCols:
                maximum = len(oneLine)
            else:
                maximum = SysMgr.ttyCols

        # get arg list #
        if self.btArgList and "PRINTBTARG" in SysMgr.environList:
            argList = list(self.btArgList)
        else:
            argList = []

        if type(bt[0]) is list:
            isUser = True
        else:
            isUser = False

        for item in bt:
            # user #
            if isUser:
                # get symbol and file info #
                if item[1] == item[2] == "??":
                    sym = hex(item[0]).rstrip("L")
                else:
                    sym = item[1]

                fname = item[2]
            # kernel #
            else:
                # skip no symbol item #
                if not item:
                    continue

                sample = item.split("] ", 1)
                sym = sample[1] if len(sample) > 1 else item
                fname = "KERNEL"

            # remove redundant symbols #
            if prevSym == sym and prevFile == fname:
                cnt += 1
                continue
            else:
                prevSym = sym
                prevFile = fname

            # check redundant symbols #
            if cnt > 0:
                cntStr = " * %s" % (cnt + 1)
                cnt = 0
            else:
                cntStr = ""

            # add arg list #
            if argList and argList[0][0][0] == item[0]:
                args = ["%s=%s" % (arg[2], arg[4]) for arg in argList[0]]
                sym = "%s(%s)" % (sym, ", ".join(args))
                argList.pop(0)

            # build a new string #
            newStr = " <- %s[%s]%s" % (sym, fname, cntStr)
            if btStr and len(newStr) + pos > maximum:
                newStr = "\n%s%s" % (indentStr, newStr)
                pos = len(newStr) - 1
            else:
                pos += len(newStr)

            # add a symbol to backtrace #
            btStr += newStr

        if btStr == "":
            self.btStr = "??"
        else:
            self.btStr = btStr

        return self.btStr

    def startSamplingKernel(self):
        while 1:
            # wait for sampling time #
            if self.runStatus:
                time.sleep(self.sampleTime)
            else:
                time.sleep(self.sampleTime * 2)

            try:
                self.stackFd.seek(0)
                sample = self.stackFd.read()
                if sample:
                    sample = sample.split("\n")
            except SystemExit:
                sys.exit(0)
            except:
                if not SysMgr.isAlive(self.pid):
                    SysMgr.printErr(
                        "%s(%s) is terminated" % (self.comm, self.pid)
                    )
                    sys.exit(0)
                elif not self.stackFd:
                    self.stackFd = open(
                        "%s/%s/stack" % (SysMgr.procPath, self.pid)
                    )
                else:
                    SysMgr.printErr(
                        "failed to read kernel stack data for %s(%s)"
                        % (self.comm, self.pid),
                        True,
                    )
                    continue

                sample = self.stackFd.read()
                if sample:
                    sample = sample.split("\n")

            if sample:
                sym = sample[0].split("] ", 1)
                sym = sym[1] if len(sym) > 1 else sample[0]
                if len(sample) > 1:
                    bt = sample[1:]
                else:
                    bt = None
            else:
                sym = "N/A"
                bt = None

            # add sample #
            self.addSample(sym, "KERNEL", realtime=True, bt=bt)

            # check run status #
            self.runStatus = self.isInRun()

        sys.exit(0)

    def checkInterval(self):
        # continue target thread #
        if self.cont(check=True) < 0:
            sys.exit(-1)

        self.traceStatus = False

        # wait for sampling time #
        if self.runStatus:
            self.sampleTime = self.sampleTimeOrig
        elif not self.multi or not self.incrementalSampling:
            self.sampleTime = self.sampleTimeOrig * 2
        else:
            # increase wait time by 2 #
            if self.sampleTimeMax > self.sampleTime:
                self.sampleTime *= 2
            # limit the maximum wait time #
            else:
                self.sampleTime = self.sampleTimeMax
        time.sleep(self.sampleTime)

        # update run status #
        self.runStatus = self.isInRun()

        # stop target thread #
        if self.stop() < 0:
            sys.exit(-1)

        self.traceStatus = True

    def getBacktrace(self, limit=32, cur=False, force=False, native=False):
        restored = True

        try:
            if not force and self.btList:
                return self.btList
            # prevent recursive backtrace call #
            elif self.inBacktrace:
                return

            # set initial flags #
            self.inBacktrace = True

            # return special language callstack #
            if not native:
                # python callstack #
                if Debugger.envFlags["PYSTACK"]:
                    btList = self.handlePycall(retbt=True)
                    if btList:
                        self.btList = btList
                        return self.btList

            # check libcorkscrew #
            if not SysMgr.libcorkscrewObj:
                SysMgr.initLibcorkscrew()

            # unwind stack using libcorkscrew #
            if SysMgr.libcorkscrewObj != -1:
                # get backtrace buffer #
                if not self.csBtList:
                    self.csBtList = (self.btframe * limit)()
                backtrace = self.csBtList

                libcc = SysMgr.libcorkscrewObj

                # get context #
                if not self.csContext:
                    self.csContext = libcc.load_ptrace_context(c_int(self.pid))
                context = self.csContext

                # get backtrace #
                frames = libcc.unwind_backtrace_ptrace(
                    c_int(self.pid),
                    context,
                    byref(backtrace),
                    c_size_t(0),
                    c_size_t(limit),
                )
                if frames <= 0:
                    return []

                """
                # pick addresses from structs #
                btList = []
                for idx in xrange(frames):
                    offset = idx * sizeof(self.btframe)
                    obj = cast(addressof(backtrace)+offset, self.btframe_ptr)
                    addr = obj.contents.absolute_pc
                    btList.append(addr)

                # convert addresses to symbols #
                self.btList = self.convAddrList(btList)
                """

                # get symbol buffer #
                if not self.csBtSymList:
                    self.csBtSymList = (self.btsym * limit)()
                btsyms = self.csBtSymList
                symsAddr = addressof(btsyms)

                # convert addresses to symbols #
                libcc.get_backtrace_symbols_ptrace(
                    context, byref(backtrace), c_size_t(frames), byref(btsyms)
                )

                # pick symbols from structs #
                self.btList = []
                for idx in xrange(frames):
                    offset = idx * sizeof(self.btsym)
                    obj = cast(symsAddr + offset, self.btsym_ptr).contents

                    # get symbol #
                    if obj.demangled_name:
                        symbol = obj.demangled_name.decode()
                    elif obj.symbol_name:
                        symbol = obj.symbol_name.decode()
                    else:
                        symbol = "??"

                    # get fname #
                    if obj.map_name:
                        fname = obj.map_name.decode()
                    else:
                        fname = "??"

                    self.btList.append([obj.relative_pc, symbol, fname])
            # unwind stack using DWARF #
            elif SysMgr.dwarfEnable:
                # init arg list for backtraces #
                argList = []
                self.btArgList = []

                # backup registers #
                self.backupRegs(bt=True)
                restored = False

                # load symbols from new objects #
                if not self.startAddr:
                    self.loadSymbols()

                # set start address #
                ip = self.pc
                if self.mode == "break":
                    ip -= self.prevInstOffset

                # add current symbol #
                if cur:
                    btList = [ip]
                else:
                    btList = []

                while 1:
                    # get return address #
                    raddr = self.getRetAddr(ip, argList)
                    if not raddr:
                        break

                    # add return addresses #
                    if type(raddr) is list:
                        btList += raddr
                    else:
                        btList.append(raddr)

                    # check max length #
                    if len(btList) >= limit:
                        break

                    # update IP #
                    ip = raddr

                # update backtrace args #
                self.btArgList = argList

                # convert addresses to symbols #
                self.btList = self.convAddrList(btList)

                # print backtrace for debugging #
                if False:
                    print("\n" + oneLine)
                    for item in self.btList:
                        print(item)
                    print(oneLine + "\n")

                # restore registers #
                self.restoreRegs(bt=True)
                restored = True
            # unwind stack using FP/SP #
            else:
                # load symbols from new objects #
                if not self.startAddr:
                    self.loadSymbols()

                self.btList = self.backtrace[SysMgr.arch](limit, cur)

            return self.btList
        except SystemExit:
            sys.exit(0)
        except:
            if self.pc:
                addr = " from %x" % self.pc
            else:
                addr = ""

            SysMgr.printWarn("failed to get backtrace%s" % addr, reason=True)

            if SysMgr.dwarfEnable and not restored:
                # restore registers #
                self.restoreRegs(bt=True)

            return []
        finally:
            self.inBacktrace = False

    def readWord(self, targetAddr):
        if not targetAddr:
            return None
        elif targetAddr % ConfigMgr.wordSize == 0:
            return self.accessMem(self.peekIdx, targetAddr)
        else:
            return self.readMem(targetAddr, retWord=True)

    def getWordFromStack(self, addr, update=False):
        if update:
            self.getStack()

        # verify address #
        if not self.startStack <= addr <= self.endStack + addr:
            return None

        offset = addr - self.startStack

        word = self.stack[offset : offset + ConfigMgr.wordSize]
        if ConfigMgr.wordSize == 8:
            return struct.unpack("Q", word)[0]
        else:
            return struct.unpack("I", word)[0]

    def getStack(self):
        if not self.pmap:
            return False

        stack = self.pmap["stack"]
        self.startStack = stack["vstart"]
        self.endStack = stack["vend"] + ConfigMgr.wordSize
        self.stackSize = self.endStack - self.startStack
        self.stack = self.readMem(self.startStack, self.stackSize)

        if self.stack:
            return True
        else:
            return False

    def getRetAddr(self, vaddr, argList=[], onlyArg=False, cur=False):
        # get file name #
        fname = self.getFileFastFromMap(vaddr)
        if not fname:
            return None

        # get file offset #
        ret = self.getSymbolInfo(vaddr)
        if not ret:
            return None
        elif ret[1] == "JIT":
            # return addr from FP #
            bts = self.backtrace[SysMgr.arch](cur=False)
            if bts:
                return [item[0] for item in bts]
            else:
                return None
        elif ret[2] == "??":
            return None

        sym = ret[0]
        foffset = long(ret[2], 16)

        # get ELF object #
        fobj = ElfAnalyzer.getObject(fname)
        if not fobj:
            return None

        # check DWARF info #
        if "dwarf" not in fobj.attr or not fobj.attr["dwarf"]["CFAIndex"]:
            SysMgr.printWarn(
                "failed to find DWARF info for %s(%s) in %s"
                % (sym, hex(foffset), fname)
            )

            # return addr from FP #
            bts = self.backtrace[SysMgr.arch](cur=False)
            if bts:
                return [item[0] for item in bts]
            else:
                return None

        # get function address from CFA index table #
        dwarf = fobj.attr["dwarf"]
        idx = UtilMgr.bisect_left(dwarf["CFAIndex"], foffset) - 1
        faddr = dwarf["CFAIndex"][idx]
        # TODO: check function scope from faddr #
        if not faddr in dwarf["CFATable"]:
            SysMgr.printWarn(
                "failed to find CFA table info for %s(%s) in %s"
                % (sym, hex(faddr), fname)
            )
            return None

        # get effective CFA rule #
        rule = None
        for line in dwarf["CFATable"][faddr]:
            if foffset < line["pc"]:
                break
            rule = line
        if not rule or not "cfa" in rule:
            SysMgr.printWarn(
                "failed to find CFA rule info for %s(%s) in %s"
                % (sym, hex(foffset), fname)
            )
            if vaddr != self.lr:
                return self.lr
            else:
                return None

        # define index for CFA member variables #
        regIdx = ElfAnalyzer.CFARule.REG
        offsetIdx = ElfAnalyzer.CFARule.OFFSET
        exprIdx = ElfAnalyzer.CFARule.EXPR

        # get CFA #
        cfaInfo = rule["cfa"]
        if cfaInfo[exprIdx]:
            return None
        reg = ConfigMgr.regList[cfaInfo[regIdx]]
        regval = getattr(self.regs, reg)
        offset = cfaInfo[offsetIdx]
        cfa = regval + offset

        # get parameter #
        if "info" in dwarf and faddr in dwarf["info"]:
            # frame base #
            if "frame" in dwarf["info"][faddr]:
                base = dwarf["info"][faddr]["frame"]
            else:
                base = 0

            # params #
            paramList = []
            if "param" in dwarf["info"][faddr]:
                abbrevIdx = dwarf["info"][faddr]["abbrev"]
                abbrev = dwarf["abbrev"][abbrevIdx]

                for item in dwarf["info"][faddr]["param"]:
                    # name #
                    if "name" in abbrev[item]:
                        name = abbrev[item]["name"]
                    else:
                        name = "??"

                    # size #
                    if "size" in abbrev[item]:
                        size = abbrev[item]["size"]
                    else:
                        size = 0

                    # type element #
                    typeName = ""
                    if "type" in abbrev[item]:
                        typeNum = abbrev[item]["type"]
                    else:
                        typeNum = -1

                    # get full type #
                    if typeNum in ElfAnalyzer.cachedTypes:
                        (
                            typeName,
                            size,
                            decChar,
                            isAddr,
                        ) = ElfAnalyzer.cachedTypes[typeNum]
                    else:
                        typeName = ""
                        typeNumOrig = typeNum

                        # build type name #
                        while 1:
                            if not typeNum in abbrev:
                                break

                            # add a type attribute #
                            if "name" in abbrev[typeNum]:
                                typeName = "%s %s" % (
                                    typeName,
                                    abbrev[typeNum]["name"],
                                )

                            # size #
                            if "size" in abbrev[typeNum]:
                                size = abbrev[typeNum]["size"]

                            if not "type" in abbrev[typeNum]:
                                break

                            typeNum = abbrev[typeNum]["type"]

                        # remove heading space #
                        typeName = typeName.lstrip()

                        # decide size and decoding type #
                        isAddr = False
                        if size == 0:
                            decChar = None
                        elif typeName.startswith("*"):
                            size = ConfigMgr.wordSize
                            decChar = self.decChar
                            isAddr = True
                        elif "unsigned" in typeName:
                            decChar = ConfigMgr.UNPACK_TYPE["U%s" % size]
                        else:
                            decChar = ConfigMgr.UNPACK_TYPE["S%s" % size]

                        # save type info #
                        ElfAnalyzer.cachedTypes[typeNumOrig] = [
                            typeName,
                            size,
                            decChar,
                            isAddr,
                        ]

                    # location #
                    paramVal = "??"
                    if size == 0:
                        pass
                    elif cur and len(paramList) < 6:
                        paramVal = self.readArgs()[len(paramList)]
                        if isAddr:
                            paramVal = hex(paramVal)
                    elif "loc" in abbrev[item]:
                        # sec_offset #
                        # TODO: handle this attribute #
                        if type(abbrev[item]["loc"]) is long:
                            paramVal = "??"
                        # exprloc(reg) #
                        # TODO: handle this attribute #
                        elif len(abbrev[item]["loc"]) == 1:
                            paramVal = "??"
                        # exprloc(offset) #
                        elif len(abbrev[item]["loc"]) == 2:
                            paramAddr = abbrev[item]["loc"][1]
                            paramVal = self.readMem(cfa + paramAddr, size)
                            paramVal = struct.unpack(decChar, paramVal)[0]
                            if isAddr:
                                paramVal = hex(paramVal)

                    # add a parameter info #
                    paramList.append([vaddr, typeName, name, size, paramVal])

                argList.append(paramList)

        # check only argument requirement #
        if onlyArg:
            return None

        # recover registers #
        argIdx = ElfAnalyzer.RegisterRule.ARG
        for num, value in rule.items():
            try:
                long(num)
                reg = ConfigMgr.regList[num]
                offset = value[argIdx]
                if offset is None:
                    continue
                rval = self.readWord(cfa + offset)
                setattr(self.regs, reg, rval)
            except SystemExit:
                sys.exit(0)
            except:
                pass

        # get CFA offset for return address #
        pcIdx = ConfigMgr.pcRegIndex[SysMgr.arch]

        # update stack pointer for previous context #
        self.updateNamedRegs()
        self.setSP(cfa)

        # use specific register #
        if pcIdx in rule:
            roffset = rule[pcIdx][argIdx]
            if roffset is None:
                return None

            # calculate address for return address #
            raddr = cfa + roffset
        # just use LR #
        elif self.arch == "aarch64" or self.arch == "arm":
            return self.lr
        # no more frame #
        else:
            return None

        # return next IP from stack #
        try:
            return self.readWord(raddr)
        except SystemExit:
            sys.exit(0)
        except:
            return None

    def getBacktrace_X86(self, limit=32, cur=False):
        nextFp = self.fp
        btList = []

        if cur and self.pc:
            btList.insert(0, self.pc)

        # update stack for target #
        readaheadStack = False
        if readaheadStack:
            self.getStack()

        # get 1st address from stack #
        targetAddr = self.sp
        if readaheadStack:
            value = self.getWordFromStack(targetAddr)
        else:
            value = self.readWord(targetAddr)

        if value > self.startAddr:
            btList.insert(0, value)

        while 1:
            if not nextFp or nextFp < self.sp:
                break

            # check max length #
            if len(btList) >= limit:
                break

            try:
                # get LR #
                targetAddr = nextFp + ConfigMgr.wordSize
                if targetAddr < self.startAddr:
                    break
                elif readaheadStack:
                    value = self.getWordFromStack(targetAddr)
                else:
                    value = self.readWord(targetAddr)

                # add call address #
                if value > 0:
                    try:
                        btList.append(long(value))
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass

                # get FP #
                if readaheadStack:
                    nextFP = self.getWordFromStack(targetAddr)
                else:
                    nextFp = self.readWord(nextFp)

                if nextFp < self.startAddr:
                    break
            except SystemExit:
                sys.exit(0)
            except:
                break

        return self.convAddrList(btList)

    def getBacktrace_ARM(self, limit=16, cur=False):
        nextFp = self.fp
        nextLr = self.lr

        if nextLr:
            btList = [nextLr]
        else:
            btList = []

        if cur and self.pc:
            btList.insert(0, self.pc)

        savedLr = nextLr

        while 1:
            # check max length #
            if len(btList) >= limit:
                break

            if not nextLr or not nextFp or nextLr & 0x1 or nextFp & 0x1:
                break

            try:
                # get LR #
                nextAddr = nextFp + ConfigMgr.wordSize
                if nextAddr < self.startAddr:
                    break
                else:
                    nextLr = self.readWord(nextAddr)

                # get FP #
                nextFp = self.readWord(nextFp)
                if nextFp < self.startAddr:
                    break
            except SystemExit:
                sys.exit(0)
            except:
                break

            # add address to list #
            if nextLr and savedLr != nextLr:
                btList.append(nextLr)
                savedLr = nextLr

        return self.convAddrList(btList)

    def getBacktrace_AARCH64(self, limit=32, cur=False):
        nextFp = self.fp
        nextLr = self.lr
        btList = [nextLr]

        if cur:
            btList.insert(0, self.pc)

        savedLr = nextLr

        # update stack for target #
        readaheadStack = False
        if readaheadStack:
            self.getStack()

        while 1:
            # check max length #
            if len(btList) >= limit:
                break

            if not nextLr or not nextFp or nextLr & 0x1 or nextFp & 0x1:
                break

            try:
                # get LR #
                nextAddr = nextFp + ConfigMgr.wordSize
                if nextAddr < self.startAddr:
                    break
                elif readaheadStack:
                    nextLr = self.getWordFromStack(nextAddr)
                else:
                    nextLr = self.readWord(nextAddr)

                # get FP #
                if nextFp < self.startAddr:
                    break
                elif readaheadStack:
                    nextFp = self.getWordFromStack(nextFp)
                else:
                    nextFp = self.readWord(nextFp)

                if nextFp <= 0:
                    break
            except SystemExit:
                sys.exit(0)
            except:
                break

            # add address to list #
            if savedLr != nextLr:
                btList.append(nextLr)
                savedLr = nextLr

        return self.convAddrList(btList)

    def convAddrList(self, btList):
        # get symbol and file from address #
        clist = []
        onlysym = Debugger.envFlags["ONLYSYM"]
        for addr in btList:
            res = self.getSymbolInfo(addr)
            if res:
                if res[0] == "??":
                    sym = res[2]
                else:
                    sym = res[0]

                # skip no symbol function #
                if onlysym and sym and sym.startswith("0x"):
                    continue

                clist.append([addr, sym, res[1]])
            elif not onlysym:
                clist.append([addr, "??", "??"])

        return clist

    def updateBpStat(self, sym, tdiff=0):
        # apply stat #
        try:
            prev, ttotal, tmin, tmax = self.bpcallStat[sym]

            if tdiff == 0:
                self.interDiff = tdiff = self.vdiff - prev
            ttotal += tdiff

            if tmax < tdiff:
                tmax = tdiff

            if tmin == 0 or tmin > tdiff:
                tmin = tdiff

            self.bpcallStat[sym] = [self.vdiff, ttotal, tmin, tmax]

            # save interval for stdev #
            if Debugger.envFlags["STDEV"]:
                self.bpcallInterStat.setdefault(sym, [])
                self.bpcallInterStat[sym].append(tdiff)
        except SystemExit:
            sys.exit(0)
        except:
            self.bpcallStat[sym] = [self.vdiff, 0, 0, 0]

    def getTraceBtStr(
        self,
        diffstr,
        tinfo,
        cont=True,
        cur=False,
        addBt=[],
        backtrace=[],
        python=False,
    ):
        def _getCommonPos(backtrace):
            # check contiguous tree presentation #
            commonPos = -1
            if not cont:
                return commonPos

            try:
                for item in reversed(self.prevStack):
                    # same pos at same level #
                    if item == backtrace[commonPos]:
                        commonPos -= 1
                        continue
                    # different item #
                    else:
                        break

                # out of stack #
                if backtrace[commonPos][1] == self.prevSym:
                    commonPos -= 1
            except SystemExit:
                sys.exit(0)
            except:
                pass

            return commonPos

        # get backtrace #
        if not backtrace:
            backtrace = self.getBacktrace(cur=cur)
            if addBt:
                commonIdx = 0
                for idx, item in enumerate(addBt):
                    if len(backtrace) > idx and item == backtrace[idx][0]:
                        commonIdx = idx + 1
                        continue
                    else:
                        break
                if commonIdx < len(addBt):
                    addBtList = self.convAddrList(addBt[commonIdx:])
                    backtrace = addBtList + backtrace

        # get indent info #
        depth = len(backtrace)
        diffindent = " " * len(diffstr)
        tinfoindent = " " * len(tinfo)

        # calculate common depth for previous stack #
        commonPos = _getCommonPos(backtrace)
        if commonPos == -1:
            commonPos = 0
            stack = backtrace
        else:
            if python:
                if SysMgr.pyFuncFilter:
                    commonPos += 1
            else:
                if SysMgr.customCmd:
                    commonPos += 1
            stack = backtrace[:commonPos]

        self.prevStack = backtrace

        # get arg list #
        if self.btArgList and "PRINTBTARG" in SysMgr.environList:
            argList = list(self.btArgList)
        else:
            argList = []

        btStr = ""
        for sidx, item in enumerate(reversed(stack)):
            # get arg list #
            if argList and argList[-1][0][0] == item[0]:
                args = "(%s)" % ", ".join(
                    ["%s=%s" % (arg[2], arg[4]) for arg in argList[-1]]
                )
                argList.pop()
            else:
                args = ""

            # add context to string #
            if python:
                btStr += "\n%s %s%s%s%s [%s:%s]" % (
                    diffindent,
                    tinfoindent,
                    (sidx - (commonPos)) * "  ",
                    item[1],
                    args,
                    item[2],
                    item[0],
                )
            else:
                btStr += "\n%s %s%s%s%s/%s [%s]" % (
                    diffindent,
                    tinfoindent,
                    (sidx - (commonPos)) * "  ",
                    item[1],
                    args,
                    hex(item[0]).rstrip("L"),
                    item[2],
                )

        return btStr, depth

    def runExecMode(self):
        # stop target #
        if not self.isStopped():
            self.stop()
            self.waitpid()

        # read registers for target #
        if not self.updateRegs():
            sys.exit(-1)

        # print context #
        if not "print" in SysMgr.customCmd:
            self.printContext(regs=SysMgr.showAll, newline=True)

        # read args #
        args = self.readArgs()

        # execute remote commands #
        for cmd in SysMgr.customCmd:
            self.executeCmd([cmd], sym=None, fname=None, args=args, force=True)

    def getBpContext(self, sym, addr, args, isRetBp):
        # set default symbol color #
        symColor = "GREEN"

        # convert args #
        if Debugger.envFlags["PRINTARG"]:
            args = []
            raddr = self.getRetAddr(addr, args, onlyArg=True, cur=True)
            if args:
                args = args[0]
            argstr = "(%s)" % ", ".join(
                ["%s=%s" % (arg[2], arg[4]) for arg in args]
            )
        # convert args #
        elif (
            Debugger.envFlags["CONVARG"]
            and sym.split("@", 1)[0] in ConfigMgr.SYSCALL_PROTOTYPES
        ):
            # convert args #
            self.syscall = sym.split("@", 1)[0]
            self.args = []
            self.updateSyscallArgs()

            # convert numbers #
            args = [
                hex(arg[2]).rstrip("L")
                if type(arg[2]) is long
                else str(arg[2])
                for arg in self.args
            ]
            argstr = "(%s)" % ",".join(args)

            # change symbol color #
            symColor = "OKBLUE"
        # build arguments string #
        elif Debugger.envFlags["NOARG"]:
            argstr = ""
        else:
            argstr = "(%s)" % ",".join(
                list(map(lambda x: hex(x).rstrip("L"), args))
            )

        # set task info #
        if self.multi:
            tinfo = "%s(%s) " % (self.comm, self.pid)
        else:
            tinfo = ""

        # get diff time #
        diffstr = "%3.6f" % self.vdiff

        # build backtrace #
        if SysMgr.funcDepth > 0:
            # add return address to backtrace #
            addBt = [addr] if isRetBp else []

            # get backtrace tree #
            btstr, depth = self.getTraceBtStr(
                diffstr, tinfo, not SysMgr.showAll, addBt=addBt
            )

            indent = "  " * depth
        else:
            btstr = indent = ""

        return tinfo, diffstr, args, argstr, btstr, indent, symColor

    def printBpContext(self, sym, addr, fname, checkArg, origPC):
        # check return type #
        isRetBp = True if sym.endswith(Debugger.RETSTR) else False

        # skip loader functions #
        if (
            Debugger.envFlags["EXCEPTLD"]
            and fname
            and os.path.basename(fname).startswith("ld-")
        ):
            SysMgr.printWarn("skip printing %s in %s" % (sym, fname))
            return isRetBp

        # read args #
        args = self.readArgs()

        # check filter #
        filterRes = True
        filterCmd = self.bpList[addr]["filter"]
        if not self.checkFilterCond(filterCmd, args, sym, fname):
            if not Debugger.envFlags["COMPLETECALL"]:
                return isRetBp
            filterRes = False

        # top mode #
        if self.isRealtime:
            if SysMgr.funcDepth > 0:
                backtrace = self.getBacktrace()
            else:
                backtrace = None

            # handle return filter #
            if isRetBp:
                (
                    etime,
                    elapsed,
                    hasRetFilter,
                    skip,
                    retcmd,
                ) = self.handleRetBpFilter(sym)
                if skip:
                    return isRetBp

                # update elapsed time #
                diff = float(elapsed.lstrip("/"))
                self.updateBpStat(sym, diff)
            else:
                # update interval time #
                self.updateBpStat(sym)

            self.addSample(sym, fname, realtime=True, bt=backtrace)

            # add timeline segment #
            self.addTimelineInt(sym, self.btStr)

            return isRetBp

        # get context data #
        (
            tinfo,
            diffstr,
            args,
            argstr,
            btstr,
            indent,
            symColor,
        ) = self.getBpContext(sym, addr, args, isRetBp)

        # print return value #
        jsonData = {}
        elapsed = callString = retstr = ""
        etime = cmds = retcmd = None
        skip = hasRetFilter = False
        convColor = UtilMgr.convColor

        # handle breakpoint for return #
        if isRetBp:
            # get original symbol #
            origSym = sym[: -len(Debugger.RETSTR)]

            try:
                (
                    etime,
                    elapsed,
                    hasRetFilter,
                    skip,
                    retcmd,
                ) = self.handleRetBpFilter(sym)
                if not elapsed:
                    raise Exception()

                # get context string and remove breakpoint for return #
                retstr = self.handleRetBp(sym, fname, addr)

                # add previous symbol info #
                if not skip:
                    # get previous symbol info #
                    prevSymInfo = self.getSymbolInfo(addr)
                    if Debugger.envFlags["NORETBT"]:
                        addStr = ""
                    elif prevSymInfo:
                        try:
                            prevAddr = hex(prevSymInfo[3]).rstrip("L")
                        except SystemExit:
                            sys.exit(0)
                        except:
                            prevAddr = prevSymInfo[3]

                        prevSym = prevSymInfo[0]

                        if Debugger.envFlags["NOFILE"]:
                            prevFname = ""
                        else:
                            prevFname = " [%s]" % prevSymInfo[1]

                        addStr = " -> %s/%s%s" % (prevSym, prevAddr, prevFname)
                    else:
                        addStr = ""

                    # convert elapsed color #
                    origElapsed = elapsed.lstrip("/")
                    if etime > self.retTime:
                        elapsed = convColor(elapsed, "RED")
                    else:
                        elapsed = convColor(elapsed, "CYAN")

                    # build combined output #
                    if (
                        Debugger.envFlags["COMPLETECALL"]
                        and origSym in self.entryContext
                    ):
                        # get entry context #
                        entryData = self.entryContext[origSym].pop()
                        if not self.entryContext[origSym]:
                            self.entryContext.pop(origSym, None)

                        # combine contexts for both entry and exit #
                        if SysMgr.jsonEnable:
                            args = entryData["args"]
                            args = args[1:-1].split(",") if args else []
                            jsonData = {
                                "context": "complete",
                                "time": entryData["time"],
                                "args": args,
                                "file": entryData["file"],
                                "task": tinfo
                                if tinfo
                                else "%s(%s)" % (self.comm, self.pid),
                                "symbol": origSym,
                                "return": retstr.lstrip("="),
                                "elapsed": origElapsed,
                                "caller": addStr.lstrip("-> "),
                            }
                        else:
                            # build file path #
                            if Debugger.envFlags["NOFILE"]:
                                fnameStr = ""
                            else:
                                fnameStr = " [%s]" % entryData["file"]

                            callString = "\n%s %s%s%s%s%s%s%s%s" % (
                                entryData["time"],
                                tinfo,
                                indent,
                                convColor(origSym, symColor),
                                entryData["args"],
                                convColor(fnameStr, "YELLOW"),
                                convColor(retstr, "PINK"),
                                elapsed,
                                addStr,
                            )

                        # add timeline segment #
                        numElapsed = float(origElapsed)
                        self.addTimelineRet(origSym, numElapsed, btstr)

                    # build JSON output #
                    elif SysMgr.jsonEnable:
                        jsonData = {
                            "context": "exit",
                            "time": diffstr,
                            "task": tinfo
                            if tinfo
                            else "%s(%s)" % (self.comm, self.pid),
                            "symbol": sym,
                            "return": retstr.lstrip("="),
                            "elapsed": origElapsed,
                            "caller": addStr.lstrip("-> "),
                        }
                    # build string output #
                    else:
                        callString = "\n%s %s%s%s%s%s%s" % (
                            diffstr,
                            tinfo,
                            indent,
                            sym,
                            convColor(retstr, "PINK"),
                            elapsed,
                            addStr,
                        )
            except SystemExit:
                sys.exit(0)
            except:
                skip = True
                elapsed = ""
                isRetBp = False

            # check command #
            if origSym in self.retCmdList:
                cmds = self.retCmdList[origSym]
        else:
            # save entry context #
            if (
                Debugger.envFlags["COMPLETECALL"]
                and self.bpList[addr]["cmd"]
                and "getret" in self.bpList[addr]["cmd"]
            ):
                self.entryContext.setdefault(sym, [])
                self.entryContext[sym].append(
                    {"time": diffstr, "args": argstr, "file": fname}
                )
            # build JSON output #
            elif SysMgr.jsonEnable:
                args = argstr[1:-1].split(",") if argstr else []
                jsonData = {
                    "context": "entry",
                    "time": diffstr,
                    "task": tinfo
                    if tinfo
                    else "%s(%s)" % (self.comm, self.pid),
                    "symbol": sym,
                    "args": args,
                    "file": fname,
                }
            # build string output #
            else:
                # build file path #
                if Debugger.envFlags["NOFILE"]:
                    fnameStr = ""
                else:
                    fnameStr = " [%s]" % fname

                callString = "\n%s %s%s%s%s/%s%s%s" % (
                    diffstr,
                    tinfo,
                    indent,
                    convColor(sym, symColor),
                    elapsed,
                    hex(addr).rstrip("L"),
                    argstr,
                    convColor(fnameStr, "YELLOW"),
                )

                # add timeline segment #
                self.addTimelineInt(sym, btstr)

        # check filter result #
        if not filterRes:
            return isRetBp

        # print output #
        if not self.showStatus or sym in self.hiddenList:
            pass
        elif jsonData:
            # add backtrace #
            if btstr:
                jsonData["backtrace"] = btstr.lstrip().split("\n")

            # print output #
            SysMgr.printPipe(
                UtilMgr.convDict2Str(jsonData, pretty=self.pretty), flush=True
            )
        elif callString:
            # update interval between calls #
            if Debugger.envFlags["INTERCALL"]:
                self.updateBpStat(sym)
                interdiffStr = " [%.6f]" % self.interDiff
                if self.interDiff > self.retTime:
                    callString += UtilMgr.convColor(interdiffStr, "RED")
                else:
                    callString += UtilMgr.convColor(interdiffStr, "CYAN")
                self.interDiff = 0

            # add backtrace #
            if btstr:
                callString = btstr + callString

            # add entry log to return filter #
            if sym in self.retFilterList:
                self.retFilterList[sym][1] = callString

            # task filter #
            if (
                self.execCmd
                and SysMgr.filterGroup
                and not UtilMgr.isValidStr(self.comm)
            ):
                pass
            # file output #
            elif SysMgr.outPath:
                self.addSample(sym, fname, realtime=True, elapsed=etime)

                # print history #
                self.callPrint.append(callString.rstrip())

                # print to stdout #
                if SysMgr.streamEnable:
                    sys.stdout.write(callString)
            # console output #
            else:
                SysMgr.printPipe(callString, newline=False, flush=True)

        # handle rest jobs #
        if jsonData or callString or Debugger.envFlags["COMPLETECALL"]:
            # handle repeat command #
            if isRetBp and origPC != self.pc:
                self.handleBp(True, checkArg)
                return isRetBp

            # check command #
            if self.bpList[addr]["cmd"]:
                self.bpList[addr]["cmd"] = self.executeCmd(
                    self.bpList[addr]["cmd"], sym=sym, fname=fname, args=args
                )

        # check skip condition #
        if skip:
            return isRetBp

        # execute commands #
        if cmds:
            self.executeCmd(cmds, sym, fname, args)
        if retcmd:
            self.executeCmd([retcmd], sym, fname, args)

        return isRetBp

    def handleBp(self, printStat=False, checkArg=None):
        # read registers for target #
        if not self.updateRegs():
            sys.exit(-1)

        # set rewind address #
        origPC = self.pc
        addr = self.pc - self.prevInstOffset
        origAddr = addr

        # get breakpoint addr #
        if addr not in self.bpList:
            # handle strange instructions such like ARM THUMB #
            if addr + 1 in self.bpList:
                addr += 1
            elif addr - 1 in self.bpList:
                addr -= 1
            elif self.loadSymbols():
                self.updateBpList(verb=False)

            # get symbol Info #
            ret = self.getSymbolInfo(addr)
            sym = ret[0]
            fname = ret[1]
            if not UtilMgr.isNumber(ret[2]):
                SysMgr.printErr(
                    "failed to recognize address %s in %s for %s(%s)"
                    % (hex(addr), fname, self.comm, self.pid)
                )

                PageAnalyzer.printMemoryArea(
                    self.pid, comm=self.comm, lastLine=True
                )

                sys.exit(-1)
            else:
                offset = long(ret[2], 16)

            # load original data from storage #
            origWord = self.loadInst(fname, offset)

            # register this lost breakpoint #
            self.injectBp(addr, sym, fname=fname, origWord=origWord)

            # check memory map again #
            if addr not in self.bpList:
                SysMgr.printErr(
                    (
                        "failed to find %s in the breakpoint list "
                        "for %s(%s), update ELF caches in %s"
                    )
                    % (
                        hex(origAddr).rstrip("L"),
                        self.comm,
                        self.pid,
                        SysMgr.cacheDirPath,
                    )
                )

                sys.exit(-1)

        # pick breakpoint info #
        sym = self.bpList[addr]["symbol"]
        fname = self.bpList[addr]["filename"]
        isRetBp = False

        # update memory map and load new ELF objects #
        if self.needMapScan or (
            not self.libcLoaded
            and (sym.startswith("__libc_") or sym.startswith("malloc"))
        ):
            # load symbols from new objects #
            if self.loadSymbols():
                self.updateBpList(verb=False)

            # set update flag #
            self.needMapScan = False

        # check calls for memory map update #
        if sym.startswith("mmap"):
            self.needMapScan = True
        elif sym.startswith("munmap"):
            unmapAddr = self.readArgs()[0]
            self.removeBpFileByAddr(unmapAddr)
            self.needMapScan = True

        # update comm #
        if self.needUpdateComm():
            comm = SysMgr.getComm(self.pid, cache=True, save=True)
            if self.comm != comm:
                self.comm = comm
                Debugger.updateCommFlag(False)

        # check changing-comm calls #
        if sym == "pthread_setname_np":
            Debugger.updateCommFlag()
        elif sym == "prctl":
            param = self.readArgs()[0]
            if (
                param in ConfigMgr.PRCTL_TYPE
                and ConfigMgr.PRCTL_TYPE[param] == "PR_SET_NAME"
            ):
                Debugger.updateCommFlag()

        # set print flag #
        if self.mode != "break":
            printStat = False

        # print context info #
        if (
            printStat
            and not addr in self.exceptBpList
            and not fname in self.exceptBpFileList
            and (not self.targetBpFileList or fname in self.targetBpFileList)
        ):
            isRetBp = self.printBpContext(sym, addr, fname, checkArg, origPC)

        # apply register set to rewind IP #
        if self.pc == origPC:
            self.setPC(addr)
            self.setRegs()

        # save symbol #
        self.prevSym = sym

        # lock between processes #
        if addr in self.bpList:
            nrLock = self.bpList[addr]["number"]
        else:
            nrLock = -1
        self.lock(nrLock)

        # remove breakpoint #
        ret = self.removeBp(addr)
        if not ret:
            self.unlock(nrLock)
            return

        # check reinstall flag #
        reins = ret[2]
        if not reins:
            self.unlock(nrLock)
            return
        # check recursive call #
        elif isRetBp and sym.endswith(Debugger.RETSTR) in self.entryTime:
            self.unlock(nrLock)
            return

        # execute original instructions #
        if self.pc == origPC:
            # continue processing an instruction #
            if self.arch == "arm":
                # PTRACE_SINGLESTEP is removed on ARM #
                self.cont()
                self.stop()
            else:
                ret = self.ptrace(self.singlestepCmd)
                if ret != 0:
                    SysMgr.printWarn(
                        "failed to singlestep %s(%s) because %s"
                        % (self.comm, self.pid, self.errmsg)
                    )

            # check process #
            ret = self.waitpid()
            self.checkStat(ret, reason="of injection failure")

        # setup this breakpoint again #
        self.injectBp(addr, sym, fname=fname, reins=reins)

        # unlock between processes #
        self.unlock(nrLock)

        # handle pycall #
        if (
            self.mode == "pybreak"
            and sym.rstrip(Debugger.RETSTR) == SysMgr.pyCallFunc
        ):
            self.handlePyTrap(sym, fname, addr)

    def handleTrapEvent(self, stat):
        # check thread status #
        if self.status == "wait":
            return
        # check thread sequence #
        elif Debugger.targetNums and not self.myNum in Debugger.targetNums:
            return

        previous = self.status
        self.status = self.mode

        # usercall #
        if self.mode == "sample" or self.mode == "inst":
            self.handleUsercall()
        # breakcall #
        elif self.isBreakMode:
            printEnable = SysMgr.printEnable

            # block signal #
            SysMgr.blockSignal(act="block")

            while 1:
                try:
                    self.handleBp(printStat=printEnable)
                    break
                except SystemExit:
                    sys.exit(0)
                except Exception as ex:
                    SysMgr.printWarn(
                        "failed to handle breakpoint for %s(%s)"
                        % (self.comm, self.pid),
                        True,
                        reason=True,
                    )
                    if type(ex).__name__ == "IOError":
                        sys.exit(-1)

            # continue target #
            if self.cont(check=True) < 0:
                sys.exit(-1)

            # unblock signal #
            SysMgr.blockSignal(act="unblock")
        # pycall #
        elif self.mode == "pycall":
            self.handlePycall()

        self.status = previous

    def handleExit(self):
        # update status #
        self.traceStatus = False

        # read return code #
        ret = self.getEventMsg()

        # get task info #
        tinfo = "%s(%s)" % (self.comm, self.pid)

        # get diff time #
        self.vdiff = self.current - self.dstart
        diffstr = "%3.6f" % self.vdiff

        exitStr = UtilMgr.convColor(
            "+++ exited %s with %s +++" % (tinfo, ret), "RED"
        )

        exitStr = "\n%s %s" % (diffstr, exitStr)

        if SysMgr.outPath:
            # print history #
            if SysMgr.showAll:
                self.callPrint.append(exitStr.rstrip())

            # print to stdout #
            if SysMgr.streamEnable:
                sys.stdout.write("%s\n" % exitStr)
        else:
            SysMgr.printPipe(exitStr, flush=True)

    def handleSignal(self, sig, warn=False, taskinfo=False):
        if not SysMgr.printEnable:
            return

        # check signal filter #
        if self.mode == "signal" and SysMgr.customCmd:
            if not ConfigMgr.SIG_LIST[sig] in list(
                map(str.upper, SysMgr.customCmd)
            ):
                return

        # get task info #
        if taskinfo or self.multi:
            tinfo = "%s(%s) " % (self.comm, self.pid)
        else:
            tinfo = ""

        # get signal name #
        try:
            name = ConfigMgr.SIG_LIST[sig]
            signame = UtilMgr.convColor(name, "GREEN", 7, "left")
        except SystemExit:
            sys.exit(0)
        except:
            name = sig
            signame = "UNKNOWN(%s)" % sig

        # get diff time #
        diff = self.vdiff
        if diff > 0:
            callString = "%3.6f %s[%s]" % (
                diff,
                tinfo,
                "{0:<7}".format(signame),
            )
        else:
            callString = "%s[%s]" % (tinfo, "{0:<7}".format(signame))

        # get signal info #
        ret = self.getSigInfo()
        if ret == 0:
            if self.sigObj.si_errno > 0:
                errinfo = "si_errno=%s, " % UtilMgr.convColor(
                    self.sigObj.si_errno, "RED"
                )
            else:
                errinfo = ""

            # code #
            try:
                code = self.sigObj.si_code
                if self.sigObj.si_code in ConfigMgr.SI_CODE:
                    code = ConfigMgr.SI_CODE[code]
                elif name == "SIGCHLD":
                    code = ConfigMgr.SIGCHLD_CODE[code]
                elif name == "SIGTRAP":
                    code = ConfigMgr.SIGTRAP_CODE[code]
                elif name == "SIGSEGV":
                    code = ConfigMgr.SIGSEGV_CODE[code]
                elif name == "SIGILL":
                    code = ConfigMgr.SIGILL_CODE[code]
                elif name == "SIGFPE":
                    code = ConfigMgr.SIGFPE_CODE[code]
                else:
                    raise Exception("no signal code")
            except:
                pass

            callString = "%s {%ssi_code=%s" % (callString, errinfo, code)

            if self.sigObj._sifields:
                fields = self.sigObj._sifields._sigchld
                if name == "SIGSEGV":
                    callString = ("%s si_addr=%s}") % (
                        callString,
                        hex(fields.pid),
                    )
                else:
                    # pid #
                    try:
                        pid = fields.pid
                        if SysMgr.showAll and pid > 0:
                            comm = SysMgr.getComm(pid, cache=True, save=True)
                            if comm:
                                pid = "%s(%s)" % (comm, pid)
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass

                    # uid #
                    try:
                        uid = fields.uid
                        if SysMgr.showAll:
                            userData = SysMgr.sysInstance.userData
                            uid = "%s(%s)" % (userData[str(uid)]["name"], uid)
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass

                    if name == "SIGCHLD":
                        # status #
                        try:
                            if code == "CLD_EXITED":
                                status = fields.status
                            else:
                                status = ConfigMgr.SIG_LIST[fields.status]
                        except:
                            status = fields.status

                        callString = (
                            "%s si_pid=%s, si_uid=%s, si_status=%s "
                            "si_utime=%s, si_stime=%s}"
                        ) % (
                            callString,
                            pid,
                            uid,
                            status,
                            fields.utime,
                            fields.stime,
                        )
                    else:
                        callString = "%s si_pid=%s, si_uid=%s}" % (
                            callString,
                            pid,
                            uid,
                        )
            else:
                callString = "%s}" % callString
        else:
            # check alive #
            if not self.isAlive():
                sys.exit(-1)

        # print context #
        if warn:
            SysMgr.printWarn(callString)
        else:
            SysMgr.printPipe(callString)

        # add timeline segment #
        self.addTimelineInt(name, callString)

        # print backtrace #
        if not self.isRealtime and SysMgr.funcDepth > 0:
            # read registers for target #
            if not self.updateRegs():
                sys.exit(-1)

            self.printContext(regs=False, sig=False)

        # handle watch command #
        if "WATCHLOG" in SysMgr.environList:
            # check exit condition #
            SysMgr.checkLogCond(
                name, SysMgr.environList["WATCHLOG"][0].split("+")
            )

    def initPyEnv(self):
        # check python version for target #
        if not self.checkPyVer():
            sys.exit(-1)

        # set target info #
        procInfo = "%s(%s)" % (self.comm, self.pid)

        # get memory map by binary type #
        pyPath = FileAnalyzer.getMapFilePath(self.pid, "libpython")
        if not pyPath:
            pyPath = FileAnalyzer.getMapFilePath(self.pid, "python")
            if not pyPath:
                SysMgr.printErr(
                    "failed to find python binary for %s" % procInfo
                )
                sys.exit(-1)

        # remove anonymous symbol #
        Debugger.envFlags["ONLYSYM"] = True

        # check native function for python call #
        addr = self.getAddrBySymbol(SysMgr.pyCallFunc)
        if not addr:
            return False

        # get symbol for interpretr #
        pySym = ["_PyThreadState_Current", "_PyRuntime"]
        symbolInfo = SysMgr.getProcAddrBySymbol(
            self.pid, pySym, fileFilter=[pyPath]
        )
        if not symbolInfo:
            SysMgr.printErr(
                "failed to find '%s' symbol for %s" % (pySym, procInfo)
            )
            sys.exit(-1)
        elif len(symbolInfo) > 1:
            SysMgr.printErr(
                "found multiple symbols [ %s ] for %s"
                % (", ".join(list(symbolInfo)), procInfo)
            )
            sys.exit(-1)

        # set pthread ID for target task #
        threadList = SysMgr.getThreadList(self.pid)
        if len(threadList) == 1:
            self.pthreadid = -1
        else:
            self.pthreadid = self.remoteUsercall("pthread_self")

        # get address for interpretr #
        pySymbol = list(symbolInfo.values())[0]
        self.pyAddr = long(pySymbol[2], 16)

        # version >= 3.7 #
        if pySymbol[3] == "_PyRuntime":
            # get offset for PyinterpretrState head #
            if ConfigMgr.wordSize == 4:
                SysMgr.printErr(
                    "not supported yet for PyThreadState on 32-bit"
                )
                sys.exit(-1)
            else:
                self.pyAddr += 32

        return True

    def checkPyVer(self):
        # check exe #
        if not hasattr(self, "exe"):
            self.exe = SysMgr.getExeName(self.pid)

        # compare python binary #
        myExe = SysMgr.getExeName(SysMgr.pid)
        if myExe != self.exe:
            SysMgr.printErr(
                (
                    "different python executable '%s' for %s(%s) "
                    "and '%s' for %s(%s)"
                )
                % (
                    myExe,
                    SysMgr.comm,
                    SysMgr.pid,
                    self.exe,
                    self.comm,
                    self.pid,
                )
            )
            return False
        else:
            return True

    def readPyState32(self, addr):
        SysMgr.printErr("not implemented yet")
        sys.exit(-1)

    def readPyState64(self, addr):
        frameList = {}

        while 1:
            if sys.version_info >= (3, 7):
                tstate_head = self.readMem(addr + 8)

                PyThreadState = struct.unpack("Q", tstate_head)[0]
                if PyThreadState == 0:
                    addr += 8
                    continue

                PyThreadState = self.readMem(PyThreadState, 216)
                if not PyThreadState:
                    break

                (
                    prevp,
                    nextp,
                    interp,
                    framep,
                    recursion_depth,
                    overflowed,
                    recursion_critical,
                    stackcheck_counter,
                    tracing,
                    use_tracing,
                    c_profilefunc,
                    c_tracefunc,
                    c_profileobj,
                    c_traceobj,
                    curexc_type,
                    curexc_value,
                    curexc_traceback,
                    exc_type,
                    exc_value,
                    exc_traceback,
                    previous_item,
                    exec_info,
                    dictp,
                    gilstate_counter,
                    async_exc,
                    thread_id,
                    trash_delete_nesting,
                    trash_delete_later,
                    on_delete,
                    on_delete_data,
                ) = struct.unpack(
                    "QQQQibbiiiQQQQQQQQQQQQQiQLiQQQ", PyThreadState
                )

            elif sys.version_info >= (3, 0):
                PyThreadState = self.readMem(addr, 192)
                if not PyThreadState:
                    break

                (
                    prevp,
                    nextp,
                    interp,
                    framep,
                    recursion_depth,
                    overflowed,
                    recursion_critical,
                    tracing,
                    use_tracing,
                    c_profilefunc,
                    c_tracefunc,
                    c_profileobj,
                    c_traceobj,
                    curexc_type,
                    curexc_value,
                    curexc_traceback,
                    exc_type,
                    exc_value,
                    exc_traceback,
                    dictp,
                    gilstate_counter,
                    async_exc,
                    thread_id,
                    trash_delete_nesting,
                    trash_delete_later,
                    on_delete,
                    on_delete_data,
                ) = struct.unpack("QQQQibbiiQQQQQQQQQQQiQliQQQ", PyThreadState)

            else:
                PyThreadState = self.readMem(addr, 168)
                if not PyThreadState:
                    break

                (
                    nextp,
                    interp,
                    framep,
                    recursion_depth,
                    tracing,
                    use_tracing,
                    c_profilefunc,
                    c_tracefunc,
                    c_profileobj,
                    c_traceobj,
                    curexc_type,
                    curexc_value,
                    curexc_traceback,
                    exc_type,
                    exc_value,
                    exc_traceback,
                    dictp,
                    tick_counter,
                    gilstate_counter,
                    async_exc,
                    thread_id,
                    trash_delete_nesting,
                    trash_delete_later,
                ) = struct.unpack("QQQiiiQQQQQQQQQQQiiQliQ", PyThreadState)

            # add frame address #
            frameList[thread_id] = framep

            if nextp == 0:
                break
            else:
                addr = nextp

        return frameList

    def readPyFrame32(self, addr):
        SysMgr.printErr("not implemented yet")
        sys.exit(-1)

    def readPyFrame64(self, addr):
        # read PyFrameObject #
        if sys.version_info >= (3, 7):
            PyFrameObject = self.readMem(addr, 112)
            (
                ob_refcnt,
                ob_type,
                ob_size,
                f_back,
                f_code,
                f_builtins,
                f_globals,
                f_locals,
                f_valuestack,
                f_stacktop,
                f_trace,
                f_trace_lines,
                f_trace_opcodes,
                f_gen,
                f_lasti,
                f_lineno,
            ) = struct.unpack("IQQQQQQQQQQbbQii", PyFrameObject)
        else:
            PyFrameObject = self.readMem(addr, 128)
            (
                ob_refcnt,
                ob_type,
                ob_size,
                f_back,
                f_code,
                f_builtins,
                f_globals,
                f_locals,
                f_valuestack,
                f_stacktop,
                f_trace,
                f_exc_type,
                f_exc_value,
                f_exc_traceback,
                f_tstate,
                f_lasti,
                f_lineno,
            ) = struct.unpack("IQQQQQQQQQQQQQQii", PyFrameObject)

        # read PyCodeObject #
        if sys.version_info >= (3, 8, 0):
            PyCodeObject = self.readMem(f_code, 144)
            (
                ob_refcnt,
                ob_type,
                co_argcount,
                co_posonlyargcount,
                co_kwonlyargcount,
                co_nlocals,
                co_stacksize,
                co_flags,
                co_firstlineno,
                co_code,
                co_consts,
                co_names,
                co_varnames,
                co_freevars,
                co_cellvars,
                co_cell2args,
                co_filename,
                co_name,
                co_lnotab,
                co_zomebiframe,
                co_wearreflist,
            ) = struct.unpack("IQIIIIIIIQQQQQQQQQQQQ", PyCodeObject)
        elif sys.version_info >= (3, 0):
            PyCodeObject = self.readMem(f_code, 136)
            (
                ob_refcnt,
                ob_type,
                co_argcount,
                co_kwonlyargcount,
                co_nlocals,
                co_stacksize,
                co_flags,
                co_firstlineno,
                co_code,
                co_consts,
                co_names,
                co_varnames,
                co_freevars,
                co_cellvars,
                co_cell2args,
                co_filename,
                co_name,
                co_lnotab,
                co_zomebiframe,
                co_wearreflist,
            ) = struct.unpack("IQIIIIIIQQQQQQQQQQQQ", PyCodeObject)
        else:
            PyCodeObject = self.readMem(f_code, 128)
            (
                ob_refcnt,
                ob_type,
                co_argcount,
                co_nlocals,
                co_stacksize,
                co_flags,
                co_code,
                co_consts,
                co_names,
                co_varnames,
                co_freevars,
                co_cellvars,
                co_filename,
                co_name,
                co_firstlineno,
                co_lnotab,
                co_zomebiframe,
                co_wearreflist,
            ) = struct.unpack("IQIIIIQQQQQQQQIQQQ", PyCodeObject)

        return f_back, f_lineno, f_code, co_name, co_filename

    def readPyStr32(self, addr):
        SysMgr.printErr("not implemented yet")
        sys.exit(-1)

    def readPyStr64(self, addr):
        PyStringObject = self.readMem(addr, 24)

        ob_refcnt, ob_type, ob_size = struct.unpack("IQQ", PyStringObject)

        if sys.version_info >= (3, 0):
            return self.readMem(addr + 48, ob_size).decode()
        else:
            return self.readMem(addr + 36, ob_size)

    def readPyStack(self, framep, depth):
        bt = []
        lastAddr = None
        lastName = None
        lastFile = None

        while 1:
            # read PyFrameObject #
            f_back, f_lineno, f_code, co_name, co_filename = self.readPyFrame(
                framep
            )

            # read context #
            if f_code in self.pyFrameCache:
                name, filename = self.pyFrameCache[f_code]
            else:
                # read name #
                name = self.readPyStr(co_name)

                # read filename #
                filename = self.readPyStr(co_filename)

            # cache frame #
            self.pyFrameCache[f_code] = [name, filename]

            # handle call info #
            if not lastName:
                lastAddr = f_lineno
                lastName = name
                lastFile = filename
            else:
                bt.append([f_lineno, name, filename])

            # check last frame #
            if depth <= len(bt) or f_back == 0:
                break

            framep = f_back

        return bt, lastAddr, lastName, lastFile

    def handlePyTrap(self, sym, fname, addr):
        """
        PyObject* _Py_HOT_FUNCTION_PyEval_EvalFrameDefault(
            PyThreadState *tstate, PyFrameObject *f, int throwflag)

        PyObject* PyEval_EvalFrame(PyFrameObject *f)
        """

        # set context flag #
        if Debugger.pyElapsed >= 0 and sym.endswith(Debugger.RETSTR):
            isRet = True
        else:
            isRet = False

        # return context #
        if isRet:
            self.handleRetBp(sym, fname, addr)
            if not self.prevPySym:
                return

            sym = sym.rstrip(Debugger.RETSTR)
            if not sym in self.entryTime:
                return
        # entry context #
        else:
            # get pointer to PyFrameObject #
            framep = self.readArgs()[0]

            # read frames #
            try:
                bt, line, call, fname = self.readPyStack(
                    framep, SysMgr.funcDepth
                )

                # save context #
                self.prevPySym = call
                self.prevPyFile = fname
                self.prevPyLine = line
                self.prevPyBt = bt
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "failed to get python stack for %s(%s)"
                    % (self.comm, self.pid),
                    True,
                )
                return

            # check filter #
            if SysMgr.pyFuncFilter and not UtilMgr.isValidStr(
                call, SysMgr.pyFuncFilter
            ):
                return

            # set the breakpoint for return #
            if Debugger.pyElapsed >= 0:
                self.setRetBp(sym, fname, ["getret"])

        # trace mode #
        if self.multi:
            tinfo = "%s(%s) " % (self.comm, self.pid)
        else:
            tinfo = ""

        # get diff time #
        diffstr = "%3.6f" % self.vdiff

        convColor = UtilMgr.convColor
        jsonData = {}
        callString = ""

        # build backtrace #
        if isRet:
            btstr = ""
            entry = self.entryTime[sym].pop()
            etime = self.vdiff - entry
            elapsed = "/%.6f" % etime
            if etime >= Debugger.pyElapsed:
                elapsed = convColor(elapsed, "CYAN")

            if self.prevPySym in self.prevPyIndent:
                indent = self.prevPyIndent[self.prevPySym].pop()
                if not self.prevPyIndent[self.prevPySym]:
                    self.prevPyIndent.pop(self.prevPySym, None)
            else:
                indent = ""

            # remove entry timestamp from list #
            if not self.entryTime[sym]:
                self.entryTime.pop(sym, None)

            sym += Debugger.RETSTR

            # build JSON output #
            if SysMgr.jsonEnable:
                jsonData = {
                    "time": diffstr,
                    "task": tinfo
                    if tinfo
                    else "%s(%s)" % (self.comm, self.pid),
                    "symbol": self.prevPySym,
                    "elapsed": elapsed.lstrip("/"),
                    "file": self.prevPyFile,
                    "line": self.prevPyLine,
                }
            # build string output #
            else:
                callString = "\n%s %s%s%s%s [%s:%s]" % (
                    diffstr,
                    tinfo,
                    indent,
                    self.prevPySym,
                    elapsed,
                    self.prevPyFile,
                    self.prevPyLine,
                )

            # add timeline segment #
            if (
                Debugger.envFlags["TIMELINE"]
                and not Debugger.envFlags["INTERCALL"]
            ):
                pySym = "%s[%s]" % (self.prevPySym, self.prevPyFile)
                pyBtStr = self.getBtStr(self.prevPyBt)
                self.addTimelineRet(pySym, etime, pyBtStr)

            # initialize previous symbol #
            call = self.prevPySym
            self.prevPySym = None
        else:
            if bt and SysMgr.funcDepth > 0:
                if SysMgr.showAll:
                    cont = False
                else:
                    cont = True

                # get backtrace tree #
                btstr, depth = self.getTraceBtStr(
                    diffstr, tinfo, cont, backtrace=bt, python=True
                )

                indent = "  " * depth

                # save indent #
                self.prevPyIndent.setdefault(call, [])
                self.prevPyIndent[call].append(indent)
            else:
                btstr = indent = ""

            elapsed = ""

            if SysMgr.jsonEnable:
                jsonData = {
                    "time": diffstr,
                    "task": tinfo
                    if tinfo
                    else "%s(%s)" % (self.comm, self.pid),
                    "symbol": call,
                    "file": fname,
                    "line": line,
                }
            else:
                # build current symbol string #
                callString = "\n%s %s%s%s%s [%s:%s]" % (
                    diffstr,
                    tinfo,
                    indent,
                    convColor(call, "GREEN"),
                    elapsed,
                    fname,
                    line,
                )

            # add timeline item #
            self.addTimelineInt(call, btstr)

        # add backtrace #
        if btstr:
            if jsonData:
                jsonData["backtrace"] = btstr.lstrip().split("\n")
            else:
                callString = btstr + callString

        # JSON output #
        if jsonData:
            SysMgr.printPipe(
                UtilMgr.convDict2Str(jsonData, pretty=self.pretty), flush=True
            )
        # file output #
        elif SysMgr.outPath:
            self.addSample(call, fname, realtime=True, elapsed=None)

            # print history #
            self.callPrint.append(callString.rstrip())

            # print to stdout #
            if SysMgr.streamEnable:
                sys.stdout.write(callString)
        # console output #
        else:
            SysMgr.printPipe(callString, newline=False, flush=True)

    def handlePycall(self, retbt=False):
        # check init status #
        if not self.pyAddr and not self.initPyEnv():
            return

        # read native call stack for version >= 3.7 #
        nativeStack = None
        if sys.version_info >= (3, 7):
            self.updateRegs()
            curSym = self.getSymbolInfo(self.pc)[0]
            if not curSym.startswith("_Py") and not curSym.startswith("Py"):
                nativeStack = self.getBacktrace(
                    SysMgr.funcDepth, cur=True, native=True
                )

        # read address for PyThreadState #
        pyThreadStateP = self.readMem(self.pyAddr)
        if not pyThreadStateP:
            return
        else:
            pyThreadStateP = struct.unpack("Q", pyThreadStateP)[0]

        # read native call stack for version < 3.7 #
        if sys.version_info < (3, 7) and not pyThreadStateP:
            self.handleUsercall()
            return

        # read PyThreadState #
        frameList = self.readPyState(pyThreadStateP)

        # TODO: get GIL usage by comparing thread_id with pthread_self() #
        nrThread = len(frameList)

        # get top-level frame for target task #
        if self.pthreadid == -1:
            framep = list(frameList.values())[0]
        elif not self.pthreadid in frameList:
            self.handleUsercall()
            return
        else:
            framep = frameList[self.pthreadid]

        # check frame pointer #
        if not framep:
            return

        # read frames #
        bt, lastAddr, lastName, lastFile = self.readPyStack(
            framep, SysMgr.funcDepth
        )

        # check filter #
        if SysMgr.pyFuncFilter and not UtilMgr.isValidStr(
            lastName, SysMgr.pyFuncFilter
        ):
            return

        # add last python call info #
        if nativeStack:
            bt.insert(0, [lastAddr, lastName, lastFile])

            # merge only native stack except for interpretr and python stack #
            if not Debugger.envFlags["INCNATIVE"]:
                lastIdx = 0
                for idx in xrange(len(nativeStack)):
                    lastIdx = idx
                    if nativeStack[idx][1] == SysMgr.pyCallFunc:
                        break
                nativeStack = nativeStack[:lastIdx]
                newStack = []
                for item in nativeStack:
                    sym = item[1]
                    if sym.startswith("_Py") or sym.startswith("Py"):
                        continue
                    newStack.append(item)
                nativeStack = newStack + bt
            # merge all native stack and python stack #
            else:
                for idx in xrange(len(nativeStack)):
                    if not bt:
                        break
                    if nativeStack[idx][1] == SysMgr.pyCallFunc:
                        nativeStack[idx] = bt.pop(0)

            # pick last call info #
            bt = nativeStack
            lastAddr, lastName, lastFile = bt.pop(0)

        # add a call stack sample #
        if retbt:
            return bt

        # add timeline segment #
        if Debugger.envFlags["TIMELINE"] and Debugger.envFlags["INTERCALL"]:
            pyBtStr = self.getBtStr(bt)
            self.addTimelineInt(lastName, pyBtStr)

        self.addSample(lastName, lastFile, realtime=True, bt=bt)

    def handleUsercall(self, update=True):
        # read registers for target #
        if update and not self.updateRegs():
            if not self.isAlive():
                sys.exit(-1)
            else:
                return

        # check previous function boundary #
        if not self.prevCallInfo or Debugger.envFlags["NOSAMPLECACHE"]:
            pass
        elif self.isRealtime:
            if self.pc == self.prevCallInfo[5]:
                self.addSample(
                    self.prevCallInfo[0],
                    self.prevCallInfo[1],
                    realtime=True,
                    bt=self.prevCallInfo[4],
                )
                return
        elif self.prevCallInfo[2] <= self.pc <= self.prevCallInfo[3]:
            if SysMgr.outPath:
                self.addSample(self.prevCallInfo[0], self.prevCallInfo[1])
            return

        # get symbol info #
        ret = self.getSymbolInfo(self.pc)
        if type(ret) is list:
            sym, fname, offset, fstart, fend, size = ret
        else:
            sym = ret
            fname = offset = fstart = fend = size = "??"

        # get backtrace #
        if self.isRealtime and SysMgr.funcDepth > 0:
            backtrace = self.getBacktrace(SysMgr.funcDepth)
        else:
            backtrace = None

        # print unknown call address #
        if fname == "??":
            sym = hex(self.pc).rstrip("L")
            self.addSample(sym, fname, realtime=self.isRealtime, bt=backtrace)
            return

        # check contiguous unknown symbol #
        if sym == "??" and self.prevCallInfo:
            if self.prevCallInfo[0] == sym:
                return
            elif self.prevCallInfo[0].startswith("mmap"):
                # enable memory update flag #
                self.needMapScan = True

        # convert args #
        if Debugger.envFlags["PRINTARG"]:
            args = []
            raddr = self.getRetAddr(self.pc, args, onlyArg=True)
            if args:
                args = args[0]
            sym += "(%s)" % ", ".join(
                ["%s=%s" % (arg[2], arg[4]) for arg in args]
            )

        # update callstack #
        if self.isRealtime:
            direction = ""
            symstr = sym

            # save current call info as previous call #
            self.prevCallInfo = [sym, fname, 0, 0, backtrace, self.pc]

            self.addSample(sym, fname, realtime=True, bt=backtrace)
        else:
            # get filter addr #
            try:
                # symbol range #
                if sym != "??":
                    vstart, vend = self.getRangeBySym(sym, fname)
                # anon range #
                else:
                    vstart, vend = self.getAnonRangeByOffset(offset, fname)
            except SystemExit:
                sys.exit(0)
            except:
                vstart = vend = 0

            # save current call info as previous call #
            self.prevCallInfo = [sym, fname, vstart, vend, backtrace, self.pc]

            self.updateStack(sym)

            # check call relationship #
            if not self.sp or not self.prevSp:
                direction = "(??)"
                self.addCall(sym)
            elif sym.startswith(".plt"):
                direction = "(--)"
                self.addCall(sym)
            elif self.sp > self.prevSp:
                direction = "(<-)"
            else:
                direction = "(->)"
                self.addCall(sym)

            symstr = (" " * 4 * len(self.callstack)) + sym

            # get time diff #
            diff = self.vdiff

            # build call string #
            callString = "%3.6f %s %s [%s + %s] [%s]" % (
                diff,
                symstr,
                direction,
                fname,
                offset,
                hex(self.sp).rstrip("L"),
            )

            # backup callString #
            self.prevCallString = callString

            # file output #
            if SysMgr.outPath:
                self.addSample(sym, fname)

                # print history #
                self.callPrint.append(callString)
            # console output #
            else:
                SysMgr.printPipe(
                    "\n%s" % callString, newline=False, flush=True
                )

        # backup register #
        self.prevSp = self.sp

        # check symbol #
        if SysMgr.customCmd:
            onlySym = sym.split("@")[0]
            self.checkSymbol(onlySym)

    def updateSyscallArgs(self, ref=True, retval=None):
        proto = ConfigMgr.SYSCALL_PROTOTYPES

        # get argument values from register #
        regstr = self.readArgs()

        # check prototype #
        if self.syscall in proto:
            # get data types #
            self.rettype, formats = proto[self.syscall]

            # get values #
            self.values = [value for value, format in zip(regstr, formats)]

        else:
            SysMgr.printWarn("failed to get prototype for %s" % self.syscall)

            self.values = []
            formats = []

        argset = {}
        seq = 0
        for value, aformat in zip(regstr, formats):
            # get type and name for an argument #
            argtype, argname = aformat
            argset[argname] = value

            # convert argument value #
            value = self.convSyscallParam(
                argtype,
                argname,
                value,
                seq,
                ref,
                argset,
                SysMgr.showAll,
                retval,
            )

            if value is not None:
                self.addArg(argtype, argname, value)

            seq += 1

    def convSyscallArgs(self, retval=None):
        args = []

        if self.isRealtime and not SysMgr.showAll:
            ref = False
        else:
            ref = True

        # converting arguments #
        self.updateSyscallArgs(ref, retval=retval)

        # pick values from argument list #
        for idx, arg in enumerate(self.args):
            if arg[0].endswith("*"):
                # convert pointer to values #
                if UtilMgr.isString(arg[2]):
                    text = UtilMgr.decodeArg(arg[2])

                    # check output length #
                    if (
                        not (SysMgr.outPath or SysMgr.showAll)
                        and len(text) > self.pbufsize
                    ):
                        text = r'"%s..."' % text[: self.pbufsize]
                    else:
                        text = r'"%s"' % text.rstrip()
                else:
                    text = arg[2]
            elif arg[0].endswith("int") or arg[0].endswith("long"):
                try:
                    if arg[2].isdigit():
                        text = long(arg[2])
                    else:
                        text = arg[2]
                except SystemExit:
                    sys.exit(0)
                except:
                    text = arg[2]
            else:
                text = arg[2]

            # append an arg to list #
            args.append(text)

        return args

    def isDeferCall(self, name):
        if name in ConfigMgr.SYSCALL_DEFFERABLE:
            return True
        else:
            return False

    def addTimelineRet(self, sym, diff, bts, gid=-1, sid=-1):
        if not Debugger.envFlags["TIMELINE"] or Debugger.envFlags["INTERCALL"]:
            return

        # get symbol id #
        if sid == -1:
            if not sym in self.timelineIdx:
                self.timelineIdx[sym] = str(len(self.timelineIdx))
            symidx = self.timelineIdx[sym]
        else:
            symidx = sid

        # get group id #
        if gid == -1:
            grpidx = symidx
        else:
            grpidx = gid

        # convert time unit to us #
        startTime = self.vdiff - diff
        endTime = self.vdiff
        endTime *= 1000000
        startTime *= 1000000

        # add timeline data #
        self.timelineData["segments"].append(
            {
                "group": grpidx,
                "text": sym,
                "id": symidx,
                "state": "S",
                "time_start": startTime,
                "time_end": endTime,
                "info": bts.strip() if bts else "",
            }
        )

    def addTimelineInt(self, sym, bts, gid=-1, sid=-1):
        # add timeline segment #
        if (
            not Debugger.envFlags["TIMELINE"]
            or not Debugger.envFlags["INTERCALL"]
        ):
            return

        # get symbol id #
        if sid == -1:
            if not sym in self.timelineIdx:
                self.timelineIdx[sym] = str(len(self.timelineIdx))
            symidx = self.timelineIdx[sym]
        else:
            symidx = sid

        # get group id #
        if gid == -1:
            grpidx = symidx
        else:
            grpidx = gid

        # convert time unit to us #
        startTime = self.vdiff * 1000000

        # add timeline data #
        self.timelineData["segments"].append(
            {
                "group": grpidx,
                "text": sym,
                "id": symidx,
                "state": "S",
                "time_start": startTime,
                "time_end": startTime + self.timeDuration,
                "info": bts.strip() if bts else "",
            }
        )

    def handleSyscallOutput(self, args, defer=False):
        # get diff time #
        diff = self.vdiff

        # get backtrace #
        if SysMgr.funcDepth > 0:
            # get backtrace list #
            backtrace = self.getBacktrace(limit=SysMgr.funcDepth, cur=True)

            # convert list to string #
            bts = self.getBtStr(backtrace)
            if bts:
                bts = "\n%s%s " % (" " * 20, bts)
        else:
            backtrace = None
            bts = ""

        # add timeline item #
        self.addTimelineInt(self.syscall, bts)

        # set filter flag #
        if Debugger.envFlags["ONLYOK"] or Debugger.envFlags["ONLYFAIL"]:
            filtered = True
        else:
            filtered = False

        # print context in JSON format #
        if SysMgr.jsonEnable and not self.isRealtime:
            # set context #
            jsonData = {
                "type": "enter",
                "time": self.current,
                "timediff": diff,
                "name": self.syscall,
                "tid": self.pid,
                "comm": self.comm,
                "backtrace": bts,
                "args": {},
            }

            # marshaling args #
            for idx, arg in enumerate(self.args):
                if args:
                    jsonData["args"][arg[1]] = args[idx]
                else:
                    jsonData["args"][arg[1]] = arg[2]

            # register entry context #
            if Debugger.envFlags["COMPLETECALL"]:
                self.entryContext[self.syscall] = jsonData
                return

            try:
                SysMgr.printPipe(
                    str(UtilMgr.convDict2Str(jsonData, pretty=self.pretty))
                )
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "failed to convert %s to JSON for marshalling"
                    % [jsonData],
                    True,
                )
            return

        callString = ""

        if not self.isRealtime or SysMgr.showAll:
            # convert args to string ##
            if Debugger.envFlags["NOARG"]:
                argText = ""
            elif args:
                argText = ", ".join(
                    hex(arg).rstrip("L")
                    if isinstance(arg, (int, long))
                    else str(arg)
                    for arg in args
                )
            else:
                argText = ", ".join(str(arg[2]) for arg in self.args)

            # build call string #
            if defer:
                callString = "%s)%s" % (argText, bts)
            else:
                syscall = UtilMgr.convColor(self.syscall, "GREEN")
                callString = "%3.6f %s(%s) %s(%s)%s" % (
                    diff,
                    self.comm,
                    self.pid,
                    syscall,
                    argText,
                    bts,
                )

            # handle call string for enter #
            if filtered:
                if defer:
                    self.bufferedStr += callString
                else:
                    self.bufferedStr = callString

        # print call info #
        if self.isRealtime:
            self.addSample(self.syscall, "??", realtime=True, bt=backtrace)

            if filtered:
                return
        elif SysMgr.outPath:
            self.addSample(self.syscall, "??", bt=backtrace)

            if filtered:
                return

            # print to stdout #
            if SysMgr.streamEnable:
                callString = "%s" % callString[: self.pbufsize]
                sys.stdout.write(callString)
        else:
            if filtered:
                return

            # trim string #
            if not SysMgr.showAll and SysMgr.funcDepth == 0:
                callString = "%s " % callString[: self.pbufsize]

            if defer:
                prefix = ""
            else:
                prefix = "\n"

            SysMgr.printPipe(
                prefix + callString,
                newline=False,
                flush=True,
                trim=False,
            )

        # file output #
        if SysMgr.outPath and callString:
            if defer:
                callString = self.bufferedStr + callString
            self.callPrint.append(callString)

        # check symbol #
        if SysMgr.customCmd:
            self.checkSymbol(self.syscall, newline=True, exceptFilter=["ret*"])

    def handleDefSyscall(self):
        self.status = "exit"

        if self.getRegs(temp=True) != 0:
            sys.exit(-1)

        # set return value from register #
        args = []
        retval = self.getRet(temp=True)
        if retval < 0:
            # get arguments from previous register set #
            self.updateSyscallArgs(ref=False)
        else:
            # clear args #
            self.clearArgs()

            # convert args #
            args = self.convSyscallArgs(retval)

        # print output #
        self.handleSyscallOutput(args, defer=True)

    def updateSyscallStat(self, name, diff):
        try:
            # get times #
            ttotal, tmax = self.syscallStat[name]
            ttotal += diff

            # update maximum time #
            if tmax < diff:
                tmax = diff

            # update times #
            self.syscallStat[name] = [ttotal, tmax]

            # save interval for stdev #
            if Debugger.envFlags["STDEV"]:
                self.syscallInterStat.setdefault(name, [])
                self.syscallInterStat[name].append(diff)
        except SystemExit:
            sys.exit(0)
        except:
            self.syscallStat[name] = [diff, diff]

    def handleSyscall(self):
        # check thread status #
        if self.status == "wait":
            return

        # task filter #
        if (
            self.execCmd
            and SysMgr.filterGroup
            and not UtilMgr.isValidStr(self.comm)
        ):
            return

        # skip useless return processing #
        if self.status == "skip":
            self.status = "enter"
            return

        # check defer #
        if self.status == "defer":
            self.handleDefSyscall()

        # ignore return #
        if Debugger.dbusEnable and self.status == "exit":
            self.status = "enter"
            self.clearArgs()
            return

        # read registers #
        if not self.updateRegs():
            sys.exit(-1)

        # get syscall number #
        nrSyscall = self.getNrSyscall()

        # check syscall condition #
        if SysMgr.syscallList and not nrSyscall in SysMgr.syscallList:
            # self.cmd = self.sysemuCmd
            self.status = "skip"
            return
        elif (
            SysMgr.syscallExceptList and nrSyscall in SysMgr.syscallExceptList
        ):
            # self.cmd = self.sysemuCmd
            self.status = "skip"
            return

        # get syscall name #
        try:
            self.syscall = name = ConfigMgr.sysList[nrSyscall][4:]
        except SystemExit:
            sys.exit(0)
        except:
            return

        # get diff time #
        diff = self.vdiff

        # define shortcut variables #
        convColor = UtilMgr.convColor

        # enter #
        if self.status == "enter":
            # set next status #
            self.status = "exit"

            # check wait condition #
            if self.wait:
                return

            # update interval between syscalls #
            if Debugger.envFlags["INTERCALL"]:
                try:
                    self.interDiff = self.vdiff - self.syscallTime[name]
                    self.updateSyscallStat(name, self.interDiff)
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

            args = []
            self.syscallTime[name] = self.vdiff

            # convert args except for top mode #
            if not self.isRealtime:
                if self.isDeferCall(name):
                    self.status = "defer"

                    # check return condition #
                    if SysMgr.jsonEnable:
                        return

                    # build call string #
                    callString = "%3.6f %s(%s) %s(" % (
                        diff,
                        self.comm,
                        self.pid,
                        convColor(name, "GREEN"),
                    )

                    # handle call string for enter #
                    if (
                        SysMgr.outPath
                        or Debugger.envFlags["ONLYOK"]
                        or Debugger.envFlags["ONLYFAIL"]
                    ):
                        self.bufferedStr = callString
                    else:
                        SysMgr.printPipe(
                            "\n%s" % callString, newline=False, flush=True
                        )

                    return

                # convert args #
                args = self.convSyscallArgs()

            # print output #
            self.handleSyscallOutput(args)

            # check syscall condition #
            if SysMgr.syscallList:
                self.clearArgs()

            return

        # exit #
        elif self.status == "exit":
            callString = ""

            # set next status #
            self.status = "enter"

            # get diff #
            try:
                diff = self.vdiff - self.syscallTime[name]
            except SystemExit:
                sys.exit(0)
            except:
                diff = 0

            # execute commands #
            if SysMgr.customCmd:
                needUpdateRegs = False
                for cmd in SysMgr.customCmd:
                    item = cmd.split("|")
                    # skip #
                    if not UtilMgr.isValidStr(name, [item[0]]):
                        continue
                    elif len(item) == 1:
                        continue

                    # execute commands #
                    for command in item[1:]:
                        if not command.startswith("ret"):
                            continue
                        args = self.readArgs()
                        self.executeCmd([command], name, None, args)
                        needUpdateRegs = True

                # update final regset #
                if needUpdateRegs:
                    self.updateRegs()
                    SysMgr.printPipe()

            # get return value from register #
            retval = self.getRet()

            # check wait condition #
            if self.wait:
                if self.wait == name and retval == 0:
                    # unset wait condition #
                    self.wait = None
                return

            # convert error code #
            if retval < 0:
                # increase error count #
                self.errCnt += 1

                # check exit condition for success #
                if Debugger.envFlags["ONLYOK"]:
                    self.clearArgs()
                    self.popSample(name)
                    return
                # print enter context #
                elif Debugger.envFlags["ONLYFAIL"]:
                    callString = "\n%s " % self.bufferedStr

                try:
                    retstr = -1
                    errtype = ConfigMgr.ERR_TYPE[abs(retval + 1)]
                    err = "%s (%s)" % (errtype, os.strerror(abs(retval)))

                    # correct wrong status for sys_enter #
                    if errtype == "ENOSYS":
                        self.status = "exit"
                        return

                    self.addSample(name, "??", err=retval)
                except SystemExit:
                    sys.exit(0)
                except:
                    err = ""
            else:
                # check exit condition for fail #
                if Debugger.envFlags["ONLYFAIL"]:
                    self.clearArgs()
                    self.popSample(name)
                    return
                # print exit context #
                elif Debugger.envFlags["ONLYOK"]:
                    callString = "\n%s " % self.bufferedStr

                # build return string #
                try:
                    retstr = "%s(%s)" % (retval, hex(retval).rstrip("L"))
                except SystemExit:
                    sys.exit(0)
                except:
                    retstr = retval
                err = ""

                # change color for return #
                retstr = convColor(retstr, "WARNING")

            # add timeline segment #
            self.addTimelineRet(name, diff, self.prevBtStr)

            # update stats #
            if self.isRealtime:
                if not Debugger.envFlags["INTERCALL"]:
                    self.updateSyscallStat(name, diff)
                self.clearArgs()
                return
            # print context in JSON format #
            elif SysMgr.jsonEnable:
                # set context #
                jsonData = {
                    "type": "exit",
                    "time": self.current,
                    "timediff": diff,
                    "name": name,
                    "tid": self.pid,
                    "comm": self.comm,
                    "backtrace": self.prevBtStr,
                    "ret": str(retval),
                    "err": err,
                }

                # make complete context #
                if (
                    Debugger.envFlags["COMPLETECALL"]
                    and self.syscall in self.entryContext
                ):
                    entryData = self.entryContext.pop(self.syscall, None)
                    if entryData:
                        entryData.update(jsonData)
                        jsonData = entryData
                    jsonData["type"] = "complete"

                # print context #
                SysMgr.printPipe(
                    str(UtilMgr.convDict2Str(jsonData, pretty=self.pretty))
                )

                self.clearArgs()

                return

            # convert error color #
            if err:
                err = " " + convColor(err, "RED")

            # convert elapsed color #
            diffStr = " [%.6f]" % diff
            if diff > self.retTime:
                diffStr = convColor(diffStr, "RED")
            else:
                diffStr = convColor(diffStr, "CYAN")

            # add interval time #
            if Debugger.envFlags["INTERCALL"] and self.interDiff:
                interdiffStr = " [%.6f]" % self.interDiff
                if self.interDiff > self.retTime:
                    diffStr += convColor(interdiffStr, "RED")
                else:
                    diffStr += convColor(interdiffStr, "CYAN")
                self.interDiff = 0

            # add newline after backtrace #
            if self.btStr or self.prevBtStr:
                newline = "\n " + (" " * self.indentLen)
            else:
                newline = ""

            # build call string #
            callString = "%s%s= %s%s%s" % (
                callString,
                newline,
                retstr,
                err,
                diffStr,
            )

            # print call string #
            if SysMgr.outPath:
                if self.callPrint:
                    self.callPrint[-1] += callString
                else:
                    self.callPrint.append(callString)

                # update stats #
                if not Debugger.envFlags["INTERCALL"]:
                    self.updateSyscallStat(name, diff)

                # print to stdout #
                if SysMgr.streamEnable:
                    sys.stdout.write("%s\n" % callString)
            elif not self.isRealtime:
                SysMgr.printPipe(callString, newline=False, flush=True)

            # remove arg string #
            self.clearArgs()

        else:
            SysMgr.printErr("failed to recognize syscall %s's status" % name)

    def getKernelStack(self, retstr=False):
        # read kernel stack #
        stat = SysMgr.readProcStat(
            self.kernelFd,
            "%s/task/%s/stack" % (self.pid, self.pid),
            self,
            "kernelFd",
        )
        if not stat:
            return None

        # return full data #
        if retstr:
            return " <- ".join(stat)
        else:
            return stat

    def getStatList(self, retstr=False, status=False):
        try:
            self.statFd.seek(0)
            stat = self.statFd.read()
        except SystemExit:
            sys.exit(0)
        except:
            try:
                statPath = "%s/%s/task/%s/stat" % (
                    SysMgr.procPath,
                    self.pid,
                    self.pid,
                )
                self.statFd = open(statPath, "r")
                stat = self.statFd.read()
            except SystemExit:
                sys.exit(0)
            except:
                try:
                    SysMgr.printOpenWarn(statPath)
                except:
                    pass
                return None

        # return full data #
        if retstr:
            return stat

        try:
            if status:
                return stat.split(") ", 1)[1][0]
            else:
                return stat.split(") ", 1)[1].split()
        except SystemExit:
            sys.exit(0)
        except:
            return None

    def isAlive(self):
        stat = self.getStatList(status=True)
        if not stat:
            return None

        if stat == "Z":
            return False
        else:
            return True

    def isStopped(self):
        stat = self.getStatList(status=True)
        if not stat:
            return None

        # check status #
        if stat in ("T", "t", "D"):
            return True
        else:
            return False

    def isInRun(self):
        stat = self.getStatList(status=True)
        if not stat:
            return None

        # check status #
        if stat == "R" or stat == "t":
            return True
        else:
            return False

    def getMemUsage(self, unit=True):
        stat = self.getStatList(retstr=True)
        if not stat:
            SysMgr.printWarn(
                "failed to get memory usage for %s(%s)" % (self.comm, self.pid)
            )
            return "0"

        # convert string to list #
        statList = stat.split(") ", 1)[1].split()

        # get RSS size #
        try:
            byteSize = long(statList[self.rssIdx - 2]) << 12
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn(
                "failed to get memory usage for %s(%s)"
                % (self.pid, self.comm),
                reason=True,
            )
            byteSize = 0

        if not unit:
            return byteSize
        else:
            return UtilMgr.convSize2Unit(byteSize, True)

    def getTotalCpuTick(self):
        # get task CPU usage #
        stat = self.getStatList(retstr=True)
        if not stat:
            SysMgr.printWarn(
                "failed to get CPU usage for %s(%s)" % (self.comm, self.pid)
            )
            return [0, 0, 0]

        statList = stat.split(") ", 1)[1].split()

        # get total CPU time #
        utime = long(statList[self.utimeIdx - 2])
        stime = long(statList[self.stimeIdx - 2])
        ttime = utime + stime

        return [ttime, utime, stime]

    def getCpuUsage(self, system=False):
        # get system CPU usage #
        if system:
            itime = SysMgr.getIdleTime()
            if itime and self.prevCpuStat and self.prevCpuStat[3]:
                nrCore = SysMgr.getNrCore()
                diff = itime - self.prevCpuStat[3]
                ctime = diff / float(nrCore)
            else:
                ctime = 0
        else:
            itime = ctime = 0

        # get task CPU usage #
        stat = self.getStatList(retstr=True)
        if not stat:
            SysMgr.printWarn(
                "failed to get CPU usage for %s(%s)" % (self.comm, self.pid)
            )
            self.prevCpuStat[3] = itime
            return [0, 0, 0, ctime]

        # check stat change #
        if self.prevStat == stat:
            self.prevCpuStat[3] = itime
            return [0, 0, 0, ctime]

        self.prevStat = stat

        # convert string to list #
        statList = stat.split(") ", 1)[1].split()
        if not statList:
            return [0, 0, 0, ctime]

        # get total CPU time #
        utime = long(statList[self.utimeIdx - 2])
        stime = long(statList[self.stimeIdx - 2])
        ttime = utime + stime

        # get previous CPU usage #
        prevUsage = self.prevCpuStat

        # update previous CPU usage #
        self.prevCpuStat = [ttime, utime, stime, itime]

        # get CPU diff #
        if prevUsage == None or ttime == 0:
            ret = [0, 0, 0, ctime]
        else:
            # return CPU times #
            ret = [
                ttime - prevUsage[0],
                utime - prevUsage[1],
                stime - prevUsage[2],
                ctime,
            ]

        return ret

    def printSymbolList(self, slist):
        if not slist or not SysMgr.warnEnable:
            return

        string = [
            "%s(%s@%s)" % (item[1], hex(item[0]).rstrip("L"), item[2])
            for item in slist
        ]

        SysMgr.printWarn("found multiple symbols [ %s ]" % ", ".join(string))

    def getAddrBySymbol(
        self,
        symbol,
        binary=None,
        inc=False,
        start=False,
        end=False,
        one=False,
        verb=False,
    ):

        # check memory map #
        if not self.pmap:
            self.loadSymbols()

        addrList = []
        addrDict = {}

        # search symbols from all memory-mapped files #
        for mfile in list(self.pmap):
            if binary and not mfile in binary:
                continue

            # get ELF object #
            try:
                fcache = ElfAnalyzer.getObject(mfile)
                if not fcache:
                    continue
            except SystemExit:
                sys.exit(0)
            except:
                continue

            # get offset #
            offset = fcache.getOffsetBySymbol(
                symbol, inc=inc, start=start, end=end
            )
            if type(offset) is str:
                offset = long(offset, 16)

                if ElfAnalyzer.isRelocFile(mfile):
                    if offset in addrDict:
                        continue
                    addrList.append(
                        [self.pmap[mfile]["vstart"] + offset, symbol, mfile]
                    )
                else:
                    if offset in addrDict:
                        continue
                    addrList.append([offset, symbol, mfile])

                addrDict[offset] = True
                continue
            elif type(offset) is not list:
                continue

            for item in offset:
                sym = item[0]
                offset = long(item[1], 16)
                if ElfAnalyzer.isRelocFile(mfile):
                    if offset in addrDict:
                        continue

                    addrList.append(
                        [self.pmap[mfile]["vstart"] + offset, sym, mfile]
                    )
                else:
                    if offset in addrDict:
                        continue

                    addrList.append([offset, sym, mfile])

                addrDict[offset] = True

        # search JIT-compiled symbols #
        for idx, item in enumerate(self.jmapSymTable):
            target = item[0]
            if (
                (start and target.startswith(symbol))
                or (end and target.endswith(symbol))
                or (inc and symbol in target)
            ):
                addrList.append([self.jmapAddrTable[idx], target, "JIT"])

        # return address #
        if not addrList:
            if verb:
                SysMgr.printErr(
                    "failed to find %s symbol for %s(%s)"
                    % (symbol, self.comm, self.pid)
                )
            return None
        elif len(addrList) > 1:
            self.printSymbolList(addrList)

        # return address for 1st item #
        if one:
            # check libc symbol first #
            if SysMgr.libcObj:
                libcPath = SysMgr.libcObj._name
                for item in addrList:
                    if libcPath in item[2]:
                        return item[0]

            if addrList:
                return addrList[0][0]

        return addrList

    def lock(self, pos=-1):
        # pylint: disable=undefined-variable
        if not self.lockObj:
            return False

        if pos > -1:
            lockf(self.lockObj, LOCK_EX, 1, pos, 0)
        else:
            lockf(self.lockObj, LOCK_EX)

        return True

    def unlock(self, pos=-1):
        # pylint: disable=undefined-variable
        if not self.lockObj:
            return False

        if pos > -1:
            lockf(self.lockObj, LOCK_UN, 1, pos, 0)
        else:
            lockf(self.lockObj, LOCK_UN)

        return True

    def handoverNewTarget(self, fork=False):
        # get tid of the child task #
        tid = self.getEventMsg()

        # give up the new tracee #
        if not SysMgr.isRoot():
            SysMgr.printWarn(
                (
                    "failed to trace a new cloned tracee "
                    "because of no root permission"
                ),
                True,
            )

            # detach the new tracee #
            self.detach(only=True, pid=tid, check=True)

            return self.pid

        # stop tracees #
        self.stop()
        self.stop(pid=tid)

        # check memory map #
        if not self.pmap:
            self.loadSymbols()

        # check lock #
        if self.isBreakMode and not self.lockObj:
            self.lockObj = Debugger.getGlobalLock(self.pid, len(self.bpList))

        # check master process #
        if SysMgr.masterPid == 0:
            chMid = True
        else:
            chMid = False

        # print clone event info #
        SysMgr.printInfo(
            "%s(%s) is created by %s(%s)"
            % (self.comm, tid, self.comm, self.pid)
        )

        # create a pipe #
        if Debugger.envFlags["SYNCTASK"]:
            rd, wr = os.pipe()

        # create a new tracer to trace the child task #
        pid = SysMgr.createProcess(isDaemon=True, chMid=chMid, chPgid=True)
        # parent tracee #
        if pid > 0:
            # detach from the parent task #
            self.detach(only=True)

            # detach from the child task #
            self.detach(only=True, pid=tid, check=True)

            # attach to the parent task again #
            if self.attach(verb=True) < 0:
                sys.exit(-1)

            # update status to leave clone context #
            if self.mode == "syscall":
                self.status = "stop"

            # increase the number of children #
            self.childNum += 1

            # wait for tracer of child task #
            try:
                if Debugger.envFlags["SYNCTASK"]:
                    os.close(wr)
                    os.fdopen(rd, "r").read()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "failed to wait for tracer of %s(%s)" % (self.comm, tid),
                    reason=True,
                )
        # child tracee #
        elif pid == 0:
            # update the child PID #
            origPid = self.pid
            self.pid = tid

            # attach to the child task #
            while 1:
                if self.attach(verb=True) == 0:
                    break

                # check and wait for attach #
                if self.isAlive():
                    time.sleep(SysMgr.waitDelay)
                    continue
                else:
                    SysMgr.printErr(
                        "%s(%s) is terminated" % (self.comm, self.pid)
                    )
                    sys.exit(0)

            # initialize variables #
            self.initValues(fork)
            self.forked = True
            signal.alarm(SysMgr.intervalEnable)

            # increase the number of children #
            self.childNum += 1
            self.myNum = self.childNum

            # update status to leave clone context #
            if self.mode == "syscall":
                self.status = "enter"
            else:
                self.status = "skip"

            # notify to tracer of parent task #
            try:
                if Debugger.envFlags["SYNCTASK"]:
                    os.close(rd)
                    os.fdopen(wr, "w").write("0")
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "failed to notify initialization to %s(%s)"
                    % (self.comm, origPid),
                    reason=True,
                )
        # fork fail #
        else:
            return self.pid

        # set trace event #
        self.ptraceEvent(self.traceEventList)

        # set attributes for multiprocess #
        self.multi = True
        if not SysMgr.outPath:
            SysMgr.setStream()

        # continue target #
        if self.mode == "syscall":
            SysMgr.syscall(self.tkillIdx, self.pid, signal.SIGCONT)
        self.cont(check=True, sig=signal.SIGCONT)

        return pid

    def restartTrace(self):
        # print exec event info #
        cmdline = SysMgr.getCmdline(self.pid)
        SysMgr.printInfo(
            '%s(%s) executed "%s"' % (self.comm, self.pid, cmdline)
        )

        # reset environment #
        Debugger.printSummary(self)
        SysMgr.exitFuncList = []

        # close fd for output #
        SysMgr.closePrintFd()

        # create a new controller #
        dobj = Debugger(pid=self.pid, attach=False, mode=self.mode)
        dobj.attached = True
        dobj.initValues()
        if cmdline:
            dobj.execCmd = cmdline.split()
            dobj.targetBpList = self.targetBpList
            dobj.targetBpFileList = self.targetBpFileList
            dobj.exceptBpFileList = self.exceptBpFileList

        # initialize variables #
        if dobj.mode == "break":
            dobj.isRunning = False
            ElfAnalyzer.cachedFiles = {}

        # apply original attribute #
        dobj.myNum = self.myNum
        dobj.childNum = self.childNum

        # load symbols and inject breakpoints #
        if SysMgr.funcDepth > 0 or not dobj.mode in (
            "syscall",
            "signal",
            "kernel",
        ):
            if dobj.loadSymbols():
                dobj.updateBpList()

        # continue target #
        if (
            not dobj.mode in ("syscall", "signal", "kernel")
            and dobj.isStopped()
        ):
            if dobj.cont(check=True) < 0:
                sys.exit(-1)

        # start new tracing #
        dobj.trace(mode=self.mode, multi=self.multi)

    def initValues(self, fork=True):
        # stat variables #
        self.pthreadid = 0
        self.comm = SysMgr.getComm(self.pid, cache=True)
        self.exe = SysMgr.getExeName(self.pid)
        self.start = self.last = time.time()
        self.statFd = None
        self.kernelFd = None
        self.prevStat = None
        self.pyLibPath = None
        self.pyInit = False
        self.prevSym = None
        self.prevPySym = None
        self.prevPyBt = None
        self.prevPyIndent = {}
        self.pretty = not SysMgr.findOption("Q")

        # update CPU usage for target #
        if hasattr(self, "prevCpuStat"):
            self.getCpuUsage(system=True)
        else:
            self.prevCpuStat = None

        # exec variable #
        if SysMgr.execEnable is None:
            self.execEnable = True
        else:
            self.execEnable = False

        # register variables #
        self.pc = None
        self.lr = None
        self.sp = None
        self.fp = None
        self.prevCallInfo = None
        self.prevSp = None
        self.prevDepth = 0

        # call variables #
        self.prevCallString = ""
        self.stack = []
        self.prevStack = []
        self.childList = []
        self.callList = []
        self.callTable = {}
        self.btTable = {}
        self.fileTable = {}
        self.callPrint = []
        self.cpuUsageList = []
        self.selfCpuUsageList = []
        self.syscallTime = {}
        self.syscallStat = {}
        self.syscallInterStat = {}
        self.syscallTotalStat = {}
        self.bpcallStat = {}
        self.bpcallInterStat = {}
        self.retList = {}
        self.accList = {}
        self.interList = {}
        self.intervalList = {}
        self.hiddenList = {}
        self.setRetList = {}
        self.regList = {}
        self.repeatCntList = {}
        self.symbolCacheList = {}
        self.failedAddrList = {}
        self.prevReturn = -1
        self.startAddr = None
        self.errCnt = 0

        # timestamp variables #
        self.updateCurrent()

        # python variables #
        self.pyAddr = None
        self.pyFrameCache = {}

        # make object for myself #
        if (
            not Debugger.tracerInstance
            or Debugger.tracerInstance.pid != SysMgr.pid
        ):
            Debugger.tracerInstance = Debugger(SysMgr.pid, attach=False)
            Debugger.tracerInstance.initValues()

        # update CPU usage for myself #
        Debugger.tracerInstance.getCpuUsage()

    def handleRetBpFilter(self, sym):
        # get original symbol #
        try:
            origSym = sym[: -len(Debugger.RETSTR)]
        except SystemExit:
            sys.exit(0)
        except:
            origSym = sym

        # check entry time #
        if origSym not in self.entryTime:
            SysMgr.printWarn(
                "no entry time of %s for %s(%s)"
                % (origSym, self.comm, self.pid)
            )
            raise Exception("no entry time")

        # calculate elapsed time #
        skip = False
        hasRetFilter = False
        entry = self.entryTime[origSym].pop()
        etime = self.vdiff - entry
        elapsed = "/%.6f" % etime

        # remove entry timestamp from list #
        if not self.entryTime[origSym]:
            self.entryTime.pop(origSym, None)

        # check return filter #
        if not origSym in self.retFilterList:
            return etime, elapsed, hasRetFilter, skip, None

        # check condition #
        try:
            filters = self.retFilterList[origSym][0]
            target = filters[0]
            op = filters[1].upper()
            cond = float(filters[2])
            cmd = self.retFilterList[origSym][2]

            # set target value #
            if target == "RETTIME":
                val = etime
            elif target == "RETVAL":
                val = self.getRet()
            else:
                SysMgr.printErr(
                    "failed to recognize '%s' as a return filter" % target
                )
                sys.exit(-1)

            # compare values #
            if op == "EQ":
                if val != cond:
                    skip = True
            elif op == "DF":
                if val == cond:
                    skip = True
            elif op == "BT":
                if val <= cond:
                    skip = True
            elif op == "LT":
                if val >= cond:
                    skip = True
            else:
                SysMgr.printErr(
                    (
                        "failed to recognize '%s' in return filter "
                        "for %s for %s(%s)"
                    )
                    % (op, origSym, self.comm, self.pid)
                )
                sys.exit(-1)

            hasRetFilter = True
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to check return filter for %s for %s(%s)"
                % (origSym, self.comm, self.pid),
                True,
            )

        # remove return filter #
        self.retFilterList.pop(origSym, None)

        return etime, elapsed, hasRetFilter, skip, cmd

    def handleRetBp(self, sym, fname, addr):
        try:
            # change return value #
            if sym in self.setRetList:
                newval = self.setRetList[sym].pop()
                if not self.setRetList[sym]:
                    self.setRetList.pop(sym, None)
                self.setRet(newval)
                self.setRegs()
                self.updateRegs()

            # get return value #
            retval = self.getRet()

            # check register set for repeat #
            try:
                origSym = sym[: -len(Debugger.RETSTR)]
            except:
                origSym = sym

            # update context #
            if origSym in self.regList:
                newObj = self.regList.pop(origSym, None)
                self.setRegs(newObj=newObj)
                self.updateRegs()

            # save return value #
            self.retList[origSym] = long(retval)
            self.prevReturn = str(retval)

            # remove breakpoint #
            if not origSym in self.entryTime:
                ret = self.removeBp(addr, lock=True)

            return "=%s(%s)" % (hex(retval).rstrip("L"), retval)
        except SystemExit:
            sys.exit(0)
        except:
            errMsg = "failed to get return value for %s" % sym
            SysMgr.printWarn(errMsg, reason=True)

    def setRetBp(self, sym, fname, cmd=None):
        # get return address #
        try:
            if self.arch == "aarch64" or self.arch == "arm":
                pos = self.lr
            else:
                pos = self.getBacktrace(limit=1, cur=False)[0][0]
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn(
                "no backtrace for %s(%s)" % (sym, fname), reason=True
            )

            # to prevent useless error message #
            return True

        # add the new breakpoint for return #
        newSym = sym + Debugger.RETSTR
        ret = self.injectBp(pos, newSym, fname, reins=True, cmd=None)
        if not ret:
            return False

        # register the new breakpoint to per-thread list #
        if not pos in self.bpNewList and pos in self.bpList:
            self.bpNewList[pos] = self.bpList[pos]

        # register function entry time #
        # TODO: handle no return procedure such like PLT #
        self.entryTime.setdefault(sym, [])
        self.entryTime[sym].append(self.vdiff)

        # set command list #
        if cmd:
            self.retCmdList[sym] = cmd

        return True

    def waitForClone(self):
        if self.status == "ready":
            return

        # set trace event #
        self.ptraceEvent(self.traceEventList)

        SysMgr.printStat(
            "wait for clone by %s(%s)... [ STOP(Ctrl+c) ]"
            % (self.comm, self.pid)
        )

        while 1:
            self.cont()

            # wait process #
            rid, ostat = self.waitpid()

            # handle clone event #
            if self.checkCloned(ostat):
                # check clone/fork event #
                if self.isForked(ostat):
                    forked = True
                else:
                    forked = False

                # handle a new task #
                pid = self.handoverNewTarget(fork=forked)
                if pid > 0:
                    continue
                break

        self.stop()

    def checkStat(self, ret, reason=None):
        stat = self.getStatus(ret[1])
        if SysMgr.isTermSignal(stat) or (stat == -1 and not self.isAlive()):
            msg = "terminated %s(%s)" % (self.comm, self.pid)
            if reason:
                msg = "%s because %s" % (msg, reason)
            SysMgr.printErr(msg)
            sys.exit(0)

    def runEventLoop(self):
        # set mode #
        sampleMode = pycallMode = signalMode = syscallMode = instMode = False
        if self.mode == "sample":
            sampleMode = True
        elif self.mode == "pycall":
            pycallMode = True
        elif self.mode == "signal":
            signalMode = True
        elif self.mode == "syscall":
            syscallMode = True
        elif self.mode == "inst":
            instMode = True
        elif self.mode == "kernel":
            self.startSamplingKernel()

        # timestamp variables #
        self.updateCurrent()

        # initialize dynamic time for tracing #
        self.dstart = time.time()

        # set update flag for time #
        if self.isBreakMode or syscallMode or SysMgr.isTraceMode():
            updateTime = True
        else:
            updateTime = False

        # set including overhead flag for time #
        incOverhead = True if Debugger.envFlags["INCOVERHEAD"] else False

        # define trap flag for syscall #
        syscallTrapFlag = signal.SIGTRAP | 0x80

        # enter trace loop #
        while 1:
            # save backtrace info #
            self.prevBtList = self.btList
            self.prevBtStr = self.btStr
            self.btList = self.btStr = None

            # set status #
            if self.status == "stop":
                self.status = "enter"
            elif self.status in ("ready", "wait"):
                pass
            else:
                # wait for sample calls #
                if sampleMode or pycallMode:
                    self.checkInterval()
                elif self.isBreakMode or signalMode:
                    pass
                # skip instructions for performance #
                elif instMode and self.skipInst > 0:
                    for _ in xrange(self.skipInst):
                        self.ptrace(self.cmd)
                # setup trap #
                else:
                    self.ptrace(self.cmd)

            try:
                # add tracing overhead to start time #
                if updateTime and not incOverhead:
                    overhead = time.time() - self.current
                    if Debugger.envFlags["PRINTDELAY"]:
                        SysMgr.printWarn(
                            "[OVERHEAD] %.6f sec" % overhead, True
                        )
                    self.dstart += overhead

                # wait for target to be stopped #
                rid, ostat = self.waitpid()

                # update time #
                self.updateCurrent()
                if updateTime:
                    delay = self.dstart - self.dvalue
                    delay = 0 if delay < 0 else delay
                    self.vdiff = self.current - delay

                # check clone event #
                if (
                    not Debugger.dbusEnable
                    and (SysMgr.cloneEnable or self.isBreakMode)
                    and self.checkCloned(ostat)
                ):

                    # check clone/fork event #
                    if self.isForked(ostat):
                        # skip handling fork in break mode #
                        if not SysMgr.cloneEnable:
                            self.cont()
                            continue
                        else:
                            forked = True
                    else:
                        forked = False

                    # handle clone event #
                    ret = self.handoverNewTarget(fork=forked)
                    # failure for handling clone #
                    if ret == self.pid:
                        self.cont()
                    # mute non-target tasks cloned in break mode #
                    elif not SysMgr.cloneEnable:
                        SysMgr.printEnable = False

                    # continue to exit event for clone syscall #
                    if not syscallMode:
                        continue

                # handle exec event #
                if self.isExeced(ostat):
                    if self.execEnable:
                        self.restartTrace()
                    else:
                        SysMgr.printErr(
                            "terminated tracing %s(%s) because of exec"
                            % (self.comm, self.pid)
                        )
                    sys.exit(0)

                # get status of process #
                stat = self.getStatus(ostat)
                self.lastSig = stat

                # trap #
                if stat == signal.SIGTRAP:
                    # handle exit event #
                    if self.isExited(ostat):
                        self.handleExit()
                        self.cont()
                        SysMgr.callSigHandler(signal.SIGALRM)
                        continue

                    # after execve() #
                    elif self.status == "ready":
                        # initialize variables #
                        self.initValues()

                        self.ptraceEvent(self.traceEventList)

                        SysMgr.printInfo(
                            "start profiling %s(%d)..." % (self.comm, self.pid)
                        )

                        # set first command #
                        if self.cmd:
                            self.ptrace(self.cmd)

                        if self.isBreakMode:
                            # remove all breakpoints for new child process #
                            if self.forked:
                                self.removeAllBp()

                            # load symbols again #
                            self.loadSymbols()
                            self.updateBpList()

                            # continue target #
                            if self.cont(check=True) < 0:
                                sys.exit(-1)

                        # change status #
                        self.status = "enter"

                    # usercall / breakcall #
                    elif self.isBreakMode or instMode:
                        self.handleTrapEvent(ostat)

                    # wrong status for syscall #
                    elif syscallMode and self.status == "enter":
                        self.status = "skip"
                        self.ptraceEvent(self.traceEventList)
                        self.ptrace(self.cmd)
                        continue

                # exit #
                elif stat == -1:
                    # check alive status #
                    if self.isAlive():
                        continue

                    # print status #
                    SysMgr.printWarn(
                        "terminated %s(%s)" % (self.comm, self.pid)
                    )

                    # wait event #
                    if SysMgr.isTopMode() and self.totalCall:
                        SysMgr.waitEvent()

                    sys.exit(0)

                # signal #
                elif signalMode:
                    # handle signal #
                    self.handleSignal(stat)

                    # deliver signal #
                    self.cont(sig=stat)

                # breakpoint for ARM #
                elif stat == signal.SIGILL and self.isBreakMode:
                    self.handleTrapEvent(ostat)

                # syscall #
                elif stat == syscallTrapFlag:
                    # interpret syscall context #
                    if syscallMode:
                        self.handleSyscall()

                # STOP signal #
                elif stat == signal.SIGSTOP:
                    if sampleMode or pycallMode:
                        self.handleTrapEvent(ostat)
                        continue

                    # update status #
                    self.status = "stop"
                    SysMgr.printWarn(
                        "blocked %s(%s) because of %s"
                        % (self.comm, self.pid, ConfigMgr.SIG_LIST[stat])
                    )

                    # continue #
                    if self.isBreakMode:
                        if self.cont(check=True, sig=stat) < 0:
                            sys.exit(-1)
                    # set up trap again #
                    elif syscallMode:
                        self.ptraceEvent(self.traceEventList)
                        self.ptrace(self.cmd)

                # KILL / SEGV / ABRT signal #
                elif SysMgr.isTermSignal(stat):
                    # print a new line #
                    sys.stdout.write("\n")

                    # print signal info #
                    self.handleSignal(stat, taskinfo=syscallMode)

                    # print context info #
                    if SysMgr.showAll:
                        self.printContext(newline=True)

                    # deliver signal #
                    if self.cont(check=True, sig=stat) < 0:
                        sys.exit(-1)

                    # stop target for next syscall #
                    if syscallMode:
                        self.stop()

                    # set fault flag to shared memory #
                    self.setFaultFlag()

                # other #
                else:
                    # print signal info #
                    if SysMgr.warnEnable:
                        self.handleSignal(
                            stat, warn=True, taskinfo=syscallMode
                        )

                    # handle signal #
                    if sampleMode or pycallMode:
                        self.handleTrapEvent(ostat)

                    # deliver signal #
                    if self.cont(check=True, sig=stat) < 0:
                        sys.exit(-1)

                    # stop target for next syscall #
                    if syscallMode:
                        self.stop()
            except SystemExit:
                return
            except:
                if not self.isAlive():
                    SysMgr.printErr(
                        "terminated tracing %s(%s)" % (self.comm, self.pid)
                    )
                    return

                SysMgr.printWarn(
                    "detected %s(%s) with error" % (self.comm, self.pid),
                    reason=True,
                )

                # deliver signal #
                if self.isBreakMode:
                    if self.cont(check=True) < 0:
                        sys.exit(-1)

    def trace(
        self,
        mode,
        wait=None,
        multi=False,
        lock=None,
        bpList={},
        exceptBpList={},
        targetBpList={},
        targetBpFileList={},
        exceptBpFileList={},
    ):

        # initialize variables #
        self.initValues()

        # apply common breakpoint list #
        if not self.targetBpList:
            self.targetBpList = targetBpList
        if not self.targetBpFileList:
            self.targetBpFileList = targetBpFileList
        if not self.exceptBpFileList:
            self.exceptBpFileList = exceptBpFileList

        # context variables #
        self.cmd = None
        self.wait = wait
        self.mode = mode
        self.multi = multi
        self.lockObj = lock

        # set maximum string size #
        if Debugger.strSize > -1:
            self.pbufsize = Debugger.strSize
        elif SysMgr.outPath:
            self.pbufsize = sys.maxsize
        else:
            self.pbufsize = SysMgr.ttyCols >> 1

        # update break mode #
        self.updateBreakMode()

        # disable extended ascii #
        SysMgr.encodeEnable = False

        # register my instance #
        SysMgr.addExitFunc(Debugger.destroyDebugger, [self])

        # check realtime mode #
        if SysMgr.isTopMode():
            self.isRealtime = True
        else:
            self.isRealtime = False

        # set tracing attribute #
        if self.isRealtime:
            # update CPU usage #
            self.getCpuUsage(system=True)
            Debugger.tracerInstance.getCpuUsage()

            # set alarm handler #
            signal.signal(signal.SIGALRM, Debugger.onAlarm)

            if self.mode in ("sample", "pycall", "kernel"):
                # set sampling rate to 100 us #
                sampleTime = SysMgr.getOption("T")
                if sampleTime:
                    try:
                        self.sampleTime = long(sampleTime) / float(1000000)
                    except:
                        SysMgr.printErr("failed to set sampling time", True)
                        sys.exit(-1)
                else:
                    self.sampleTime = 0.001

                # save original sampling rate #
                self.sampleTimeOrig = self.sampleTime

                if not self.multi:
                    SysMgr.printInfo(
                        "do sampling every %s second"
                        % UtilMgr.convFloat2Str(self.sampleTime)
                    )

            # set default interval #
            if not SysMgr.findOption("R") and SysMgr.intervalEnable == 0:
                SysMgr.intervalEnable = 1

            # set maximum sampling rate #
            self.sampleTimeMax = float(SysMgr.intervalEnable) / 10

            # check disabling incremental sampling #
            if "FIXSAMPLING" in SysMgr.environList:
                self.incrementalSampling = False
        else:
            # set timer handler #
            if SysMgr.intervalEnable:
                signal.signal(signal.SIGALRM, SysMgr.alarmExitHandler)

            # inst #
            if SysMgr.checkMode("utrace") and SysMgr.funcDepth > 0:
                # set sampling rate for instruction #
                self.skipInst = SysMgr.funcDepth

                SysMgr.printInfo(
                    "do sampling every %s instrunctions"
                    % UtilMgr.convNum(SysMgr.funcDepth)
                )

        # init python environment #
        if self.mode in ("pycall", "pybreak"):
            self.initPyEnv()

        # prepare environment for the running target #
        if self.isRunning:
            # check the process is running #
            try:
                os.kill(self.pid, 0)
            except SystemExit:
                sys.exit(0)
            except:
                ereason = SysMgr.getErrMsg()
                if ereason != "0":
                    SysMgr.printErr(
                        "failed to trace %s(%s) because %s"
                        % (self.comm, self.pid, ereason)
                    )
                sys.exit(-1)

            # initialize environment for python #
            if mode in ("pycall", "pybreak"):
                pass
            # load user symbols #
            elif SysMgr.funcDepth > 0 or mode not in (
                "syscall",
                "signal",
                "kernel",
            ):
                try:
                    self.loadSymbols()
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr("failed to load symbols", True)
                    sys.exit(-1)

            # print target task info #
            if SysMgr.printEnable:
                SysMgr.printInfo(
                    "start profiling %s(%d)..." % (self.comm, self.pid)
                )

            # check attach status #
            if not self.attached:
                if self.attach(verb=True) < 0:
                    sys.exit(-1)

            ret = self.ptraceEvent(self.traceEventList)

            # handle current user symbol #
            if self.mode in ("inst", "sample") and not SysMgr.isTopMode():
                try:
                    self.handleUsercall()
                except SystemExit:
                    sys.exit(0)
                except:
                    return

        # set trap event type for the new target #
        else:
            self.ptraceEvent(self.traceEventList)
            self.status = "ready"

        # select trap command #
        if self.mode == "syscall":
            self.cmd = self.syscallCmd
        elif self.mode == "inst":
            self.cmd = self.singlestepCmd
            if self.arch == "arm":
                SysMgr.printErr("not supported on %s" % self.arch.upper())
                sys.exit(-1)
        elif self.mode in ("sample", "pycall"):
            self.cmd = None

            # set syscall command to wait for wakeup #
            if self.isRunning and Debugger.envFlags["WAITWAKEUP"]:
                SysMgr.printInfo(
                    "start waiting for %s(%s) awakened" % (self.comm, self.pid)
                )
                # sleep for syscall wakeup #
                self.ptrace(self.syscallCmd)
                self.waitpid()

                self.ptrace(self.syscallCmd)
                self.waitpid()
        elif self.isBreakMode:
            if self.isRunning:
                # register breakpoint data #
                if bpList:
                    self.bpList = bpList
                if exceptBpList:
                    self.exceptBpList = exceptBpList

                # check thread status #
                stat = self.getStatList(status=True)
                if not stat:
                    SysMgr.printErr(
                        "terminated %s(%s)" % (self.comm, self.pid)
                    )
                elif stat == "S":
                    SysMgr.syscall(self.tkillIdx, self.pid, signal.SIGCONT)
        elif self.mode in ("signal", "kernel"):
            if self.isStopped():
                if self.cont(check=True) < 0:
                    sys.exit(-1)
        elif self.mode == "remote":
            Debugger.envFlags["PRINTDIFF"] = True
            for _ in xrange(SysMgr.intervalEnable + 1):
                self.runExecMode()
            SysMgr.printPipe()
            sys.exit(0)
        else:
            SysMgr.printErr(
                "failed to recognize '%s' mode for trace" % self.mode
            )
            sys.exit(-1)

        # register summary callback #
        SysMgr.addExitFunc(Debugger.printSummary, [self])

        # wait for task creation #
        if Debugger.envFlags["WAITCLONE"]:
            self.waitForClone()

        # set timer #
        if SysMgr.masterPid == 0 or SysMgr.printEnable:
            signal.alarm(SysMgr.intervalEnable)

        # run loop #
        self.runEventLoop()

    @staticmethod
    def destroyDebugger(instance):
        def _printTimeline():
            if (
                Debugger.envFlags["TIMELINE"]
                and instance.timelineData["segments"]
            ):
                # get symbol list #
                ylist = {y: x for x, y in instance.timelineIdx.items()}

                # update name table #
                instance.timelineData["names"] = ylist

                # set output path #
                if SysMgr.outPath:
                    outPath = SysMgr.inputFile
                else:
                    outPath = "/tmp/guider_%s.svg" % instance.pid
                outPath = UtilMgr.getDrawOutputPath(outPath, "timeline")
                dataPath = outPath.replace(".svg", ".json")

                # backup data #
                SysMgr.backupFile(dataPath)

                # save data #
                UtilMgr.saveStr2File(
                    UtilMgr.convDict2Str(instance.timelineData, pretty=True),
                    dataPath,
                )

                # get data size #
                fsize = UtilMgr.getFileSizeStr(dataPath)

                SysMgr.printStat(
                    "wrote timeline data into '%s'%s" % (dataPath, fsize)
                )

                # backup output #
                SysMgr.backupFile(outPath)

                # check svgwrite object #
                try:
                    SysMgr.getPkg("svgwrite")
                except:
                    return

                # draw timeline #
                SysMgr.drawTimeline(
                    inputData=instance.timelineData,
                    outputPath=outPath,
                    yval=ylist,
                )

        Debugger.dbgInstance = None

        # check condition for breakpoint cleanup #
        if (
            not instance.pid
            or SysMgr.inputParam
            or not instance.bpList
            or not instance.isAlive()
        ):
            # print timeline #
            _printTimeline()

            # remove instance #
            instance.__del__()

            # return #
            return

        # stop target #
        if not instance.isStopped():
            instance.stop()
            instance.waitpid()

        # notify termination to master process #
        try:
            tgid = long(SysMgr.getTgid(instance.pid))
            if SysMgr.masterPid and tgid == instance.pid:
                os.kill(SysMgr.masterPid, signal.SIGINT)
        except:
            # return #
            return

        # make CPU priority lower #
        SysMgr.setPriority(SysMgr.pid, "C", 19, verb=False)

        try:
            # set max try count #
            cnt = 5

            while 1:
                # update register set #
                ret = instance.updateRegs()
                if ret:
                    break
                elif not instance.isAlive():
                    return

                # check count #
                cnt -= 1
                if cnt <= 0:
                    instance.__del__(stop=True)
                    return

                # wait a moment #
                time.sleep(SysMgr.waitDelay)
        except:
            Debugger.printSummary(instance)
            SysMgr.outPath = None

        # rewind IP from trap status #
        addr = instance.pc - instance.prevInstOffset
        if addr in instance.bpList:
            instance.setPC(addr)
            instance.setRegs()
            instance.removeBp(addr)
        else:
            # check alignment #
            if addr % ConfigMgr.wordSize == 0:
                origWord = instance.accessMem(instance.peekIdx, addr)
                origWord = UtilMgr.convWord2Str(origWord)
            else:
                origWord = instance.readMem(addr)

            # recover memory #
            if origWord and origWord.startswith(instance.brkInst):
                ret = instance.getSymbolInfo(addr)
                fname = ret[1]
                offset = long(ret[2], 16)
                inst = instance.loadInst(fname, offset)
                instance.writeMem(addr, inst, skipCheck=True)

        # remove all breakpoints for the thread group leader #
        if tgid == instance.pid:
            origPrintFlag = SysMgr.printEnable
            SysMgr.printEnable = True
            if not instance.execCmd:
                # block signal #
                SysMgr.blockSignal(act="block")

                instance.removeAllBp(tgid)

                # unblock signal #
                SysMgr.blockSignal(act="unblock")

            SysMgr.printEnable = origPrintFlag

        # remove new breakpoints for children after fork #
        for addr in list(instance.bpNewList):
            instance.removeBp(addr)

        instance.__del__(stop=True)

        # draw timeline segment #
        _printTimeline()

        # terminate immediately to avoid memory increase due to COW by GC #
        if tgid != instance.pid:
            Debugger.printSummary(instance)

            # release all resources #
            SysMgr.releaseResource()

            os._exit(0)

    @staticmethod
    def printCallHistory(instance, name=None):
        if not instance.callPrint:
            return

        try:
            elapsed = instance.callList[-1][1] - instance.start
        except:
            elapsed = instance.last - instance.start

        nrLine = UtilMgr.convNum(len(instance.callPrint))
        callStr = "\n".join(instance.callPrint)
        procInfo = "%s(%s)" % (instance.comm, instance.pid)

        SysMgr.printPipe(
            "\n[Trace %s History] [%s] [Time: %f] [Line: %s]\n%s\n%s\n%s"
            % (name, procInfo, elapsed, nrLine, twoLine, callStr, oneLine)
        )

    @staticmethod
    def printSummary(instance):
        def _printSystemStat():
            # save system info #
            SysMgr.saveSysStats()
            SysMgr.printInfoBuffer()

        # check realtime mode #
        if not SysMgr.outPath or SysMgr.jsonEnable:
            return
        elif (
            not instance.callList and not "FORCESUMMARY" in SysMgr.environList
        ):
            SysMgr.printWarn(
                "no sample data to summarize for %s(%s)"
                % (instance.comm, instance.pid),
                True,
            )
            return

        # summarize samples after last tick #
        if instance.isRealtime and (
            SysMgr.repeatCount == 0 or SysMgr.progressCnt < SysMgr.repeatCount
        ):
            instance.printIntervalSummary()
        else:
            instance.last = time.time()

        callTable = {}
        fileTable = {}
        elapsedTable = []

        # define stop flag #
        needStop = False

        # check mode and define type variables #
        if instance.mode == "syscall":
            ctype = "Syscall"
            if Debugger.envFlags["INTERCALL"]:
                addInfo = "<Interval>"
            else:
                addInfo = "<Elapsed>"
        elif instance.mode == "break":
            ctype = "Breakcall"
            addInfo = "[PATH] <Elapsed>"
        elif instance.mode == "pybreak":
            ctype = "Pycall"
            addInfo = "[PATH] <Elapsed>"
        else:
            addInfo = "[Path]"
            if instance.mode == "pycall":
                ctype = "Pycall"
            else:
                ctype = "Usercall"

            # continue target to prevent too long freezing #
            if instance.traceStatus and instance.isAlive():
                try:
                    sig = 0
                    ret = os.waitpid(instance.pid, os.WNOHANG)
                    if ret and ret[1] > 0:
                        sig = instance.getStatus(ret[1])
                    if (
                        sig != signal.SIGSTOP
                        and instance.cont(check=True, sig=sig) == 0
                    ):
                        needStop = True
                except:
                    pass

        if instance.isRealtime:
            mtype = "Top"
        else:
            mtype = "Trace"
        suffix = "\n"

        # update suffix of output file name #
        SysMgr.fileSuffix = "%s_%s_%s" % (
            instance.comm,
            instance.pid,
            SysMgr.pid,
        )

        # print logo #
        if not SysMgr.printFd:
            SysMgr.printLogo(big=True, onlyFile=True)

        # print System Info #
        _printSystemStat()

        SysMgr.printInfo(
            "start analyzing calls of %s(%s)..."
            % (instance.comm, instance.pid)
        )

        nrTotal = float(len(instance.callList))

        # check incomplete break mode #
        if not Debugger.envFlags["COMPLETECALL"] and instance.mode == "break":
            isIncompleteBreakMode = True
        else:
            isIncompleteBreakMode = False

        # iterate the call sample list #
        for idx, item in enumerate(instance.callList):
            try:
                symbol, timestamp, filename = item

                # skip breakpoints for return #
                if isIncompleteBreakMode and symbol.endswith(Debugger.RETSTR):
                    nrTotal -= 1
                    continue

                # convert anonymous call to filename #
                if symbol == "??":
                    symbol = filename

                # add to symbol table #
                try:
                    callTable[symbol]["cnt"] += 1
                except:
                    callTable[symbol] = {
                        "cnt": 1,
                        "path": filename,
                    }

                UtilMgr.printProgress(idx, len(instance.callList))

                if instance.mode == "syscall":
                    continue

                # add to file table #
                try:
                    fileTable[filename]["cnt"] += 1
                except:
                    fileTable[filename] = {"cnt": 1}
            except SystemExit:
                UtilMgr.deleteProgress()

                # stop target to return original status #
                if needStop:
                    instance.stop(check=True)

                return
            except:
                pass

        if instance.callList:
            UtilMgr.deleteProgress()

        # print call table #
        convert = UtilMgr.convNum
        try:
            elapsed = instance.callList[-1][1] - instance.start
        except:
            elapsed = instance.last - instance.start

        # get sample info #
        try:
            maxSample = elapsed / instance.sampleTime
            perSample = "%.1f" % (nrTotal / maxSample * 100)
        except:
            perSample = "100"

        # get sampling period #
        if instance.sampleTime > 0:
            samplingStr = " [Freq: %s] " % UtilMgr.convFloat2Str(
                instance.sampleTime
            )
            freqStr = "(%s%%)" % perSample
        else:
            samplingStr = ""
            freqStr = ""

        # set task info #
        procInfo = "%s(%s)" % (instance.comm, instance.pid)
        mprocInfo = "%s(%s)" % (
            Debugger.tracerInstance.comm,
            Debugger.tracerInstance.pid,
        )

        # average CPU usage for target #
        nrCpuUsageSample = len(instance.cpuUsageList)
        if nrCpuUsageSample > 0:
            # calculate average CPU usage #
            ttime = utime = stime = ctime = 0
            for cpustat in instance.cpuUsageList:
                ttime += cpustat[0]
                utime += cpustat[1]
                stime += cpustat[2]
                ctime += cpustat[3]
            ttime /= float(nrCpuUsageSample)
            utime /= float(nrCpuUsageSample)
            stime /= float(nrCpuUsageSample)
            ctime /= float(nrCpuUsageSample)

            cpuStr = "%d%%(U%d%%+S%d%%)" % (ttime, utime, stime)
            cpuStr = "[%s: %s] " % (procInfo, cpuStr)

            sysStr = "[SYS: %d%%/%s] " % (ctime, SysMgr.getAvailMemInfo())
        else:
            sysStr = " "
            cpuStr = "[%s] " % procInfo

        # average CPU usage for myself #
        if instance.selfCpuUsageList:
            mttime = sum(instance.selfCpuUsageList)
            mttime /= float(len(instance.selfCpuUsageList))
            rssStr = Debugger.tracerInstance.getMemUsage()
            mStr = "[%s: %d%%/%s]" % (mprocInfo, mttime, rssStr)
        else:
            mStr = "[%s]" % mprocInfo

        # set error count #
        if instance.errCnt:
            errstr = "[Err: %s] " % convert(instance.errCnt)
        else:
            errstr = ""

        # print top stat #
        SysMgr.printPipe(
            (
                "\n[%s %s Summary] [Elapsed: %.3f]%s%s%s%s "
                "[Sample: %s%s] %s[Symbol: %s] %s"
            )
            % (
                mtype,
                ctype,
                elapsed,
                samplingStr,
                sysStr,
                cpuStr,
                mStr,
                convert(long(nrTotal)),
                freqStr,
                errstr,
                convert(len(callTable)),
                suffix,
            )
        )
        SysMgr.printPipe(
            "{3:1}{0:^7} | {1:<144}{2:1}{3:1}".format(
                "Usage", "Function %s" % addInfo, suffix, twoLine + suffix
            )
        )

        tcnt = 0
        for sym, value in sorted(
            callTable.items(), key=lambda x: x[1]["cnt"], reverse=True
        ):
            cnt = value["cnt"]

            # get percentage #
            try:
                per = cnt / nrTotal * 100
            except:
                break

            # add stats #
            if instance.mode == "syscall":
                # add time stats #
                if sym in instance.syscallTotalStat:
                    vals = instance.syscallTotalStat[sym]
                    addVal = "<Tot: %.6f, Avg: %.6f, Max: %.6f> <Cnt: %s>" % (
                        vals[0],
                        vals[0] / float(cnt),
                        vals[1],
                        convert(cnt),
                    )
                elif sym in instance.syscallStat:
                    vals = instance.syscallStat[sym]
                    addVal = "<Tot: %.6f, Avg: %.6f, Max: %.6f> <Cnt: %s>" % (
                        vals[0],
                        vals[0] / float(cnt),
                        vals[1],
                        convert(cnt),
                    )
                else:
                    addVal = "<Cnt: %s>" % convert(cnt)
            elif instance.isBreakMode:
                addVal = "[%s] <Cnt: %s" % (
                    value["path"],
                    convert(cnt),
                )

                # set symbol #
                if sym.endswith(Debugger.RETSTR):
                    rsym = sym
                else:
                    rsym = sym + Debugger.RETSTR

                # add return stats #
                if (
                    rsym in instance.callTable
                    and "elapsed" in instance.callTable[rsym]
                    and instance.callTable[rsym]["elapsed"] > 0
                ):
                    val = instance.callTable[rsym]
                    addVal = (
                        "%s, Elapsed: %.6f, Avg: %.6f, Min: %.6f, Max: %.6f"
                        % (
                            addVal,
                            val["elapsed"],
                            val["elapsed"] / val["cnt"],
                            val["min"],
                            val["max"],
                        )
                    )

                    elapsedTable.append(val["elapsed"])

                addVal += ">"
            else:
                addVal = "[%s] <Cnt: %s>" % (
                    value["path"],
                    convert(cnt),
                )

            # convert path to anonymous symbol #
            if sym[0] == "/":
                targetSym = "??"
            else:
                targetSym = sym

            SysMgr.printPipe(
                "{0:>7} | {1:<144}{2:1}".format(
                    "%.1f%%" % per, "%s %s" % (targetSym, addVal), suffix
                )
            )

            # add backtraces #
            if sym in instance.btTable:
                for bt, btcnt in sorted(
                    instance.btTable[sym].items(),
                    key=lambda x: x[1],
                    reverse=True,
                ):
                    # print backtrace and percent #
                    bper = btcnt / float(cnt) * 100
                    ret = SysMgr.printPipe(
                        "{0:>17} | {1:<1} <Cnt: {2:1}>".format(
                            "%.1f%%" % bper, bt, convert(btcnt)
                        )
                    )

            tcnt += 1

        if tcnt == 0:
            SysMgr.printPipe("\tNone%s" % suffix)

        SysMgr.printPipe(oneLine + suffix)

        # print histo stats for elapsed time #
        if elapsedTable:
            elapsedTable = UtilMgr.convList2Histo(elapsedTable, mult=1000000)
            UtilMgr.printHist(elapsedTable, "elapsed", "us")

        # print file table #
        if fileTable:
            SysMgr.printPipe(
                (
                    "\n[%s File Summary] [Elapsed: %.3f]%s%s%s%s "
                    "[NrSamples: %s(%s%%)] [NrFiles: %s] %s"
                )
                % (
                    mtype,
                    elapsed,
                    samplingStr,
                    sysStr,
                    cpuStr,
                    mStr,
                    convert(long(nrTotal)),
                    perSample,
                    convert(len(fileTable)),
                    suffix,
                )
            )
            SysMgr.printPipe(
                "{3:1}{0:^7} | {1:<144}{2:1}{3:1}".format(
                    "Usage", "Path", suffix, twoLine + suffix
                )
            )

            tcnt = 0
            for filename, value in sorted(
                fileTable.items(), key=lambda x: x[1]["cnt"], reverse=True
            ):
                try:
                    per = value["cnt"] / nrTotal * 100
                except:
                    break

                SysMgr.printPipe(
                    "{0:>7} | {1:<144}{2:1}".format(
                        "%.1f%%" % per, filename, suffix
                    )
                )

                tcnt += 1

            if tcnt == 0:
                SysMgr.printPipe("\tNone%s" % suffix)

            SysMgr.printPipe(oneLine + suffix)

        # print history #
        instance.printCallHistory(instance, ctype)

        # stop target to return original status #
        if needStop:
            instance.stop(check=True)

        try:
            outFile = SysMgr.printFd.name
            SysMgr.printInfo(
                "saved the results into '%s' successfully"
                % SysMgr.printFd.name
            )
        except:
            pass

        # check realtime mode #
        if not SysMgr.procBuffer:
            return

        # print detailed statistics #
        SysMgr.printProcBuffer(suffix)

    @staticmethod
    def checkPtraceScope():
        filePath = "%s/sys/kernel/yama/ptrace_scope" % SysMgr.procPath

        try:
            with open(filePath, "r") as fd:
                """
                0 - classic ptrace permissions: a process can PTRACE_ATTACH to any other
                process running under the same uid, as long as it is dumpable (i.e.
                did not transition uids, start privileged, or have called
                prctl(PR_SET_DUMPABLE...) already). Similarly, PTRACE_TRACEME is
                unchanged.

                1 - restricted ptrace: a process must have a predefined relationship
                with the inferior it wants to call PTRACE_ATTACH on. By default,
                this relationship is that of only its descendants when the above
                classic criteria is also met. To change the relationship, an
                inferior can call prctl(PR_SET_PTRACER, debugger, ...) to declare
                an allowed debugger PID to call PTRACE_ATTACH on the inferior.
                Using PTRACE_TRACEME is unchanged.

                2 - admin-only attach: only processes with CAP_SYS_PTRACE may use ptrace
                with PTRACE_ATTACH, or through children calling PTRACE_TRACEME.

                3 - no attach: no processes may use ptrace with PTRACE_ATTACH nor via
                PTRACE_TRACEME. Once set, this sysctl value cannot be changed.
                """
                perm = long(fd.readline()[:-1])
                if perm == 3:
                    SysMgr.printErr(
                        (
                            "failed to use ptrace because it is not allowed, "
                            "check %s"
                        )
                        % filePath
                    )
                    return -1
                return 0
        except:
            return 0

    @staticmethod
    def dumpTaskMemory(pid, meminfo, output):
        SysMgr.checkRootPerm()

        # check ptrace scope #
        if Debugger.checkPtraceScope() < 0:
            return

        # dump memory #
        try:
            dobj = Debugger(pid=pid)
            if not dobj:
                raise Exception("N/A")
            ret = dobj.dumpMemory(meminfo, output)
            if ret == 0:
                raise Exception("N/A")
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to dump memory for %s(%s)"
                % (SysMgr.getComm(pid), pid),
                reason=True,
            )

    @staticmethod
    def pauseThreads(tlist):
        def _updateTargets(taskList):
            dlist = []
            tlist = list(taskList)

            for tid in tlist:
                if not SysMgr.isAlive(tid):
                    dlist.append(tid)

            for tid in list(set(dlist)):
                SysMgr.printWarn(
                    "terminated %s(%s)" % (taskList[tid], tid), True
                )
                taskList.pop(tid, None)

            return taskList

        # check thread list #
        if not tlist:
            return False

        SysMgr.checkRootPerm()

        # check ptrace scope #
        if Debugger.checkPtraceScope() < 0:
            return False

        # set alarm #
        signal.signal(signal.SIGALRM, SysMgr.onAlarm)
        signal.alarm(SysMgr.intervalEnable)

        taskList = {}
        lastTid = 0
        try:
            for tid in tlist:
                lastTid = long(tid)

                ret = SysMgr.createProcess(mute=True, chPgid=True)
                if ret > 0:
                    comm = SysMgr.getComm(tid)
                    taskList[tid] = comm
                    SysMgr.printInfo("paused %s(%s)" % (comm, lastTid))
                elif ret == 0:
                    dobj = Debugger(pid=lastTid)
                    SysMgr.waitEvent(ignChldSig=False)
                    dobj.__del__()
                    sys.exit(0)
                else:
                    SysMgr.printErr("failed to create a process")
                    sys.exit(-1)

            # wait for user event to continue threads #
            while 1:
                SysMgr.waitEvent(ignChldSig=False, exit=True)
                taskList = _updateTargets(taskList)
                SysMgr.updateChildList()
                if SysMgr.isNoChild():
                    break

            SysMgr.printErr("no target thread")
        except SystemExit:
            return
        except:
            SysMgr.printErr("failed to pause thread %s" % lastTid, True)
        finally:
            # send SIGCONT to targets #
            for tid in tlist:
                try:
                    SysMgr.syscall("tkill", tid, signal.SIGCONT)
                except:
                    pass

    def getSigInfo(self):
        PTRACE_GETSIGINFO = 0x4202
        ret = self.ptrace(PTRACE_GETSIGINFO, data=addressof(self.sigObj))
        return ret

    def setSigInfo(self):
        PTRACE_SETSIGINFO = 0x4203
        ret = self.ptrace(PTRACE_SETSIGINFO, data=addressof(self.sigObj))
        return ret

    def checkCloned(self, status):
        stat = status >> 8
        if (
            stat == self.sigCloneFlag
            or stat == self.sigForkFlag
            or stat == self.sigVforkFlag
        ):
            return True
        else:
            return False

    def isForked(self, status):
        stat = status >> 8
        return stat == self.sigForkFlag or stat == self.sigVforkFlag

    def isExited(self, status):
        return status >> 8 == self.sigExitFlag

    def isExeced(self, status):
        return status >> 8 == self.sigExecFlag

    def isCloned(self, status):
        return status >> 8 == self.sigCloneFlag

    def getEventMsg(self):
        PTRACE_GETEVENTMSG = 0x4201
        data = c_long(0)
        addr = addressof(data)

        ret = self.ptrace(PTRACE_GETEVENTMSG, data=addr)
        return data.value

    def getStatus(self, status):
        ret = None

        if os.WIFEXITED(status):
            code = os.WEXITSTATUS(status)
            ret = -1

        # Process killed by a signal #
        elif os.WIFSIGNALED(status):
            signum = os.WTERMSIG(status)
            ret = signum

        # Invalid process status #
        elif not os.WIFSTOPPED(status):
            pass

        # Ptrace Event #
        elif status >> 8 == 0:
            ret = status >> 16

        # Process stopped by a signal #
        else:
            signum = os.WSTOPSIG(status)
            ret = signum

        return ret

    def setPC(self, val):
        if self.arch == "aarch64":
            self.regs.pc = val
        elif self.arch == "x64":
            self.regs.rip = val
        elif self.arch == "arm":
            self.regs.r15 = val
        elif self.arch == "x86":
            self.regs.eip = val

    def setSP(self, val):
        if self.arch == "aarch64":
            self.regs.sp = val
        elif self.arch == "x64":
            self.regs.rsp = val
        elif self.arch == "arm":
            self.regs.r13 = val
        elif self.arch == "x86":
            self.regs.esp = val

    def setLR(self, val):
        if self.arch == "aarch64":
            self.regs.x30 = val
        elif self.arch == "arm":
            self.regs.r14 = val

    def setRegs(self, temp=False, newObj=None):
        pid = self.pid
        wordSize = ConfigMgr.wordSize

        # read registers #
        try:
            if not self.supportSetRegset:
                raise Exception("not support setregset")

            cmd = PTRACE_SETREGSET = 0x4205
            NT_PRSTATUS = 1
            nrWords = sizeof(self.regs) * wordSize

            if newObj:
                addr = addressof(self.getIovec(newObj))
            elif temp:
                addr = addressof(self.tempIovecObj)
            else:
                addr = addressof(self.iovecObj)

            ret = self.ptrace(cmd, NT_PRSTATUS, addr)
            if ret != 0:
                raise Exception("setregset failure")
        except SystemExit:
            sys.exit(0)
        except:
            self.supportSetRegset = False

            if newObj:
                addr = addressof(newObj)
            elif temp:
                addr = addressof(self.tempRegs)
            else:
                addr = addressof(self.regs)

            cmd = self.setregsCmd

            ret = self.ptrace(cmd, 0, addr)

        # check ret value #
        if ret >= 0:
            return True

        if not self.isAlive():
            SysMgr.printErr("terminated %s(%s)" % (self.comm, self.pid))
            sys.exit(0)

        SysMgr.printErr(
            "failed to write remote registers for %s(%s) because %s"
            % (self.comm, self.pid, self.errmsg)
        )

        return False

    def restoreRegs(self, bt=False):
        if bt:
            target = self.btRegs
        else:
            target = self.tempRegs

        memmove(addressof(self.regs), addressof(target), sizeof(self.regs))

        self.updateNamedRegs()

    def backupRegs(self, bt=False):
        if bt:
            target = self.btRegs
        else:
            target = self.tempRegs

        memmove(addressof(target), addressof(self.regs), sizeof(self.regs))

    def getFpRegs(self, temp=False):
        pid = self.pid
        wordSize = ConfigMgr.wordSize

        if temp:
            addr = addressof(self.tempFpRegs)
        else:
            addr = addressof(self.fpregs)

        cmd = self.getfpregsCmd

        ret = self.ptrace(cmd, 0, addr)
        if ret != 0:
            if not self.isAlive():
                SysMgr.printErr("terminated %s(%s)" % (self.comm, self.pid))
                sys.exit(0)

            SysMgr.printErr(
                "failed to get fp register set of %s(%s) because %s"
                % (self.comm, self.pid, self.errmsg)
            )

        return ret

    def getRegs(self, temp=False, new=False):
        pid = self.pid
        wordSize = ConfigMgr.wordSize

        if new:
            newObj = self.getRegStruct()

        # read registers #
        try:
            if not self.supportGetRegset:
                raise Exception("not support getregset")

            if new:
                addr = addressof(self.getIovec(newObj))
            elif temp:
                addr = addressof(self.tempIovecObj)
            else:
                addr = addressof(self.iovecObj)

            # PTRACE_GETREGSET #
            cmd = 0x4204
            NT_PRSTATUS = 1

            ret = self.ptrace(cmd, NT_PRSTATUS, addr)
            if ret != 0:
                raise Exception("getregset failure")
        except SystemExit:
            sys.exit(0)
        except:
            self.supportGetRegset = False

            if new:
                addr = addressof(newObj)
            elif temp:
                addr = addressof(self.tempRegs)
            else:
                addr = addressof(self.regs)

            cmd = self.getregsCmd
            ret = self.ptrace(cmd, 0, addr)

        # handle error #
        if ret != 0:
            if not self.isAlive():
                SysMgr.printErr("terminated %s(%s)" % (self.comm, self.pid))
                sys.exit(0)

            errMsg = "failed to read registers for %s(%s)" % (
                self.comm,
                self.pid,
            )

            # check state #
            if self.isStopped():
                SysMgr.printWarn("%s because %s" % (errMsg, self.errmsg))
            else:
                SysMgr.printWarn("%s because it is not stopped" % errMsg)

        # return result #
        if new:
            return newObj
        else:
            return ret

    def updateNamedRegs(self):
        if self.arch == "arm":
            self.fp = self.regs.r11
            self.sp = self.regs.r13
            self.lr = self.regs.r14
            self.pc = self.regs.r15
        elif self.arch == "aarch64":
            self.fp = self.regs.x29
            self.lr = self.regs.x30
            self.sp = self.regs.sp
            self.pc = self.regs.pc
        elif self.arch == "x86":
            self.fp = self.regs.ebp
            self.sp = self.regs.esp
            self.pc = self.regs.eip
        elif self.arch == "x64":
            # no use rbp as frame pointer #
            self.fp = self.regs.rbp
            self.sp = self.regs.rsp
            self.pc = self.regs.rip

    def updateRegs(self):
        if self.getRegs() != 0:
            return False

        self.updateNamedRegs()

        return True

    def dumpMemory(self, meminfo, output, verb=True):
        if meminfo in ("heap", "stack"):
            meminfo = "[%s]" % meminfo

        # get range info #
        self.updateProcMap()
        ret = FileAnalyzer.getMapAddr(self.pid, meminfo, self.mapFd)
        if not ret:
            ret = meminfo.split("-")
            if not ret:
                SysMgr.printErr(
                    "failed to search %s on memory map for %s(%s)"
                    % (meminfo, self.comm, self.pid)
                )
                return 0

        # convert range #
        start = UtilMgr.convStr2Num(ret[0], onlyHex=True)
        if not start:
            return 0
        end = UtilMgr.convStr2Num(ret[1], onlyHex=True)
        if not end:
            return 0
        size = end - start

        # print status #
        if verb:
            SysMgr.printInfo(
                "start dumping memory %s-%s [%s] for %s(%s)"
                % (
                    hex(start).rstrip("L"),
                    hex(start + size).rstrip("L"),
                    UtilMgr.convSize2Unit(size),
                    self.comm,
                    self.pid,
                )
            )

        # backup #
        SysMgr.backupFile(output)

        # open output file #
        try:
            fd = open(output, "wb")
            os.chmod(output, 0o777)
        except:
            SysMgr.printOpenErr(output)
            return 0

        # handle SAVEBITMAP variable #
        if "SAVEBITMAP" in SysMgr.environList:
            # get page-aligned size #
            pageSize = SysMgr.PAGESIZE
            tsize = long((size + pageSize - 1) / pageSize)
            rsize = tsize * pageSize

            # init bitmap #
            table = [0] * tsize

            # check present bit for each page #
            for idx in range(tsize):
                entry = PageAnalyzer.getPagemapEntry(
                    self.pid, start + (idx * pageSize)
                )
                res = PageAnalyzer.isPresent(entry)
                if res:
                    table[idx] = 1

            # write memory to file #
            btable = bytes(table)
            fd.write(btable)
            fd.close()

            # close output file for sync #
            if verb:
                # get output size #
                fsize = UtilMgr.getFileSizeStr(output)

                SysMgr.printStat(
                    "saved the bitmap data to '%s'%s successfully"
                    % (output, fsize)
                )

            return size

        # define buffer and chunk size #
        offset = start
        chunk = UtilMgr.convUnit2Size("10MB")
        total = 0

        # copy data from target memory #
        while size > 0:
            if size < chunk:
                chunk = size
                size = 0
            else:
                size -= chunk

            # read memory from target #
            buf = self.readMem(offset, chunk)

            # write memory to file #
            fd.write(buf)

            if verb:
                UtilMgr.printProgress(total, size)

            offset += chunk
            total += len(buf)

        if verb:
            UtilMgr.deleteProgress()

        # close output file for sync #
        if verb:
            SysMgr.printStat(
                "start writing dump data [%s] to %s"
                % (UtilMgr.convSize2Unit(total), output)
            )

        fd.close()

        return total

    def ptraceEvent(self, reqList):
        # define architect-independent constant #
        PTRACE_SETOPTIONS = 0x4200

        option = 0
        plist = ConfigMgr.PTRACE_EVENT_TYPE

        for req in reqList:
            if req == "PTRACE_O_TRACESYSGOOD":
                option |= 1
            elif req == "PTRACE_O_TRACEEXEC":
                option |= 1 << plist.index("PTRACE_EVENT_EXEC")
            elif req == "PTRACE_O_TRACEEXIT":
                option |= 1 << plist.index("PTRACE_EVENT_EXIT")
            elif req == "PTRACE_O_TRACESECCOMP":
                option |= 1 << plist.index("PTRACE_EVENT_SECCOMP")
            elif SysMgr.cloneEnable or self.isBreakMode:
                if req == "PTRACE_O_TRACEFORK":
                    option |= 1 << plist.index("PTRACE_EVENT_FORK")
                elif req == "PTRACE_O_TRACEVFORK":
                    option |= 1 << plist.index("PTRACE_EVENT_VFORK")
                elif req == "PTRACE_O_TRACECLONE":
                    option |= 1 << plist.index("PTRACE_EVENT_CLONE")
                elif req == "PTRACE_O_TRACEVFORKDONE":
                    option |= 1 << plist.index("PTRACE_EVENT_VFORK_DONE")

        return self.ptrace(PTRACE_SETOPTIONS, 0, option)

    def waitpid(self, pid=None):
        """
        # Don't wait on children of other threads in this group #
        __WNOTHREAD = 0x20000000

        # Wait on all children, regardless of type #
        __WALL = 0x40000000

        # Wait only on non-SIGCHLD children #
        __WCLONE = 0x80000000
        """

        try:
            # init variables #
            ret = 0
            status = c_uint(0)
            waitpid = SysMgr.libcObj.waitpid
            if not pid:
                pid = self.pid

            # type converting #
            if not self.initWaitpid:
                waitpid.argtypes = (c_int, POINTER(None), c_int)
                waitpid.restype = c_int
                self.initWaitpid = True

            while 1:
                # wait for children #
                try:
                    ret = waitpid(pid, pointer(status), 0x40000000)
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

                # check termination #
                if ret == -1:
                    if not self.isAlive():
                        sys.exit(0)

                break

            return ret, status.value
        except SystemExit:
            sys.exit(0)
        except Exception as ex:
            # handle exception error during exit #
            if type(ex).__name__ == "TypeError":
                sys.exit(-1)

            SysMgr.printWarn("failed to call waitpid", reason=True)

            return 0, 0

    def ptrace(self, req, addr=0, data=0, pid=None):
        if pid is None:
            pid = self.pid

        """
        # try to call native ptrace call #
        try:
            return SysMgr.guiderObj.ptrace(req, pid, addr, data)
        except SystemExit: sys.exit(0)
        except: pass
        """

        try:
            # type converting #
            if not self.initPtrace:
                SysMgr.libcObj.ptrace.argtypes = (
                    c_ulong,
                    c_ulong,
                    c_ulong,
                    c_ulong,
                )
                SysMgr.libcObj.ptrace.restype = c_ulong
                self.initPtrace = True

            # ptrace #
            ret = SysMgr.libcObj.ptrace(req, pid, addr, data)
            if not ret:
                return ret
            elif c_long(ret).value == -1:
                self.errmsg = SysMgr.getErrReason()
                return -1
            else:
                return ret
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("failed to call ptrace", reason=True)
            return -1


class EventAnalyzer(object):
    """Analyzer for event"""

    eventData = {}

    def __init__(self):
        pass

    def __del__(self):
        pass

    @staticmethod
    def addEvent(time, event):
        eventData = EventAnalyzer.eventData

        # ramdom event #
        if len(event.split(":")) == 1:
            name = event
            ID = None
        # sequantial event #
        else:
            name = event.split(":")[0]
            ID = event.split(":")[1]

        try:
            eventData[name]
            """
            {'list': [ID, time, number],
            'summary': [ID, cnt, avr, min, max, first, last]}
            """
        except:
            eventData[name] = {"list": [], "summary": []}

        eventData[name]["list"].append(
            [ID, time, sum(t[0] == ID for t in eventData[name]["list"]) + 1]
        )

        if sum(id[0] == ID for id in eventData[name]["summary"]) == 0:
            eventData[name]["summary"].append([ID, 1, -1, -1, -1, time, time])
        else:
            for n in eventData[name]["summary"]:
                if n[0] == ID:
                    n[1] += 1
                    n[6] = time
                    break

    @staticmethod
    def printEventInfo():
        eventData = EventAnalyzer.eventData

        if eventData:
            SysMgr.printPipe(
                "\n[%s] [Total: %d]\n%s"
                % ("Event Info", len(eventData), twoLine)
            )
            try:
                EventAnalyzer.printEvent()
            except SystemExit:
                sys.exit(0)
            except:
                pass
            SysMgr.printPipe(twoLine)

    @staticmethod
    def printEvent():
        eventData = EventAnalyzer.eventData
        startTime = float(SysMgr.startTime)

        for key, value in sorted(
            eventData.items(), key=lambda x: float(x[1]["summary"][0][5])
        ):
            string = ""
            head = "%10s: [total: %s] [subEvent: %s] " % (
                key,
                len(eventData[key]["list"]),
                len(eventData[key]["summary"]),
            )
            for idx, n in enumerate(
                sorted(eventData[key]["summary"], key=lambda slist: slist[0])
            ):
                if idx == 0:
                    msg = head
                else:
                    msg = " " * len(head)

                if not n[0]:
                    n[0] = "MAIN"

                try:
                    string = (
                        "%s[%8s > cnt: %3d, avr: %3d, min: %3d,"
                        "max: %3d, first: %7.3f, last: %7.3f]"
                    ) % (
                        msg,
                        n[0],
                        n[1],
                        n[2],
                        n[3],
                        n[4],
                        float(n[5]) - startTime,
                        float(n[6]) - startTime,
                    )
                except:
                    pass

                SysMgr.printPipe("%s" % string)


class MemoryFile(object):
    """File object for memory region"""

    def __init__(self, addr=0, size=4096, name=None):
        self.pos = 0
        self.addr = addr
        self.size = size
        self.name = name

        if addr == 0:
            self.mem = bytearray(size)
        else:
            self.resize(size)

    def resize(self, size):
        SysMgr.importPkgItems("ctypes")

        # orig #
        orig = self.mem
        optr = (c_char * len(orig)).from_buffer(orig)

        # new #
        self.mem = bytearray(size)
        nptr = (c_char * size).from_buffer(self.mem)

        # memcpy #
        ret = memmove(nptr, optr, len(orig))
        if ret < 0:
            SysMgr.printErr("failed to copy memory from %s" % self.addr)
        else:
            self.size = size

        return ret

    def getsize(self):
        return len(self.mem)

    def read(self, size):
        des = self.pos + size

        if des > self.size:
            self.resize(des)

        segment = self.mem[self.pos : des]

        self.pos += size

        return bytes(segment)

    def write(self, buf):
        self.mem = self.mem[: self.pos] + buf + self.mem[self.pos + len(buf) :]
        self.pos += len(buf)

    def tell(self):
        return self.pos

    def seek(self, pos):
        self.pos = pos

    def __iter__(self):
        return self

    def __next__(self):
        while 1:
            if self.pos == len(self.mem) - 1:
                raise StopIteration

            data = self.mem[self.pos :]
            try:
                data = data.decode()
            except:
                pass

            # find newline #
            pos = data.find("\n")

            # newline #
            if pos == 0:
                self.pos += 1
                return ""

            # EOF #
            if pos < 0:
                self.pos = len(self.mem) - 1
                return data

            # return a line #
            self.pos += pos
            return data[self.pos : self.pos + pos]

    def next(self):
        return self.__next__()


class ElfAnalyzer(object):
    """Analyzer for ELF object"""

    SHF_WRITE = 0x1
    SHF_ALLOC = 0x2
    SHF_EXECINSTR = 0x4
    SHF_MASKPROC = 0xF0000000

    DT_VERSIONTAGNUM = 16

    rustChars = [
        [",", "$C$"],
        ["@", "$SP$"],
        ["*", "$BP$"],
        ["&", "$RF$"],
        ["<", "$LT$"],
        [">", "$GT$"],
        ["(", "$LP$"],
        [")", "$RP$"],
        [" ", "$u20$"],
        ["'", "$u27$"],
        ["[", "$u5b$"],
        ["]", "$u5d$"],
        ["~", "$u7e$"],
        ["{", "$u7b$"],
        ["}", "$u7d$"],
        ["::", ".."],
        ["-", "."],
    ]

    PT_FLAGS = {
        0: "None",
        1: "E",
        2: "W",
        3: "WE",
        4: "R",
        5: "RE",
        6: "RW",
        7: "RWE",
    }

    PT_TYPE = {
        0: "NULL",
        1: "LOAD",
        2: "DYNAMIC",
        3: "INTERP",
        4: "NOTE",
        5: "SHLIB",
        6: "PHDR",
        7: "TLS",
        8: "NUM",
        "LOOS": 0x60000000,
        "HIOS": 0x6FFFFFFF,
        0x60000000: "LOOS",
        0x6FFFFFFF: "HIOS",
        0x70000000: "LOPROC",
        0x7FFFFFFF: "HPROC",
        0x6474E550: "GNU_EH_FRAME",
        0x6474E551: "GNU_STACK",
        0x6474E552: "GNU_RELRO",
    }

    ST_TYPE = {
        0: "NOTYPE",
        1: "OBJECT",
        2: "FUNC",
        3: "SECTION",
        4: "FILE",
        5: "COMMON",
        6: "TLS",
        7: "NUM",
        10: "LOOS",
        12: "HIOS",
        13: "LOPROC",
        15: "HIPROC",
    }

    ST_BIND_TYPE = {
        0: "LOCAL",
        1: "GLOBAL",
        2: "WEAK",
        3: "NUM",
        10: "LOOS",
        12: "HIOS",
        13: "LOPROC",
        15: "HIPROC",
    }

    ST_VISIBILITY_TYPE = {
        0: "DEFAULT",
        1: "INTERNAL",
        2: "HIDDEN",
        3: "PROTECTED",
    }

    SH_TYPE = {
        0: "NULL",
        1: "PROGBITS",
        2: "SYMTAB",
        3: "STRTAB",
        4: "RELA",
        5: "HASH",
        6: "DYNAMIC",
        7: "NOTE",
        8: "NOBITS",
        9: "REL",
        10: "SHLIB",
        11: "DYNSYM",
        12: "NUM",
        14: "INIT_ARRAY",
        15: "FINI_ARRAY",
        16: "PREINIT_ARRAY",
        17: "GROUP",
        18: "SYMTAB_SHNDX",
        19: "NUM",
        0x60000000: "LOOS",
        0x6FFFFFFF: "HIOS",
        0x70000000: "LOPROC",
        0x7FFFFFFF: "HIPROC",
        0x80000000: "LOUSER",
        0xFFFFFFFF: "HIUSER",
        0x6FFFFFF5: "GNU_ATTRIBUTES",
        0x6FFFFFF6: "GNU_HASH",
        0x6FFFFFF7: "GNU_LIBLIST",
        0x6FFFFFF8: "CHECKSUM",
        0x6FFFFFFA: "LOSUNW",
        0x6FFFFFFA: "SUNW_move",
        0x6FFFFFFB: "SUNW_COMDAT",
        0x6FFFFFFC: "SUNW_syminfo",
        0x6FFFFFFD: "GNU_verdef",
        0x6FFFFFFE: "GNU_verneed",
        0x6FFFFFFF: "GNU_versym",
    }

    SHN_TYPE = {
        0: "SHN_UNDEF",  # Undefined section #
        0xFF00: "SHN_LORESERVE",  # Start of reserved indices #
        0xFF00: "SHN_LOPROC",  # Start of processor-specific #
        0xFF00: "SHN_BEFORE",  # Order section before all others #
        0xFF01: "SHN_AFTER",  # Order section after all others #
        0xFF1F: "SHN_HIPROC",  # End of processor-specific #
        0xFF20: "SHN_LOOS",  # Start of OS-specific #
        0xFF3F: "SHN_HIOS",  # End of OS-specific #
        0xFFF1: "SHN_ABS",  # Associated symbol is absolute #
        0xFFF2: "SHN_COMMON",  # Associated symbol is common #
        0xFFFF: "SHN_XINDEX",  # Index is in extra table. #
        0xFFFF: "SHN_HIRESERVE",  # End of reserved indices #
    }

    DT_TYPE = {
        0: "NULL",
        1: "NEEDED",
        2: "PLTRELSZ",
        3: "PLTGOT",
        4: "HASH",
        5: "STRTAB",
        6: "SYMTAB",
        7: "RELA",
        8: "RELASZ",
        9: "RELAENT",
        10: "STRSZ",
        11: "SYMENT",
        12: "INIT",
        13: "FINI",
        14: "SONAME",
        15: "RPATH",
        16: "SYMBOLIC",
        17: "REL",
        18: "RELSZ",
        19: "RELENT",
        20: "PLTREL",
        21: "DEBUG",
        22: "TEXTREL",
        23: "JMPREL",
        24: "BIND_NOW",
        25: "INIT_ARRAY",
        26: "FINI_ARRAY",
        27: "INIT_ARRAYSZ",
        28: "FINI_ARRAYSZ",
        29: "RUNPATH",
        30: "FLAGS",
        31: "ENCODING",
        32: "PREINIT_ARRAY",
        33: "PREINIT_ARRAYSZ",
        34: "NUM",
        0x36: "PROCNUM",
        0x60000000: "OLD_LOOS",
        0x6000000D: "LOOS",
        0x6FFFF000: "HIOS",
        0x70000000: "LOPROC",
        0x7FFFFFFF: "HIPROC",
        0x6FFFFD00: "VALRNGLO",
        0x6FFFFDF5: "GNU_PRELINKED",
        0x6FFFFDF6: "GNU_CONFLICTSZ",
        0x6FFFFDF7: "GNU_LIBLISTSZ",
        0x6FFFFDF8: "CHECKSUM",
        0x6FFFFDF9: "PLTPADSZ",
        0x6FFFFDFA: "MOVEENT",
        0x6FFFFDFB: "MOVESZ",
        0x6FFFFDFE: "SYMINSZ",
        0x6FFFFDFF: "SYMINENT",
        0x6FFFFEF5: "GNU_HASH",
        0x6FFFFEF6: "TLSDESC_PLT",
        0x6FFFFEF7: "TLSDESC_GOT",
        0x6FFFFEF8: "GNU_CONFLICT",
        0x6FFFFEF9: "GNU_LIBLIST",
        0x6FFFFEFA: "CONFIG",
        0x6FFFFEFB: "DEPAUDIT",
        0x6FFFFEFC: "AUDIT",
        0x6FFFFEFD: "PLTPAD",
        0x6FFFFEFE: "MOVETAB",
        0x6FFFFEFF: "SYMINFO",
        0x6FFFFFF0: "VERSYM",
        0x6FFFFFF9: "RELACOUNT",
        0x6FFFFFFA: "RELCOUNT",
        0x6FFFFFFB: "FLAGS_1",
        0x6FFFFFFC: "VERDEF",
        0x6FFFFFFD: "VERDEFNUM",
        0x6FFFFFFE: "VERNEED",
        0x6FFFFFFF: "VERNEEDNUM",
        0x7FFFFFFD: "AUXILIARY",
        0x7FFFFFFF: "FILTER",
    }

    DT_VERSYM = 0x6FFFFFF0
    DT_VERDEF = 0x6FFFFFFC
    DT_VERNEEDNUM = 0x6FFFFFFF

    EI_TYPE = {
        0: "None",
        1: "Relocatable",
        2: "Executable",
        3: "Shared-object",
        4: "Core",
        0xFF00: "Processor-specific",
        0xFFFF: "Processor-specific",
    }

    EI_OSABI = {
        0: "SYSV",
        1: "HPUX",
        2: "NETBSD",
        3: "LINUX",
        4: "HURD",
        6: "SOLARIS",
        7: "AIX",
        8: "IRIX",
        9: "FREEBSD",
        10: "TRU64",
        11: "MODESTO",
        12: "OPENBSD",
        13: "OPENVMS",
        14: "NSK",
        15: "AROS",
        16: "FENIXOS",
        17: "CLOUD",
        53: "SORTIX",
        64: "ARM_AEABI",
        97: "ARM",
        255: "STANDALONE",
    }

    DT_FLAGS = {
        0x1: "ORIGIN",
        0x2: "SYMBOLIC",
        0x4: "TEXTREL",
        0x8: "BIND_NOW",
        0x10: "STATIC_TLS",
    }

    DT_FLAGS_1 = {
        0x1: "NOW",
        0x2: "GLOBAL",
        0x4: "GROUP",
        0x8: "NODELETE",
        0x10: "LOADFLTR",
        0x20: "INITFIRST",
        0x40: "NOOPEN",
        0x80: "ORIGIN",
        0x100: "DIRECT",
        0x200: "TRANS",
        0x400: "INTERPOSE",
        0x800: "NODEFLIB",
        0x1000: "NODUMP",
        0x2000: "CONFALT",
        0x4000: "ENDFILTEE",
        0x8000: "DISPRELDNE",
        0x10000: "DISPRELPND",
        0x20000: "NODIRECT",
        0x40000: "IGNMULDEF",
        0x80000: "NOKSYMS",
        0x100000: "NOHDR",
        0x200000: "EDITED",
        0x400000: "NORELOC",
        0x800000: "SYMINTPOSE",
        0x1000000: "GLOBAUDIT",
        0x2000000: "SINGLETON",
        0x4000000: "STUB",
        0x8000000: "PIE",
    }

    RELOC_TYPE = {}

    RELOC_TYPE_x86 = {
        0: "R_386_NONE",
        1: "R_386_32",
        2: "R_386_PC32",
        3: "R_386_GOT32",
        4: "R_386_PLT32",
        5: "R_386_COPY",
        6: "R_386_GLOB_DAT",
        7: "R_386_JUMP_SLOT",
        8: "R_386_RELATIVE",
        9: "R_386_GOTOFF",
        10: "R_386_GOTPC",
        11: "R_386_32PLT",
        14: "R_386_TLS_TPOFF",
        15: "R_386_TLS_IE",
        16: "R_386_TLS_GOTIE",
        17: "R_386_TLS_LE",
        18: "R_386_TLS_GD",
        19: "R_386_TLS_LDM",
        20: "R_386_16",
        21: "R_386_PC16",
        22: "R_386_8",
        23: "R_386_PC8",
        24: "R_386_TLS_GD_32",
        25: "R_386_TLS_GD_PUSH",
        26: "R_386_TLS_GD_CALL",
        27: "R_386_TLS_GD_POP",
        28: "R_386_TLS_LDM_32",
        29: "R_386_TLS_LDM_PUSH",
        30: "R_386_TLS_LDM_CALL",
        31: "R_386_TLS_LDM_POP",
        32: "R_386_TLS_LDO_32",
        33: "R_386_TLS_IE_32",
        34: "R_386_TLS_LE_32",
        35: "R_386_TLS_DTPMOD32",
        36: "R_386_TLS_DTPOFF32",
        37: "R_386_TLS_TPOFF32",
        39: "R_386_TLS_GOTDESC",
        40: "R_386_TLS_DESC_CALL",
        41: "R_386_TLS_DESC",
        42: "R_386_IRELATIVE",
        200: "R_386_USED_BY_INTEL_200",
        250: "R_386_GNU_VTINHERIT",
        251: "R_386_GNU_VTENTRY",
    }

    RELOC_TYPE_x64 = {
        0: "R_X86_64_NONE",
        1: "R_X86_64_64",
        2: "R_X86_64_PC32",
        3: "R_X86_64_GOT32",
        4: "R_X86_64_PLT32",
        5: "R_X86_64_COPY",
        6: "R_X86_64_GLOB_DAT",
        7: "R_X86_64_JUMP_SLOT",
        8: "R_X86_64_RELATIVE",
        9: "R_X86_64_GOTPCREL",
        10: "R_X86_64_32",
        11: "R_X86_64_32S",
        12: "R_X86_64_16",
        13: "R_X86_64_PC16",
        14: "R_X86_64_8",
        15: "R_X86_64_PC8",
        16: "R_X86_64_DTPMOD64",
        17: "R_X86_64_DTPOFF64",
        18: "R_X86_64_TPOFF64",
        19: "R_X86_64_TLSGD",
        20: "R_X86_64_TLSLD",
        21: "R_X86_64_DTPOFF32",
        22: "R_X86_64_GOTTPOFF",
        23: "R_X86_64_TPOFF32",
        24: "R_X86_64_PC64",
        25: "R_X86_64_GOTOFF64",
        26: "R_X86_64_GOTPC32",
        27: "R_X86_64_GOT64",
        28: "R_X86_64_GOTPCREL64",
        29: "R_X86_64_GOTPC64",
        30: "R_X86_64_GOTPLT64",
        31: "R_X86_64_PLTOFF64",
        34: "R_X86_64_GOTPC32_TLSDESC",
        35: "R_X86_64_TLSDESC_CALL",
        36: "R_X86_64_TLSDESC",
        37: "R_X86_64_IRELATIVE",
        250: "R_X86_64_GNU_VTINHERIT",
        251: "R_X86_64_GNU_VTENTRY",
    }

    RELOC_TYPE_ARM = {
        0: "R_ARM_NONE",
        1: "R_ARM_PC24",
        2: "R_ARM_ABS32",
        3: "R_ARM_REL32",
        4: "R_ARM_LDR_PC_G0",
        5: "R_ARM_ABS16",
        6: "R_ARM_ABS12",
        7: "R_ARM_THM_ABS5",
        8: "R_ARM_ABS8",
        9: "R_ARM_SBREL32",
        10: "R_ARM_THM_CALL",
        11: "R_ARM_THM_PC8",
        12: "R_ARM_BREL_ADJ",
        13: "R_ARM_SWI24",
        14: "R_ARM_THM_SWI8",
        15: "R_ARM_XPC25",
        16: "R_ARM_THM_XPC22",
        17: "R_ARM_TLS_DTPMOD32",
        18: "R_ARM_TLS_DTPOFF32",
        19: "R_ARM_TLS_TPOFF32",
        20: "R_ARM_COPY",
        21: "R_ARM_GLOB_DAT",
        22: "R_ARM_JUMP_SLOT",
        23: "R_ARM_RELATIVE",
        24: "R_ARM_GOTOFF32",
        25: "R_ARM_BASE_PREL",
        26: "R_ARM_GOT_BREL",
        27: "R_ARM_PLT32",
        28: "R_ARM_CALL",
        29: "R_ARM_JUMP24",
        30: "R_ARM_THM_JUMP24",
        31: "R_ARM_BASE_ABS",
        32: "R_ARM_ALU_PCREL_7_0",
        33: "R_ARM_ALU_PCREL_15_8",
        34: "R_ARM_ALU_PCREL_23_15",
        35: "R_ARM_LDR_SBREL_11_0_NC",
        36: "R_ARM_ALU_SBREL_19_12_NC",
        37: "R_ARM_ALU_SBREL_27_20_CK",
        38: "R_ARM_TARGET1",
        39: "R_ARM_SBREL31",
        40: "R_ARM_V4BX",
        41: "R_ARM_TARGET2",
        42: "R_ARM_PREL31",
        43: "R_ARM_MOVW_ABS_NC",
        44: "R_ARM_MOVT_ABS",
        45: "R_ARM_MOVW_PREL_NC",
        46: "R_ARM_MOVT_PREL",
        47: "R_ARM_THM_MOVW_ABS_NC",
        48: "R_ARM_THM_MOVT_ABS",
        49: "R_ARM_THM_MOVW_PREL_NC",
        50: "R_ARM_THM_MOVT_PREL",
        51: "R_ARM_THM_JUMP19",
        52: "R_ARM_THM_JUMP6",
        53: "R_ARM_THM_ALU_PREL_11_0",
        54: "R_ARM_THM_PC12",
        55: "R_ARM_ABS32_NOI",
        56: "R_ARM_REL32_NOI",
        57: "R_ARM_ALU_PC_G0_NC",
        58: "R_ARM_ALU_PC_G0",
        59: "R_ARM_ALU_PC_G1_NC",
        60: "R_ARM_ALU_PC_G1",
        61: "R_ARM_ALU_PC_G2",
        62: "R_ARM_LDR_PC_G1",
        63: "R_ARM_LDR_PC_G2",
        64: "R_ARM_LDRS_PC_G0",
        65: "R_ARM_LDRS_PC_G1",
        66: "R_ARM_LDRS_PC_G2",
        67: "R_ARM_LDC_PC_G0",
        68: "R_ARM_LDC_PC_G1",
        69: "R_ARM_LDC_PC_G2",
        70: "R_ARM_ALU_SB_G0_NC",
        71: "R_ARM_ALU_SB_G0",
        72: "R_ARM_ALU_SB_G1_NC",
        73: "R_ARM_ALU_SB_G1",
        74: "R_ARM_ALU_SB_G2",
        75: "R_ARM_LDR_SB_G0",
        76: "R_ARM_LDR_SB_G1",
        77: "R_ARM_LDR_SB_G2",
        78: "R_ARM_LDRS_SB_G0",
        79: "R_ARM_LDRS_SB_G1",
        80: "R_ARM_LDRS_SB_G2",
        81: "R_ARM_LDC_SB_G0",
        82: "R_ARM_LDC_SB_G1",
        83: "R_ARM_LDC_SB_G2",
        84: "R_ARM_MOVW_BREL_NC",
        85: "R_ARM_MOVT_BREL",
        86: "R_ARM_MOVW_BREL",
        87: "R_ARM_THM_MOVW_BREL_NC",
        88: "R_ARM_THM_MOVT_BREL",
        89: "R_ARM_THM_MOVW_BREL",
        94: "R_ARM_PLT32_ABS",
        95: "R_ARM_GOT_ABS",
        96: "R_ARM_GOT_PREL",
        97: "R_ARM_GOT_BREL12",
        98: "R_ARM_GOTOFF12",
        99: "R_ARM_GOTRELAX",
        100: "R_ARM_GNU_VTENTRY",
        101: "R_ARM_GNU_VTINHERIT",
        102: "R_ARM_THM_JUMP11",
        103: "R_ARM_THM_JUMP8",
        104: "R_ARM_TLS_GD32",
        105: "R_ARM_TLS_LDM32",
        106: "R_ARM_TLS_LDO32",
        107: "R_ARM_TLS_IE32",
        108: "R_ARM_TLS_LE32",
        109: "R_ARM_TLS_LDO12",
        110: "R_ARM_TLS_LE12",
        111: "R_ARM_TLS_IE12GP",
        112: "R_ARM_PRIVATE_0",
        113: "R_ARM_PRIVATE_1",
        114: "R_ARM_PRIVATE_2",
        115: "R_ARM_PRIVATE_3",
        116: "R_ARM_PRIVATE_4",
        117: "R_ARM_PRIVATE_5",
        118: "R_ARM_PRIVATE_6",
        119: "R_ARM_PRIVATE_7",
        120: "R_ARM_PRIVATE_8",
        121: "R_ARM_PRIVATE_9",
        122: "R_ARM_PRIVATE_10",
        123: "R_ARM_PRIVATE_11",
        124: "R_ARM_PRIVATE_12",
        125: "R_ARM_PRIVATE_13",
        126: "R_ARM_PRIVATE_14",
        127: "R_ARM_PRIVATE_15",
        128: "R_ARM_ME_TOO",
        129: "R_ARM_THM_TLS_DESCSEQ16",
        130: "R_ARM_THM_TLS_DESCSEQ32",
        131: "R_ARM_THM_GOT_BREL12",
        140: "R_ARM_IRELATIVE",
    }

    RELOC_TYPE_AARCH64 = {
        256: "R_AARCH64_NONE",
        257: "R_AARCH64_ABS64",
        258: "R_AARCH64_ABS32",
        259: "R_AARCH64_ABS16",
        260: "R_AARCH64_PREL64",
        261: "R_AARCH64_PREL32",
        262: "R_AARCH64_PREL16",
        263: "R_AARCH64_MOVW_UABS_G0",
        264: "R_AARCH64_MOVW_UABS_G0_NC",
        265: "R_AARCH64_MOVW_UABS_G1",
        266: "R_AARCH64_MOVW_UABS_G1_NC",
        267: "R_AARCH64_MOVW_UABS_G2",
        268: "R_AARCH64_MOVW_UABS_G2_NC",
        269: "R_AARCH64_MOVW_UABS_G3",
        270: "R_AARCH64_MOVW_SABS_G0",
        271: "R_AARCH64_MOVW_SABS_G1",
        272: "R_AARCH64_MOVW_SABS_G2",
        273: "R_AARCH64_LD_PREL_LO19",
        274: "R_AARCH64_ADR_PREL_LO21",
        275: "R_AARCH64_ADR_PREL_PG_HI21",
        276: "R_AARCH64_ADR_PREL_PG_HI21_NC",
        277: "R_AARCH64_ADD_ABS_LO12_NC",
        278: "R_AARCH64_LDST8_ABS_LO12_NC",
        279: "R_AARCH64_TSTBR14",
        280: "R_AARCH64_CONDBR19",
        282: "R_AARCH64_JUMP26",
        283: "R_AARCH64_CALL26",
        284: "R_AARCH64_LDST16_ABS_LO12_NC",
        285: "R_AARCH64_LDST32_ABS_LO12_NC",
        286: "R_AARCH64_LDST64_ABS_LO12_NC",
        287: "R_AARCH64_MOVW_PREL_G0",
        288: "R_AARCH64_MOVW_PREL_G0_NC",
        289: "R_AARCH64_MOVW_PREL_G1",
        290: "R_AARCH64_MOVW_PREL_G1_NC",
        291: "R_AARCH64_MOVW_PREL_G2",
        292: "R_AARCH64_MOVW_PREL_G2_NC",
        293: "R_AARCH64_MOVW_PREL_G3",
        300: "R_AARCH64_MOVW_GOTOFF_G0",
        301: "R_AARCH64_MOVW_GOTOFF_G0_NC",
        302: "R_AARCH64_MOVW_GOTOFF_G1",
        303: "R_AARCH64_MOVW_GOTOFF_G1_NC",
        304: "R_AARCH64_MOVW_GOTOFF_G2",
        305: "R_AARCH64_MOVW_GOTOFF_G2_NC",
        306: "R_AARCH64_MOVW_GOTOFF_G3",
        307: "R_AARCH64_GOTREL64",
        308: "R_AARCH64_GOTREL32",
        309: "R_AARCH64_GOT_LD_PREL19",
        310: "R_AARCH64_LD64_GOTOFF_LO15",
        311: "R_AARCH64_ADR_GOT_PAGE",
        312: "R_AARCH64_LD64_GOT_LO12_NC",
        512: "R_AARCH64_TLSGD_ADR_PREL21",
        513: "R_AARCH64_TLSGD_ADR_PAGE21",
        514: "R_AARCH64_TLSGD_ADD_LO12_NC",
        515: "R_AARCH64_TLSGD_MOVW_G1",
        516: "R_AARCH64_TLSGD_MOVW_G0_NC",
        517: "R_AARCH64_TLSLD_ADR_PREL21",
        518: "R_AARCH64_TLSLD_ADR_PAGE21",
        519: "R_AARCH64_TLSLD_ADD_LO12_NC",
        520: "R_AARCH64_TLSLD_MOVW_G1",
        521: "R_AARCH64_TLSLD_MOVW_G0_NC",
        522: "R_AARCH64_TLSLD_LD_PREL19",
        523: "R_AARCH64_TLSLD_MOVW_DTPREL_G2",
        524: "R_AARCH64_TLSLD_MOVW_DTPREL_G1",
        525: "R_AARCH64_TLSLD_MOVW_DTPREL_G1_NC",
        526: "R_AARCH64_TLSLD_MOVW_DTPREL_G0",
        527: "R_AARCH64_TLSLD_MOVW_DTPREL_G0_NC",
        528: "R_AARCH64_TLSLD_ADD_DTPREL_HI12",
        529: "R_AARCH64_TLSLD_ADD_DTPREL_LO12",
        530: "R_AARCH64_TLSLD_ADD_DTPREL_LO12_NC",
        531: "R_AARCH64_TLSLD_LDST8_DTPREL_LO12",
        532: "R_AARCH64_TLSLD_LDST8_DTPREL_LO12_NC",
        533: "R_AARCH64_TLSLD_LDST16_DTPREL_LO12",
        534: "R_AARCH64_TLSLD_LDST16_DTPREL_LO12_NC",
        535: "R_AARCH64_TLSLD_LDST32_DTPREL_LO12",
        536: "R_AARCH64_TLSLD_LDST32_DTPREL_LO12_NC",
        537: "R_AARCH64_TLSLD_LDST64_DTPREL_LO12",
        538: "R_AARCH64_TLSLD_LDST64_DTPREL_LO12_NC",
        539: "R_AARCH64_TLSIE_MOVW_GOTTPREL_G1",
        540: "R_AARCH64_TLSIE_MOVW_GOTTPREL_G0_NC",
        541: "R_AARCH64_TLSIE_ADR_GOTTPREL_PAGE21",
        542: "R_AARCH64_TLSIE_LD64_GOTTPREL_LO12_NC",
        543: "R_AARCH64_TLSIE_LD_GOTTPREL_PREL19",
        544: "R_AARCH64_TLSLE_MOVW_TPREL_G2",
        545: "R_AARCH64_TLSLE_MOVW_TPREL_G1",
        546: "R_AARCH64_TLSLE_MOVW_TPREL_G1_NC",
        547: "R_AARCH64_TLSLE_MOVW_TPREL_G0",
        548: "R_AARCH64_TLSLE_MOVW_TPREL_G0_NC",
        549: "R_AARCH64_TLSLE_ADD_TPREL_HI12",
        550: "R_AARCH64_TLSLE_ADD_TPREL_LO12",
        551: "R_AARCH64_TLSLE_ADD_TPREL_LO12_NC",
        552: "R_AARCH64_TLSLE_LDST8_TPREL_LO12",
        553: "R_AARCH64_TLSLE_LDST8_TPREL_LO12_NC",
        554: "R_AARCH64_TLSLE_LDST16_TPREL_LO12",
        555: "R_AARCH64_TLSLE_LDST16_TPREL_LO12_NC",
        556: "R_AARCH64_TLSLE_LDST32_TPREL_LO12",
        557: "R_AARCH64_TLSLE_LDST32_TPREL_LO12_NC",
        558: "R_AARCH64_TLSLE_LDST64_TPREL_LO12",
        559: "R_AARCH64_TLSLE_LDST64_TPREL_LO12_NC",
        1024: "R_AARCH64_COPY",
        1025: "R_AARCH64_GLOB_DAT",
        1026: "R_AARCH64_JUMP_SLOT",
        1027: "R_AARCH64_RELATIVE",
        1028: "R_AARCH64_TLS_DTPREL64",
        1029: "R_AARCH64_TLS_DTPMOD64",
        1030: "R_AARCH64_TLS_TPREL64",
        1031: "R_AARCH64_TLS_DTPREL32",
        1032: "R_AARCH64_TLS_DTPMOD32",
        1033: "R_AARCH64_TLS_TPREL32",
    }

    EI_MACHINE_TYPE = {
        0: "no machine",
        1: "AT&T WE 32100",
        2: "SPARC",
        3: "Intel 80386",
        4: "Motorola 68000",
        5: "Motorola 88000",
        6: "Intel MCU",
        7: "Intel 80860",
        8: "MIPS I Architecture",
        9: "IBM System/370 Processor",
        10: "MIPS RS3000 Little-endian",
        11 - 14: "Reserved for future use",
        15: "Hewlett-Packard PA-RISC",
        16: "Reserved for future use",
        17: "Fujitsu VPP500",
        18: "Enhanced instruction set SPARC",
        19: "Intel 80960",
        20: "PowerPC",
        21: "64-bit PowerPC",
        22: "IBM System/390 Processor",
        23: "IBM SPU/SPC",
        24 - 35: "Reserved for future use",
        36: "NEC V800",
        37: "Fujitsu FR20",
        38: "TRW RH-32",
        39: "Motorola RCE",
        40: "ARM 32-bit architecture (AARCH32)",
        41: "Digital Alpha",
        42: "Hitachi SH",
        43: "SPARC Version 9",
        44: "Siemens TriCore embedded processor",
        45: "Argonaut RISC Core, Argonaut Technologies Inc.",
        46: "Hitachi H8/300",
        47: "Hitachi H8/300H",
        48: "Hitachi H8S",
        49: "Hitachi H8/500",
        50: "Intel IA-64 processor architecture",
        51: "Stanford MIPS-X",
        52: "Motorola ColdFire",
        53: "Motorola M68HC12",
        54: "Fujitsu MMA Multimedia Accelerator",
        55: "Siemens PCP",
        56: "Sony nCPU embedded RISC processor",
        57: "Denso NDR1 microprocessor",
        58: "Motorola Star*Core processor",
        59: "Toyota ME16 processor",
        60: "STMicroelectronics ST100 processor",
        61: "Advanced Logic Corp. TinyJ embedded processor family",
        62: "AMD x86-64 architecture",
        63: "Sony DSP Processor",
        64: "Digital Equipment Corp. PDP-10",
        65: "Digital Equipment Corp. PDP-11",
        66: "Siemens FX66 microcontroller",
        67: "STMicroelectronics ST9+ 8/16 bit microcontroller",
        68: "STMicroelectronics ST7 8-bit microcontroller",
        69: "Motorola MC68HC16 Microcontroller",
        70: "Motorola MC68HC11 Microcontroller",
        71: "Motorola MC68HC08 Microcontroller",
        72: "Motorola MC68HC05 Microcontroller",
        73: "Silicon Graphics SVx",
        74: "STMicroelectronics ST19 8-bit microcontroller",
        75: "Digital VAX",
        76: "Axis Communications 32-bit embedded processor",
        77: "Infineon Technologies 32-bit embedded processor",
        78: "Element 14 64-bit DSP Processor",
        79: "LSI Logic 16-bit DSP Processor",
        80: "Donald Knuth's educational 64-bit processor",
        81: "Harvard University machine-independent object files",
        82: "SiTera Prism",
        83: "Atmel AVR 8-bit microcontroller",
        84: "Fujitsu FR30",
        85: "Mitsubishi D10V",
        86: "Mitsubishi D30V",
        87: "NEC v850",
        88: "Mitsubishi M32R",
        89: "Matsushita MN10300",
        90: "Matsushita MN10200",
        91: "picoJava",
        92: "OpenRISC 32-bit embedded processor",
        93: "ARC International ARCompact processor (old spelling/synonym: EM_ARC_A5)",
        94: "Tensilica Xtensa Architecture",
        95: "Alphamosaic VideoCore processor",
        96: "Thompson Multimedia General Purpose Processor",
        97: "National Semiconductor 32000 series",
        98: "Tenor Network TPC processor",
        99: "Trebia SNP 1000 processor",
        100: "STMicroelectronics (www.st.com) ST200 microcontroller",
        101: "Ubicom IP2xxx microcontroller family",
        102: "MAX Processor",
        103: "National Semiconductor CompactRISC microprocessor",
        104: "Fujitsu F2MC16",
        105: "Texas Instruments embedded microcontroller msp430",
        106: "Analog Devices Blackfin (DSP) processor",
        107: "S1C33 Family of Seiko Epson processors",
        108: "Sharp embedded microprocessor",
        109: "Arca RISC Microprocessor",
        110: "Microprocessor series from PKU-Unity Ltd. and MPRC of Peking University",
        111: "eXcess: 16/32/64-bit configurable embedded CPU",
        112: "Icera Semiconductor Inc. Deep Execution Processor",
        113: "Altera Nios II soft-core processor",
        114: "National Semiconductor CompactRISC CRX microprocessor",
        115: "Motorola XGATE embedded processor",
        116: "Infineon C16x/XC16x processor",
        117: "Renesas M16C series microprocessors",
        118: "Microchip Technology dsPIC30F Digital Signal Controller",
        119: "Freescale Communication Engine RISC core",
        120: "Renesas M32C series microprocessors",
        121 - 130: "Reserved for future use",
        131: "Altium TSK3000 core",
        132: "Freescale RS08 embedded processor",
        133: "Analog Devices SHARC family of 32-bit DSP processors",
        134: "Cyan Technology eCOG2 microprocessor",
        135: "Sunplus S+core7 RISC processor",
        136: "New Japan Radio (NJR) 24-bit DSP Processor",
        137: "Broadcom VideoCore III processor",
        138: "RISC processor for Lattice FPGA architecture",
        139: "Seiko Epson C17 family",
        140: "The Texas Instruments TMS320C6000 DSP family",
        141: "The Texas Instruments TMS320C2000 DSP family",
        142: "The Texas Instruments TMS320C55x DSP family",
        143: "Texas Instruments Application Specific RISC Processor, 32bit fetch",
        144: "Texas Instruments Programmable Realtime Unit",
        145 - 159: "Reserved for future use",
        160: "",
        145 - 159: "Reserved for future use",
        160: "STMicroelectronics 64bit VLIW Data Signal Processor",
        161: "Cypress M8C microprocessor",
        162: "Renesas R32C series microprocessors",
        163: "NXP Semiconductors TriMedia architecture family",
        164: "QUALCOMM DSP6 Processor",
        165: "Intel 8051 and variants",
        166: "STMicroelectronics STxP7x family of configurable and extensible RISC processors",
        167: "Andes Technology compact code size embedded RISC processor family",
        168: "Cyan Technology eCOG1X family",
        168: "Cyan Technology eCOG1X family",
        169: "Dallas Semiconductor MAXQ30 Core Micro-controllers",
        170: "New Japan Radio (NJR) 16-bit DSP Processor",
        171: "M2000 Reconfigurable RISC Microprocessor",
        172: "Cray Inc. NV2 vector architecture",
        173: "Renesas RX family",
        174: "Imagination Technologies META processor architecture",
        175: "MCST Elbrus general purpose hardware architecture",
        176: "Cyan Technology eCOG16 family",
        177: "National Semiconductor CompactRISC CR16 16-bit microprocessor",
        178: "Freescale Extended Time Processing Unit",
        179: "Infineon Technologies SLE9X core",
        180: "Intel L10M",
        181: "Intel K10M",
        182: "Reserved for future Intel use",
        183: "ARM 64-bit architecture (AARCH64)",
        184: "Reserved for future ARM use",
        185: "Atmel Corporation 32-bit microprocessor family",
        186: "STMicroeletronics STM8 8-bit microcontroller",
        187: "Tilera TILE64 multicore architecture family",
        188: "Tilera TILEPro multicore architecture family",
        189: "Xilinx MicroBlaze 32-bit RISC soft processor core",
        190: "NVIDIA CUDA architecture",
        191: "Tilera TILE-Gx multicore architecture family",
        192: "CloudShield architecture family",
        193: "KIPO-KAIST Core-A 1st generation processor family",
        194: "KIPO-KAIST Core-A 2nd generation processor family",
        195: "Synopsys ARCompact V2",
        196: "Open8 8-bit RISC soft processor core",
        197: "Renesas RL78 family",
        198: "Broadcom VideoCore V processor",
        199: "Renesas 78KOR family",
        200: "Freescale 56800EX Digital Signal Controller (DSC)",
        201: "Beyond BA1 CPU architecture",
        202: "Beyond BA2 CPU architecture",
        203: "XMOS xCORE processor family",
        204: "Microchip 8-bit PIC(r) family",
        205: "Reserved by Intel",
        206: "Reserved by Intel",
        207: "Reserved by Intel",
        208: "Reserved by Intel",
        209: "Reserved by Intel",
        210: "KM211 KM32 32-bit processor",
        211: "KM211 KMX32 32-bit processor",
        212: "KM211 KMX16 16-bit processor",
        213: "KM211 KMX8 8-bit processor",
        214: "KM211 KVARC processor",
        215: "Paneve CDP architecture family",
        216: "Cognitive Smart Memory Processor",
        217: "Bluechip Systems CoolEngine",
        218: "Nanoradio Optimized RISC",
        219: "CSR Kalimba architecture family",
        220: "Zilog Z80",
        221: "Controls and Data Services VISIUMcore processor",
        222: "FTDI Chip FT32 high performance 32-bit RISC architecture",
        223: "Moxie processor family",
        224: "AMD GPU architecture",
        243: "RISC-V",
    }

    """
    python elftools constants
    refer to https://github.com/eliben/pyelftools

    Note that the first 3 instructions have the so-called "primary opcode"
    (as described in DWARFv3 7.23), so only their highest 2 bits take part
    in the opcode decoding. They are kept as constants with the low bits masked
    out, and the callframe module knows how to handle this.
    The other instructions use an "extended opcode" encoded just in the low 6
    bits, with the high 2 bits, so these constants are exactly as they would
    appear in an actual file.
    """
    DW_INL = {
        "DW_INL_not_inlined": 0,
        "DW_INL_inlined": 1,
        "DW_INL_declared_not_inlined": 2,
        "DW_INL_declared_inlined": 3,
    }
    DW_INL_MAP = {v: k for k, v in DW_INL.items()}

    DW_LANG = {
        "DW_LANG_C89": 0x0001,
        "DW_LANG_C": 0x0002,
        "DW_LANG_Ada83": 0x0003,
        "DW_LANG_C_plus_plus": 0x0004,
        "DW_LANG_Cobol74": 0x0005,
        "DW_LANG_Cobol85": 0x0006,
        "DW_LANG_Fortran77": 0x0007,
        "DW_LANG_Fortran90": 0x0008,
        "DW_LANG_Pascal83": 0x0009,
        "DW_LANG_Modula2": 0x000A,
        "DW_LANG_Java": 0x000B,
        "DW_LANG_C99": 0x000C,
        "DW_LANG_Ada95": 0x000D,
        "DW_LANG_Fortran95": 0x000E,
        "DW_LANG_PLI": 0x000F,
        "DW_LANG_ObjC": 0x0010,
        "DW_LANG_ObjC_plus_plus": 0x0011,
        "DW_LANG_UPC": 0x0012,
        "DW_LANG_D": 0x0013,
        "DW_LANG_Python": 0x0014,
        "DW_LANG_OpenCL": 0x0015,
        "DW_LANG_Go": 0x0016,
        "DW_LANG_Modula3": 0x0017,
        "DW_LANG_Haskell": 0x0018,
        "DW_LANG_C_plus_plus_03": 0x0019,
        "DW_LANG_C_plus_plus_11": 0x001A,
        "DW_LANG_OCaml": 0x001B,
        "DW_LANG_Rust": 0x001C,
        "DW_LANG_C11": 0x001D,
        "DW_LANG_Swift": 0x001E,
        "DW_LANG_Julia": 0x001F,
        "DW_LANG_Dylan": 0x0020,
        "DW_LANG_C_plus_plus_14": 0x0021,
        "DW_LANG_Fortran03": 0x0022,
        "DW_LANG_Fortran08": 0x0023,
        "DW_LANG_RenderScript": 0x0024,
        "DW_LANG_BLISS": 0x0025,
        "DW_LANG_Mips_Assembler": 0x8001,
        "DW_LANG_Upc": 0x8765,
        "DW_LANG_HP_Bliss": 0x8003,
        "DW_LANG_HP_Basic91": 0x8004,
        "DW_LANG_HP_Pascal91": 0x8005,
        "DW_LANG_HP_IMacro": 0x8006,
        "DW_LANG_HP_Assembler": 0x8007,
        "DW_LANG_GOOGLE_RenderScript": 0x8E57,
        "DW_LANG_BORLAND_Delphi": 0xB000,
    }
    DW_LANG_MAP = {v: k for k, v in DW_LANG.items()}

    DW_ATE = {
        "DW_ATE_void": 0x0,
        "DW_ATE_address": 0x1,
        "DW_ATE_boolean": 0x2,
        "DW_ATE_complex_float": 0x3,
        "DW_ATE_float": 0x4,
        "DW_ATE_signed": 0x5,
        "DW_ATE_signed_char": 0x6,
        "DW_ATE_unsigned": 0x7,
        "DW_ATE_unsigned_char": 0x8,
        "DW_ATE_imaginary_float": 0x9,
        "DW_ATE_packed_decimal": 0xA,
        "DW_ATE_numeric_string": 0xB,
        "DW_ATE_edited": 0xC,
        "DW_ATE_signed_fixed": 0xD,
        "DW_ATE_unsigned_fixed": 0xE,
        "DW_ATE_decimal_float": 0xF,
        "DW_ATE_UTF": 0x10,
        "DW_ATE_UCS": 0x11,
        "DW_ATE_ASCII": 0x12,
        "DW_ATE_lo_user": 0x80,
        "DW_ATE_hi_user": 0xFF,
        "DW_ATE_HP_float80": 0x80,
        "DW_ATE_HP_complex_float80": 0x81,
        "DW_ATE_HP_float128": 0x82,
        "DW_ATE_HP_complex_float128": 0x83,
        "DW_ATE_HP_floathpintel": 0x84,
        "DW_ATE_HP_imaginary_float80": 0x85,
        "DW_ATE_HP_imaginary_float128": 0x86,
    }
    DW_ATE_MAP = {v: k for k, v in DW_ATE.items()}

    DW_ACCESS = {
        "DW_ACCESS_public": 1,
        "DW_ACCESS_protected": 2,
        "DW_ACCESS_private": 3,
    }
    DW_ACCESS_MAP = {v: k for k, v in DW_ACCESS.items()}

    DW_VIS = {"DW_VIS_local": 1, "DW_VIS_exported": 2, "DW_VIS_qualified": 3}
    DW_VIS_MAP = {v: k for k, v in DW_VIS.items()}

    DW_VIRTUALITY = {
        "DW_VIRTUALITY_none": 0,
        "DW_VIRTUALITY_virtual": 1,
        "DW_VIRTUALITY_pure_virtual": 2,
    }
    DW_VIRTUALITY_MAP = {v: k for k, v in DW_VIRTUALITY.items()}

    DW_ID = {
        "DW_ID_case_sensitive": 0,
        "DW_ID_up_case": 1,
        "DW_ID_down_case": 2,
        "DW_ID_case_insensitive": 3,
    }
    DW_ID_MAP = {v: k for k, v in DW_ID.items()}

    DW_CC = {"DW_CC_normal": 0x1, "DW_CC_program": 0x2, "DW_CC_nocall": 0x3}
    DW_CC_MAP = {v: k for k, v in DW_CC.items()}

    DW_ORD = {"DW_ORD_row_major": 0, "DW_ORD_col_major": 1}
    DW_ORD_MAP = {v: k for k, v in DW_ORD.items()}

    DW_LNS = {
        "DW_LNS_copy": 0x01,
        "DW_LNS_advance_pc": 0x02,
        "DW_LNS_advance_line": 0x03,
        "DW_LNS_set_file": 0x04,
        "DW_LNS_set_column": 0x05,
        "DW_LNS_negate_stmt": 0x06,
        "DW_LNS_set_basic_block": 0x07,
        "DW_LNS_const_add_pc": 0x08,
        "DW_LNS_fixed_advance_pc": 0x09,
        "DW_LNS_set_prologue_end": 0x0A,
        "DW_LNS_set_epilogue_begin": 0x0B,
        "DW_LNS_set_isa": 0x0C,
    }
    DW_LNS_MAP = {v: k for k, v in DW_LNS.items()}

    DW_LNE = {
        "DW_LNE_end_sequence": 0x01,
        "DW_LNE_set_address": 0x02,
        "DW_LNE_define_file": 0x03,
        "DW_LNE_set_discriminator": 0x04,
        "DW_LNE_lo_user": 0x80,
        "DW_LNE_hi_user": 0xFF,
    }
    DW_LNE_MAP = {v: k for k, v in DW_LNE.items()}

    DW_AT = {
        "DW_AT_null": 0x00,
        "DW_AT_sibling": 0x01,
        "DW_AT_location": 0x02,
        "DW_AT_name": 0x03,
        "DW_AT_ordering": 0x09,
        "DW_AT_subscr_data": 0x0A,
        "DW_AT_byte_size": 0x0B,
        "DW_AT_bit_offset": 0x0C,
        "DW_AT_bit_size": 0x0D,
        "DW_AT_element_list": 0x0F,
        "DW_AT_stmt_list": 0x10,
        "DW_AT_low_pc": 0x11,
        "DW_AT_high_pc": 0x12,
        "DW_AT_language": 0x13,
        "DW_AT_member": 0x14,
        "DW_AT_discr": 0x15,
        "DW_AT_discr_value": 0x16,
        "DW_AT_visibility": 0x17,
        "DW_AT_import": 0x18,
        "DW_AT_string_length": 0x19,
        "DW_AT_common_reference": 0x1A,
        "DW_AT_comp_dir": 0x1B,
        "DW_AT_const_value": 0x1C,
        "DW_AT_containing_type": 0x1D,
        "DW_AT_default_value": 0x1E,
        "DW_AT_inline": 0x20,
        "DW_AT_is_optional": 0x21,
        "DW_AT_lower_bound": 0x22,
        "DW_AT_producer": 0x25,
        "DW_AT_prototyped": 0x27,
        "DW_AT_return_addr": 0x2A,
        "DW_AT_start_scope": 0x2C,
        "DW_AT_bit_stride": 0x2E,
        "DW_AT_stride_size": 0x2E,
        "DW_AT_upper_bound": 0x2F,
        "DW_AT_abstract_origin": 0x31,
        "DW_AT_accessibility": 0x32,
        "DW_AT_address_class": 0x33,
        "DW_AT_artificial": 0x34,
        "DW_AT_base_types": 0x35,
        "DW_AT_calling_convention": 0x36,
        "DW_AT_count": 0x37,
        "DW_AT_data_member_location": 0x38,
        "DW_AT_decl_column": 0x39,
        "DW_AT_decl_file": 0x3A,
        "DW_AT_decl_line": 0x3B,
        "DW_AT_declaration": 0x3C,
        "DW_AT_discr_list": 0x3D,
        "DW_AT_encoding": 0x3E,
        "DW_AT_external": 0x3F,
        "DW_AT_frame_base": 0x40,
        "DW_AT_friend": 0x41,
        "DW_AT_identifier_case": 0x42,
        "DW_AT_macro_info": 0x43,
        "DW_AT_namelist_item": 0x44,
        "DW_AT_priority": 0x45,
        "DW_AT_segment": 0x46,
        "DW_AT_specification": 0x47,
        "DW_AT_static_link": 0x48,
        "DW_AT_type": 0x49,
        "DW_AT_use_location": 0x4A,
        "DW_AT_variable_parameter": 0x4B,
        "DW_AT_virtuality": 0x4C,
        "DW_AT_vtable_elem_location": 0x4D,
        "DW_AT_allocated": 0x4E,
        "DW_AT_associated": 0x4F,
        "DW_AT_data_location": 0x50,
        "DW_AT_byte_stride": 0x51,
        "DW_AT_stride": 0x51,
        "DW_AT_entry_pc": 0x52,
        "DW_AT_use_UTF8": 0x53,
        "DW_AT_extension": 0x54,
        "DW_AT_ranges": 0x55,
        "DW_AT_trampoline": 0x56,
        "DW_AT_call_column": 0x57,
        "DW_AT_call_file": 0x58,
        "DW_AT_call_line": 0x59,
        "DW_AT_description": 0x5A,
        "DW_AT_binary_scale": 0x5B,
        "DW_AT_decimal_scale": 0x5C,
        "DW_AT_small": 0x5D,
        "DW_AT_decimal_sign": 0x5E,
        "DW_AT_digit_count": 0x5F,
        "DW_AT_picture_string": 0x60,
        "DW_AT_mutable": 0x61,
        "DW_AT_threads_scaled": 0x62,
        "DW_AT_explicit": 0x63,
        "DW_AT_object_pointer": 0x64,
        "DW_AT_endianity": 0x65,
        "DW_AT_elemental": 0x66,
        "DW_AT_pure": 0x67,
        "DW_AT_recursive": 0x68,
        "DW_AT_signature": 0x69,
        "DW_AT_main_subprogram": 0x6A,
        "DW_AT_data_bit_offset": 0x6B,
        "DW_AT_const_expr": 0x6C,
        "DW_AT_enum_class": 0x6D,
        "DW_AT_linkage_name": 0x6E,
        "DW_AT_string_length_bit_size": 0x6F,
        "DW_AT_string_length_byte_size": 0x70,
        "DW_AT_rank": 0x71,
        "DW_AT_str_offsets_base": 0x72,
        "DW_AT_addr_base": 0x73,
        "DW_AT_rnglists_base": 0x74,
        "DW_AT_dwo_name": 0x76,
        "DW_AT_reference": 0x77,
        "DW_AT_rvalue_reference": 0x78,
        "DW_AT_macros": 0x79,
        "DW_AT_call_all_calls": 0x7A,
        "DW_AT_call_all_source_calls": 0x7B,
        "DW_AT_call_all_tail_calls": 0x7C,
        "DW_AT_call_return_pc": 0x7D,
        "DW_AT_call_value": 0x7E,
        "DW_AT_call_origin": 0x7F,
        "DW_AT_call_parameter": 0x80,
        "DW_AT_call_pc": 0x81,
        "DW_AT_call_tail_call": 0x82,
        "DW_AT_call_target": 0x83,
        "DW_AT_call_target_clobbered": 0x84,
        "DW_AT_call_data_location": 0x85,
        "DW_AT_call_data_value": 0x86,
        "DW_AT_noreturn": 0x87,
        "DW_AT_alignment": 0x88,
        "DW_AT_export_symbols": 0x89,
        "DW_AT_deleted": 0x8A,
        "DW_AT_defaulted": 0x8B,
        "DW_AT_loclists_base": 0x8C,
        "DW_AT_MIPS_fde": 0x2001,
        "DW_AT_MIPS_loop_begin": 0x2002,
        "DW_AT_MIPS_tail_loop_begin": 0x2003,
        "DW_AT_MIPS_epilog_begin": 0x2004,
        "DW_AT_MIPS_loop_unroll_factor": 0x2005,
        "DW_AT_MIPS_software_pipeline_depth": 0x2006,
        "DW_AT_MIPS_linkage_name": 0x2007,
        "DW_AT_MIPS_stride": 0x2008,
        "DW_AT_MIPS_abstract_name": 0x2009,
        "DW_AT_MIPS_clone_origin": 0x200A,
        "DW_AT_MIPS_has_inlines": 0x200B,
        "DW_AT_MIPS_stride_byte": 0x200C,
        "DW_AT_MIPS_stride_elem": 0x200D,
        "DW_AT_MIPS_ptr_dopetype": 0x200E,
        "DW_AT_MIPS_allocatable_dopetype": 0x200F,
        "DW_AT_MIPS_assumed_shape_dopetype": 0x2010,
        "DW_AT_MIPS_assumed_size": 0x2011,
        "DW_AT_sf_names": 0x2101,
        "DW_AT_src_info": 0x2102,
        "DW_AT_mac_info": 0x2103,
        "DW_AT_src_coords": 0x2104,
        "DW_AT_body_begin": 0x2105,
        "DW_AT_body_end": 0x2106,
        "DW_AT_GNU_vector": 0x2107,
        "DW_AT_GNU_template_name": 0x2110,
        "DW_AT_GNU_odr_signature": 0x210F,
        "DW_AT_GNU_call_site_value": 0x2111,
        "DW_AT_GNU_call_site_data_value": 0x2112,
        "DW_AT_GNU_call_site_target": 0x2113,
        "DW_AT_GNU_call_site_target_clobbered": 0x2114,
        "DW_AT_GNU_tail_call": 0x2115,
        "DW_AT_GNU_all_tail_call_sites": 0x2116,
        "DW_AT_GNU_all_call_sites": 0x2117,
        "DW_AT_GNU_all_source_call_sites": 0x2118,
        "DW_AT_GNU_macros": 0x2119,
        "DW_AT_GNU_deleted": 0x211A,
        "DW_AT_GNU_dwo_id": 0x2131,
        "DW_AT_GNU_pubnames": 0x2134,
        "DW_AT_GNU_pubtypes": 0x2135,
        "DW_AT_GNU_discriminator": 0x2136,
        "DW_AT_LLVM_include_path": 0x3E00,
        "DW_AT_LLVM_config_macros": 0x3E01,
        "DW_AT_LLVM_isysroot": 0x3E02,
        "DW_AT_LLVM_tag_offset": 0x3E03,
        "DW_AT_APPLE_optimized": 0x3FE1,
        "DW_AT_APPLE_flags": 0x3FE2,
        "DW_AT_APPLE_isa": 0x3FE3,
        "DW_AT_APPLE_block": 0x3FE4,
        "DW_AT_APPLE_major_runtime_vers": 0x3FE5,
        "DW_AT_APPLE_runtime_class": 0x3FE6,
        "DW_AT_APPLE_omit_frame_ptr": 0x3FE7,
        "DW_AT_APPLE_property_name": 0x3FE8,
        "DW_AT_APPLE_property_getter": 0x3FE9,
        "DW_AT_APPLE_property_setter": 0x3FEA,
        "DW_AT_APPLE_property_attribute": 0x3FEB,
        "DW_AT_APPLE_objc_complete_type": 0x3FEC,
        "DW_AT_APPLE_property": 0x3FED,
    }
    DW_AT_MAP = {v: k for k, v in DW_AT.items()}

    DW_LANG = {
        "DW_LANG_C89": 0x0001,
        "DW_LANG_C": 0x0002,
        "DW_LANG_Ada83": 0x0003,
        "DW_LANG_C_plus_plus": 0x0004,
        "DW_LANG_Cobol74": 0x0005,
        "DW_LANG_Cobol85": 0x0006,
        "DW_LANG_Fortran77": 0x0007,
        "DW_LANG_Fortran90": 0x0008,
        "DW_LANG_Pascal83": 0x0009,
        "DW_LANG_Modula2": 0x000A,
        "DW_LANG_Java": 0x000B,
        "DW_LANG_C99": 0x000C,
        "DW_LANG_Ada95": 0x000D,
        "DW_LANG_Fortran95": 0x000E,
        "DW_LANG_PLI": 0x000F,
        "DW_LANG_ObjC": 0x0010,
        "DW_LANG_ObjC_plus_plus": 0x0011,
        "DW_LANG_UPC": 0x0012,
        "DW_LANG_D": 0x0013,
        "DW_LANG_Python": 0x0014,
        "DW_LANG_OpenCL": 0x0015,
        "DW_LANG_Go": 0x0016,
        "DW_LANG_Modula3": 0x0017,
        "DW_LANG_Haskell": 0x0018,
        "DW_LANG_C_plus_plus_03": 0x0019,
        "DW_LANG_C_plus_plus_11": 0x001A,
        "DW_LANG_OCaml": 0x001B,
        "DW_LANG_Rust": 0x001C,
        "DW_LANG_C11": 0x001D,
        "DW_LANG_Swift": 0x001E,
        "DW_LANG_Julia": 0x001F,
        "DW_LANG_Dylan": 0x0020,
        "DW_LANG_C_plus_plus_14": 0x0021,
        "DW_LANG_Fortran03": 0x0022,
        "DW_LANG_Fortran08": 0x0023,
        "DW_LANG_RenderScript": 0x0024,
        "DW_LANG_BLISS": 0x0025,
        "DW_LANG_Mips_Assembler": 0x8001,
        "DW_LANG_Upc": 0x8765,
        "DW_LANG_HP_Bliss": 0x8003,
        "DW_LANG_HP_Basic91": 0x8004,
        "DW_LANG_HP_Pascal91": 0x8005,
        "DW_LANG_HP_IMacro": 0x8006,
        "DW_LANG_HP_Assembler": 0x8007,
        "DW_LANG_GOOGLE_RenderScript": 0x8E57,
        "DW_LANG_BORLAND_Delphi": 0xB000,
    }
    DW_LANG_MAP = {v: k for k, v in DW_LANG.items()}

    DW_FORM = {
        "DW_FORM_null": 0x00,
        "DW_FORM_addr": 0x01,
        "DW_FORM_ref": 0x02,
        "DW_FORM_block2": 0x03,
        "DW_FORM_block4": 0x04,
        "DW_FORM_data2": 0x05,
        "DW_FORM_data4": 0x06,
        "DW_FORM_data8": 0x07,
        "DW_FORM_string": 0x08,
        "DW_FORM_block": 0x09,
        "DW_FORM_block1": 0x0A,
        "DW_FORM_data1": 0x0B,
        "DW_FORM_flag": 0x0C,
        "DW_FORM_sdata": 0x0D,
        "DW_FORM_strp": 0x0E,
        "DW_FORM_udata": 0x0F,
        "DW_FORM_ref_addr": 0x10,
        "DW_FORM_ref1": 0x11,
        "DW_FORM_ref2": 0x12,
        "DW_FORM_ref4": 0x13,
        "DW_FORM_ref8": 0x14,
        "DW_FORM_ref_udata": 0x15,
        "DW_FORM_indirect": 0x16,
        "DW_FORM_sec_offset": 0x17,
        "DW_FORM_exprloc": 0x18,
        "DW_FORM_flag_present": 0x19,
        "DW_FORM_strx": 0x1A,
        "DW_FORM_addrx": 0x1B,
        "DW_FORM_ref_sup4": 0x1C,
        "DW_FORM_strp_sup": 0x1D,
        "DW_FORM_data16": 0x1E,
        "DW_FORM_line_strp": 0x1F,
        "DW_FORM_ref_sig8": 0x20,
        "DW_FORM_implicit_const": 0x21,
        "DW_FORM_loclistx": 0x22,
        "DW_FORM_rnglistx": 0x23,
        "DW_FORM_ref_sup8": 0x24,
        "DW_FORM_strx1": 0x25,
        "DW_FORM_strx2": 0x26,
        "DW_FORM_strx3": 0x27,
        "DW_FORM_strx4": 0x28,
        "DW_FORM_addrx1": 0x29,
        "DW_FORM_addrx2": 0x2A,
        "DW_FORM_addrx3": 0x2B,
        "DW_FORM_addrx4": 0x2C,
        "DW_FORM_GNU_addr_index": 0x1F01,
        "DW_FORM_GNU_str_index": 0x1F02,
        "DW_FORM_GNU_ref_alt": 0x1F20,
        "DW_FORM_GNU_strp_alt": 0x1F21,
    }
    DW_FORM_MAP = {v: k for k, v in DW_FORM.items()}

    DW_TAG = {
        "DW_TAG_null": 0x00,
        "DW_TAG_array_type": 0x01,
        "DW_TAG_class_type": 0x02,
        "DW_TAG_entry_point": 0x03,
        "DW_TAG_enumeration_type": 0x04,
        "DW_TAG_formal_parameter": 0x05,
        "DW_TAG_imported_declaration": 0x08,
        "DW_TAG_label": 0x0A,
        "DW_TAG_lexical_block": 0x0B,
        "DW_TAG_member": 0x0D,
        "DW_TAG_pointer_type": 0x0F,
        "DW_TAG_reference_type": 0x10,
        "DW_TAG_compile_unit": 0x11,
        "DW_TAG_string_type": 0x12,
        "DW_TAG_structure_type": 0x13,
        "DW_TAG_subroutine_type": 0x15,
        "DW_TAG_typedef": 0x16,
        "DW_TAG_union_type": 0x17,
        "DW_TAG_unspecified_parameters": 0x18,
        "DW_TAG_variant": 0x19,
        "DW_TAG_common_block": 0x1A,
        "DW_TAG_common_inclusion": 0x1B,
        "DW_TAG_inheritance": 0x1C,
        "DW_TAG_inlined_subroutine": 0x1D,
        "DW_TAG_module": 0x1E,
        "DW_TAG_ptr_to_member_type": 0x1F,
        "DW_TAG_set_type": 0x20,
        "DW_TAG_subrange_type": 0x21,
        "DW_TAG_with_stmt": 0x22,
        "DW_TAG_access_declaration": 0x23,
        "DW_TAG_base_type": 0x24,
        "DW_TAG_catch_block": 0x25,
        "DW_TAG_const_type": 0x26,
        "DW_TAG_constant": 0x27,
        "DW_TAG_enumerator": 0x28,
        "DW_TAG_file_type": 0x29,
        "DW_TAG_friend": 0x2A,
        "DW_TAG_namelist": 0x2B,
        "DW_TAG_namelist_item": 0x2C,
        "DW_TAG_namelist_items": 0x2C,
        "DW_TAG_packed_type": 0x2D,
        "DW_TAG_subprogram": 0x2E,
        "DW_TAG_template_type_param": 0x2F,
        "DW_TAG_template_value_param": 0x30,
        "DW_TAG_thrown_type": 0x31,
        "DW_TAG_try_block": 0x32,
        "DW_TAG_variant_part": 0x33,
        "DW_TAG_variable": 0x34,
        "DW_TAG_volatile_type": 0x35,
        "DW_TAG_dwarf_procedure": 0x36,
        "DW_TAG_restrict_type": 0x37,
        "DW_TAG_interface_type": 0x38,
        "DW_TAG_namespace": 0x39,
        "DW_TAG_imported_module": 0x3A,
        "DW_TAG_unspecified_type": 0x3B,
        "DW_TAG_partial_unit": 0x3C,
        "DW_TAG_imported_unit": 0x3D,
        "DW_TAG_mutable_type": 0x3E,
        "DW_TAG_condition": 0x3F,
        "DW_TAG_shared_type": 0x40,
        "DW_TAG_type_unit": 0x41,
        "DW_TAG_rvalue_reference_type": 0x42,
        "DW_TAG_atomic_type": 0x47,
        "DW_TAG_call_site": 0x48,
        "DW_TAG_call_site_parameter": 0x49,
        "DW_TAG_skeleton_unit": 0x4A,
        "DW_TAG_immutable_type": 0x4B,
        "DW_TAG_lo_user": 0x4080,
        "DW_TAG_GNU_template_template_param": 0x4106,
        "DW_TAG_GNU_template_parameter_pack": 0x4107,
        "DW_TAG_GNU_formal_parameter_pack": 0x4108,
        "DW_TAG_GNU_call_site": 0x4109,
        "DW_TAG_GNU_call_site_parameter": 0x410A,
        "DW_TAG_APPLE_property": 0x4200,
        "DW_TAG_hi_user": 0xFFFF,
    }
    DW_TAG_MAP = {v: k for k, v in DW_TAG.items()}

    DW_EH_ENCODING_FLAGS = {
        "DW_EH_PE_absptr": 0x00,
        "DW_EH_PE_uleb128": 0x01,
        "DW_EH_PE_udata2": 0x02,
        "DW_EH_PE_udata4": 0x03,
        "DW_EH_PE_udata8": 0x04,
        "DW_EH_PE_signed": 0x08,
        "DW_EH_PE_sleb128": 0x09,
        "DW_EH_PE_sdata2": 0x0A,
        "DW_EH_PE_sdata4": 0x0B,
        "DW_EH_PE_sdata8": 0x0C,
        "DW_EH_PE_pcrel": 0x10,
        "DW_EH_PE_textrel": 0x20,
        "DW_EH_PE_datarel": 0x30,
        "DW_EH_PE_funcrel": 0x40,
        "DW_EH_PE_aligned": 0x50,
        "DW_EH_PE_indirect": 0x80,
        "DW_EH_PE_omit": 0xFF,
    }
    DW_EH_ENCODING_MAP = {v: k for k, v in DW_EH_ENCODING_FLAGS.items()}

    DW_INST = {
        "DW_CFA_advance_loc": 0b01000000,
        "DW_CFA_offset": 0b10000000,
        "DW_CFA_restore": 0b11000000,
        "DW_CFA_nop": 0x00,
        "DW_CFA_set_loc": 0x01,
        "DW_CFA_advance_loc1": 0x02,
        "DW_CFA_advance_loc2": 0x03,
        "DW_CFA_advance_loc4": 0x04,
        "DW_CFA_offset_extended": 0x05,
        "DW_CFA_restore_extended": 0x06,
        "DW_CFA_undefined": 0x07,
        "DW_CFA_same_value": 0x08,
        "DW_CFA_register": 0x09,
        "DW_CFA_remember_state": 0x0A,
        "DW_CFA_restore_state": 0x0B,
        "DW_CFA_def_cfa": 0x0C,
        "DW_CFA_def_cfa_register": 0x0D,
        "DW_CFA_def_cfa_offset": 0x0E,
        "DW_CFA_def_cfa_expression": 0x0F,
        "DW_CFA_expression": 0x10,
        "DW_CFA_offset_extended_sf": 0x11,
        "DW_CFA_def_cfa_sf": 0x12,
        "DW_CFA_def_cfa_offset_sf": 0x13,
        "DW_CFA_val_offset": 0x14,
        "DW_CFA_val_offset_sf": 0x15,
        "DW_CFA_val_expression": 0x16,
        "DW_CFA_GNU_args_size": 0x2E,
        "DW_PRIMARY_MASK": 0b11000000,
        "DW_PRIMARY_ARG_MASK": 0b00111111,
    }
    DW_INST_MAP = {v: k for k, v in DW_INST.items()}

    DW_OPS_NAMES = {
        "DW_OP_addr": 0x03,
        "DW_OP_deref": 0x06,
        "DW_OP_const1u": 0x08,
        "DW_OP_const1s": 0x09,
        "DW_OP_const2u": 0x0A,
        "DW_OP_const2s": 0x0B,
        "DW_OP_const4u": 0x0C,
        "DW_OP_const4s": 0x0D,
        "DW_OP_const8u": 0x0E,
        "DW_OP_const8s": 0x0F,
        "DW_OP_constu": 0x10,
        "DW_OP_consts": 0x11,
        "DW_OP_dup": 0x12,
        "DW_OP_drop": 0x13,
        "DW_OP_over": 0x14,
        "DW_OP_pick": 0x15,
        "DW_OP_swap": 0x16,
        "DW_OP_rot": 0x17,
        "DW_OP_xderef": 0x18,
        "DW_OP_abs": 0x19,
        "DW_OP_and": 0x1A,
        "DW_OP_div": 0x1B,
        "DW_OP_minus": 0x1C,
        "DW_OP_mod": 0x1D,
        "DW_OP_mul": 0x1E,
        "DW_OP_neg": 0x1F,
        "DW_OP_not": 0x20,
        "DW_OP_or": 0x21,
        "DW_OP_plus": 0x22,
        "DW_OP_plus_uconst": 0x23,
        "DW_OP_shl": 0x24,
        "DW_OP_shr": 0x25,
        "DW_OP_shra": 0x26,
        "DW_OP_xor": 0x27,
        "DW_OP_bra": 0x28,
        "DW_OP_eq": 0x29,
        "DW_OP_ge": 0x2A,
        "DW_OP_gt": 0x2B,
        "DW_OP_le": 0x2C,
        "DW_OP_lt": 0x2D,
        "DW_OP_ne": 0x2E,
        "DW_OP_skip": 0x2F,
        "DW_OP_regx": 0x90,
        "DW_OP_fbreg": 0x91,
        "DW_OP_bregx": 0x92,
        "DW_OP_piece": 0x93,
        "DW_OP_deref_size": 0x94,
        "DW_OP_xderef_size": 0x95,
        "DW_OP_nop": 0x96,
        "DW_OP_push_object_address": 0x97,
        "DW_OP_call2": 0x98,
        "DW_OP_call4": 0x99,
        "DW_OP_call_ref": 0x9A,
        "DW_OP_form_tls_address": 0x9B,
        "DW_OP_call_frame_cfa": 0x9C,
        "DW_OP_bit_piece": 0x9D,
        "DW_OP_implicit_value": 0x9E,
        "DW_OP_stack_value": 0x9F,
        "DW_OP_implicit_pointer": 0xA0,
        "DW_OP_addrx": 0xA1,
        "DW_OP_constx": 0xA2,
        "DW_OP_entry_value": 0xA3,
        "DW_OP_const_type": 0xA4,
        "DW_OP_regval_type": 0xA5,
        "DW_OP_deref_type": 0xA6,
        "DW_OP_xderef_type": 0xA7,
        "DW_OP_convert": 0xA8,
        "DW_OP_reinterpret": 0xA9,
        "DW_OP_lo_user": 0xE0,
        "DW_OP_GNU_push_tls_address": 0xE0,
        "DW_OP_GNU_implicit_pointer": 0xF2,
        "DW_OP_GNU_entry_value": 0xF3,
        "DW_OP_GNU_const_type": 0xF4,
        "DW_OP_GNU_regval_type": 0xF5,
        "DW_OP_GNU_deref_type": 0xF6,
        "DW_OP_GNU_convert": 0xF7,
        "DW_OP_GNU_parameter_ref": 0xFA,
        "DW_OP_hi_user": 0xFF,
    }
    DW_OPS_NAMES.update(UtilMgr.genRangeDict("DW_OP_lit", 0, 31, 0x30))
    DW_OPS_NAMES.update(UtilMgr.genRangeDict("DW_OP_reg", 0, 31, 0x50))
    DW_OPS_NAMES.update(UtilMgr.genRangeDict("DW_OP_breg", 0, 31, 0x70))
    DW_OPS_NAMES_MAP = {v: k for k, v in DW_OPS_NAMES.items()}

    DW_UT = {
        "DW_UT_compile": 0x01,
        "DW_UT_type": 0x02,
        "DW_UT_partial": 0x03,
        "DW_UT_skeleton": 0x04,
        "DW_UT_split_compile": 0x05,
        "DW_UT_split_type": 0x06,
        "DW_UT_lo_user": 0x80,
        "DW_UT_hi_user": 0xFF,
    }
    DW_UT_MAP = {v: k for k, v in DW_UT.items()}

    DW_OPS_NOARGS = dict.fromkeys(
        [
            "DW_OP_deref",
            "DW_OP_dup",
            "DW_OP_drop",
            "DW_OP_over",
            "DW_OP_swap",
            "DW_OP_swap",
            "DW_OP_rot",
            "DW_OP_xderef",
            "DW_OP_abs",
            "DW_OP_and",
            "DW_OP_div",
            "DW_OP_minus",
            "DW_OP_mod",
            "DW_OP_mul",
            "DW_OP_neg",
            "DW_OP_not",
            "DW_OP_or",
            "DW_OP_plus",
            "DW_OP_shl",
            "DW_OP_shr",
            "DW_OP_shra",
            "DW_OP_xor",
            "DW_OP_eq",
            "DW_OP_ge",
            "DW_OP_gt",
            "DW_OP_le",
            "DW_OP_lt",
            "DW_OP_ne",
            "DW_OP_nop",
            "DW_OP_push_object_address",
            "DW_OP_form_tls_address",
            "DW_OP_call_frame_cfa",
            "DW_OP_stack_value",
            "DW_OP_GNU_push_tls_address",
        ]
        + ["DW_OP_lit%s" % idx for idx in xrange(32)]
        + ["DW_OP_reg%s" % idx for idx in xrange(32)]
    )

    DW_OPS_DEC_ARGS = set(
        [
            "DW_OP_const1u",
            "DW_OP_const1s",
            "DW_OP_const2u",
            "DW_OP_const2s",
            "DW_OP_const4u",
            "DW_OP_const4s",
            "DW_OP_const8u",
            "DW_OP_const8s",
            "DW_OP_constu",
            "DW_OP_consts",
            "DW_OP_pick",
            "DW_OP_plus_uconst",
            "DW_OP_bra",
            "DW_OP_skip",
            "DW_OP_fbreg",
            "DW_OP_piece",
            "DW_OP_deref_size",
            "DW_OP_xderef_size",
            "DW_OP_regx",
        ]
        + ["DW_OP_breg%s" % idx for idx in xrange(32)]
    )

    DW_OPS_2DEC_ARGS = set(["DW_OP_bregx", "DW_OP_bit_piece"])

    DW_OPS_HEX_ARGS = set(
        ["DW_OP_addr", "DW_OP_call2", "DW_OP_call4", "DW_OP_call_ref"]
    )

    DW_CFI_REGISTER_RULE_TYPE = dict(
        UNDEFINED="u",
        SAME_VALUE="s",
        OFFSET="c",
        VAL_OFFSET="v",
        REGISTER="",
        EXPRESSION="exp",
        VAL_EXPRESSION="vexp",
        ARCHITECTURAL="a",
    )

    class EHABIBytecodeDecoder(object):
        """
        refer to https://github.com/eliben/pyelftools
        Decoder of a sequence of ARM exception handler abi bytecode.

        Reference:
        https://github.com/llvm/llvm-project/blob/master/llvm/tools/llvm-readobj/ARMEHABIPrinter.h
        https://developer.arm.com/documentation/ihi0038/b/

        Accessible attributes:
            mnemonic_array:
                MnemonicItem array.

        Parameters:
            bytecode_array:
                Integer array, raw data of bytecode.
        """

        def __init__(self, bytecode_array, path=None):
            self.path = path
            self._bytecode_array = bytecode_array
            self._index = None
            self.mnemonic_array = []
            self.cfa_table = {}
            if bytecode_array:
                self._decode()

        def _getMnemonicItem(self, bytecode, mnemonic):
            return "%s ; %s" % (
                " ".join(["0x%02x" % x for x in bytecode]),
                mnemonic,
            )

        def _decode(self):
            # pylint: disable=too-many-function-args
            """Decode bytecode array, put result into mnemonic_array."""
            sp_opsstr = "vsp = vsp "
            sp_defstr = "vsp = r"
            pop_str = "pop {"

            fpIdx = 11
            ipIdx = 12
            spIdx = 13
            lrIdx = 14
            pcIdx = 15

            self._index = 0
            self.offset = 0

            while self._index < len(self._bytecode_array):
                for mask, value, handler in self.ring:
                    if (self._bytecode_array[self._index] & mask) != value:
                        continue

                    # decode code #
                    start_idx = self._index
                    mnemonic = handler(self)
                    end_idx = self._index

                    # convert code to string #
                    dstr = self._getMnemonicItem(
                        self._bytecode_array[start_idx:end_idx], mnemonic
                    )
                    self.mnemonic_array.append(dstr)

                    # convert to offset #
                    if mnemonic == "finish":
                        break

                    # apply CFA offset #
                    if mnemonic.startswith(sp_opsstr):
                        ops = mnemonic[len(sp_opsstr) :]
                        if ops[0] == "+":
                            offset = long(ops[1:])
                        else:
                            offset = -long(ops[1:])

                        # change offset #
                        if "cfa" in self.cfa_table:
                            cfaList = list(self.cfa_table["cfa"])
                            cfaList[1] += offset
                            self.cfa_table["cfa"] = tuple(cfaList)
                        else:
                            self.cfa_table["cfa"] = (spIdx, offset, None)
                    # define CFA #
                    elif mnemonic.startswith(sp_defstr):
                        reg = long(mnemonic[len(sp_defstr) :])
                        self.cfa_table["cfa"] = (reg, 0, None)
                    # set regs #
                    elif mnemonic.startswith(pop_str):
                        regs = mnemonic[len(pop_str) : -1].split(", ")
                        val = "OFFSET"
                        for reg in regs:
                            if reg == "lr":
                                self.cfa_table[lrIdx] = (val, self.offset)
                            elif reg == "fp":
                                self.cfa_table[fpIdx] = (val, self.offset)
                            elif reg == "sp":
                                self.cfa_table[spIdx] = (val, self.offset)
                            elif reg == "ip":
                                self.cfa_table[ipIdx] = (val, self.offset)
                            elif reg == "pc":
                                self.cfa_table[pcIdx] = (val, self.offset)
                            else:
                                reg = long(reg[1:])
                                self.cfa_table[reg] = (val, self.offset)

                            # only ARM 32bit supported #
                            self.offset += 4
                    else:
                        SysMgr.printWarn(
                            "unknown operation '%s' in %s"
                            % (mnemonic, self.path)
                        )

                    break

            # set default CFA #
            if not "cfa" in self.cfa_table:
                self.cfa_table["cfa"] = (spIdx, 0, None)

        def _decode_00xxxxxx(self):
            opcode = self._bytecode_array[self._index]
            self._index += 1
            return "vsp = vsp + %u" % (((opcode & 0x3F) << 2) + 4)

        def _decode_01xxxxxx(self):
            opcode = self._bytecode_array[self._index]
            self._index += 1
            return "vsp = vsp - %u" % (((opcode & 0x3F) << 2) + 4)

        gpr_register_names = (
            "r0",
            "r1",
            "r2",
            "r3",
            "r4",
            "r5",
            "r6",
            "r7",
            "r8",
            "r9",
            "r10",
            "fp",
            "ip",
            "sp",
            "lr",
            "pc",
        )

        def _calculate_xrange(self, start, count):
            return ((1 << (count + 1)) - 1) << start

        def _printGPR(self, gpr_mask):
            hits = [
                self.gpr_register_names[i]
                for i in xrange(32)
                if gpr_mask & (1 << i) != 0
            ]
            return "{%s}" % ", ".join(hits)

        def _print_registers(self, vfp_mask, prefix):
            hits = [
                prefix + str(i) for i in xrange(32) if vfp_mask & (1 << i) != 0
            ]
            return "{%s}" % ", ".join(hits)

        def _decode_1000iiii_iiiiiiii(self):
            op0 = self._bytecode_array[self._index]
            self._index += 1
            op1 = self._bytecode_array[self._index]
            self._index += 1
            gpr_mask = (op1 << 4) | ((op0 & 0x0F) << 12)
            if gpr_mask == 0:
                return "refuse to unwind"
            else:
                return "pop %s" % self._printGPR(gpr_mask)

        def _decode_10011101(self):
            self._index += 1
            return "reserved (ARM MOVrr)"

        def _decode_10011111(self):
            self._index += 1
            return "reserved (WiMMX MOVrr)"

        def _decode_1001nnnn(self):
            opcode = self._bytecode_array[self._index]
            self._index += 1
            return "vsp = r%u" % (opcode & 0x0F)

        def _decode_10100nnn(self):
            opcode = self._bytecode_array[self._index]
            self._index += 1
            return "pop %s" % self._printGPR(
                self._calculate_xrange(4, opcode & 0x07)
            )

        def _decode_10101nnn(self):
            opcode = self._bytecode_array[self._index]
            self._index += 1
            return "pop %s" % self._printGPR(
                self._calculate_xrange(4, opcode & 0x07) | (1 << 14)
            )

        def _decode_10110000(self):
            self._index += 1
            return "finish"

        def _decode_10110001_0000iiii(self):
            self._index += 1  # skip constant byte
            op1 = self._bytecode_array[self._index]
            self._index += 1
            if (op1 & 0xF0) != 0 or op1 == 0x00:
                return "spare"
            else:
                return "pop %s" % self._printGPR((op1 & 0x0F))

        def _decode_10110010_uleb128(self):
            self._index += 1  # skip constant byte
            uleb_buffer = [self._bytecode_array[self._index]]
            self._index += 1
            while self._bytecode_array[self._index] & 0x80 == 0:
                uleb_buffer.append(self._bytecode_array[self._index])
                self._index += 1
            value = 0
            for b in reversed(uleb_buffer):
                value = (value << 7) + (b & 0x7F)
            return "vsp = vsp + %u" % (0x204 + (value << 2))

        def _decode_10110011_sssscccc(self):
            # these two decoders are equal
            return self._decode_11001001_sssscccc()

        def _decode_101101nn(self):
            return self._spare()

        def _decode_10111nnn(self):
            opcode = self._bytecode_array[self._index]
            self._index += 1
            return "pop %s" % self._print_registers(
                self._calculate_xrange(8, opcode & 0x07), "d"
            )

        def _decode_11000110_sssscccc(self):
            self._index += 1  # skip constant byte
            op1 = self._bytecode_array[self._index]
            self._index += 1
            start = (op1 & 0xF0) >> 4
            count = (op1 & 0x0F) >> 0
            return "pop %s" % self._print_registers(
                self._calculate_xrange(start, count), "wR"
            )

        def _decode_11000111_0000iiii(self):
            self._index += 1  # skip constant byte
            op1 = self._bytecode_array[self._index]
            self._index += 1
            if (op1 & 0xF0) != 0 or op1 == 0x00:
                return "spare"
            else:
                return "pop %s" % self._print_registers(op1 & 0x0F, "wCGR")

        def _decode_11001000_sssscccc(self):
            self._index += 1  # skip constant byte
            op1 = self._bytecode_array[self._index]
            self._index += 1
            start = 16 + ((op1 & 0xF0) >> 4)
            count = (op1 & 0x0F) >> 0
            return "pop %s" % self._print_registers(
                self._calculate_xrange(start, count), "d"
            )

        def _decode_11001001_sssscccc(self):
            self._index += 1  # skip constant byte
            op1 = self._bytecode_array[self._index]
            self._index += 1
            start = (op1 & 0xF0) >> 4
            count = (op1 & 0x0F) >> 0
            return "pop %s" % self._print_registers(
                self._calculate_xrange(start, count), "d"
            )

        def _decode_11001yyy(self):
            return self._spare()

        def _decode_11000nnn(self):
            opcode = self._bytecode_array[self._index]
            self._index += 1
            return "pop %s" % self._print_registers(
                self._calculate_xrange(10, opcode & 0x07), "wR"
            )

        def _decode_11010nnn(self):
            # these two decoders are equal
            return self._decode_10111nnn()

        def _decode_11xxxyyy(self):
            return self._spare()

        def _spare(self):
            self._index += 1
            return "spare"

        ring = (
            (0xC0, 0x00, _decode_00xxxxxx),
            (0xC0, 0x40, _decode_01xxxxxx),
            (0xF0, 0x80, _decode_1000iiii_iiiiiiii),
            (0xFF, 0x9D, _decode_10011101),
            (0xFF, 0x9F, _decode_10011111),
            (0xF0, 0x90, _decode_1001nnnn),
            (0xF8, 0xA0, _decode_10100nnn),
            (0xF8, 0xA8, _decode_10101nnn),
            (0xFF, 0xB0, _decode_10110000),
            (0xFF, 0xB1, _decode_10110001_0000iiii),
            (0xFF, 0xB2, _decode_10110010_uleb128),
            (0xFF, 0xB3, _decode_10110011_sssscccc),
            (0xFC, 0xB4, _decode_101101nn),
            (0xF8, 0xB8, _decode_10111nnn),
            (0xFF, 0xC6, _decode_11000110_sssscccc),
            (0xFF, 0xC7, _decode_11000111_0000iiii),
            (0xFF, 0xC8, _decode_11001000_sssscccc),
            (0xFF, 0xC9, _decode_11001001_sssscccc),
            (0xC8, 0xC8, _decode_11001yyy),
            (0xF8, 0xC0, _decode_11000nnn),
            (0xF8, 0xD0, _decode_11010nnn),
            (0xC0, 0xC0, _decode_11xxxyyy),
        )

    class RegisterRule(object):
        """
        refer to https://github.com/eliben/pyelftools
        Register rules are used to find registers in call frames. Each rule
        consists of a type (enumeration following DWARFv3 section 6.4.1)
        and an optional argument to augment the type.
        """

        UNDEFINED = "UNDEFINED"
        SAME_VALUE = "SAME_VALUE"
        OFFSET = "OFFSET"
        VAL_OFFSET = "VAL_OFFSET"
        REGISTER = "REGISTER"
        EXPRESSION = "EXPRESSION"
        VAL_EXPRESSION = "VAL_EXPRESSION"
        ARCHITECTURAL = "ARCHITECTURAL"

        TYPE = 0
        ARG = 1

        def __init__(self, type, arg=None):
            pass

        def __new__(self, type, arg=None):
            return (type, arg)

    class CFARule(object):
        """
        refer to https://github.com/eliben/pyelftools
        A CFA rule is used to compute the CFA for each location. It either
        consists of a register+offset, or a DWARF expression.
        """

        REG = 0
        OFFSET = 1
        EXPR = 2

        def __init__(self, reg=None, offset=None, expr=None):
            pass

        def __new__(self, reg=None, offset=None, expr=None):
            return (reg, offset, expr)

    cachedFiles = {}
    cachedHeaderFiles = {}
    preloadedFiles = {}
    cachedCFAs = {}
    cachedTypes = {}
    strippedFiles = {}
    failedFiles = {}
    relocTypes = {}
    cachedDemangleTable = {}
    overlayTable = {}

    @staticmethod
    def getCFARule(reg=None, offset=None, expr=None):
        key = "%s%s%s" % (reg, offset, expr)
        if not key in ElfAnalyzer.cachedCFAs:
            ElfAnalyzer.cachedCFAs[key] = ElfAnalyzer.CFARule(
                reg, offset, expr
            )
        return ElfAnalyzer.cachedCFAs[key]

    @staticmethod
    def ELF_ST_BIND(i):
        return (i) >> 4

    @staticmethod
    def ELF_ST_TYPE(i):
        return (i) & 0x0F

    @staticmethod
    def ELF_ST_INFO(b, t):
        return (b) << 4 + ((t) & 0x0F)

    @staticmethod
    def ELF_ST_VISIBILITY(i):
        return (i) & 0x3

    @staticmethod
    def ELF32_R_SYM(i):
        return (i) >> 8

    @staticmethod
    def ELF32_R_TYPE(i):
        return (i) & 0xFF

    @staticmethod
    def ELF32_R_INFO(s, t):
        return ((s) << 8) + ((t) & 0xFF)

    @staticmethod
    def ELF64_R_SYM(i):
        return (i) >> 32

    @staticmethod
    def ELF64_R_TYPE(i):
        return (i) & 0xFFFFFFFF

    @staticmethod
    def ELF64_R_INFO(s, type):
        return ((s) << 32) + ((s) & 0xFFFFFFFF)

    @staticmethod
    def DT_VERSIONTAGIDX(tag):
        return ElfAnalyzer.DT_VERNEEDNUM - (tag)

    @staticmethod
    def getHeader(path):
        if path not in ElfAnalyzer.cachedHeaderFiles:
            try:
                ElfAnalyzer.cachedHeaderFiles[path] = ElfAnalyzer(
                    path, onlyHeader=True
                )
            except:
                return None

        return ElfAnalyzer.cachedHeaderFiles[path]

    @staticmethod
    def iteratePhdr():
        # load libc #
        SysMgr.loadLibcObj(exit=True)

        # define word size #
        if ConfigMgr.wordSize == 4:
            dlpi_addr_t = c_int32
        else:
            dlpi_addr_t = c_int64

        class dl_phdr_info(Structure):
            _fields_ = [
                ("dlpi_addr", dlpi_addr_t),
                ("dlpi_name", c_char_p),
                ("dlpi_phdr", c_void_p),
                ("dlpi_phnum", c_uint16),
                ("dlpi_adds", c_ulonglong),
                ("dlpi_subs", c_ulonglong),
                ("dlpi_tls_modid", c_size_t),
                ("dlpi_tls_data", c_void_p),
            ]

        callback_t = CFUNCTYPE(
            c_int, POINTER(dl_phdr_info), POINTER(c_size_t), c_char_p
        )

        # define dl_iterate_phdr #
        SysMgr.libcObj.dl_iterate_phdr.argtypes = [callback_t, c_char_p]
        SysMgr.libcObj.dl_iterate_phdr.restype = c_int

        def callback(info, size, data):
            if not info.contents.dlpi_name:
                return 0

            # 32-bit #
            if ConfigMgr.wordSize == 4:
                bufSize = 32
            else:
                bufSize = 56

            # create a buffer for Elfxx_Phdr #
            lbuf = (c_char * bufSize)()
            memmove(addressof(lbuf), info.contents.dlpi_phdr, sizeof(lbuf))

            # 32-bit #
            if ConfigMgr.wordSize == 4:
                (
                    p_type,
                    p_offset,
                    p_vaddr,
                    p_paddr,
                    p_filesz,
                    p_memsz,
                    p_flags,
                    p_align,
                ) = struct.unpack("IIIIIIII", lbuf)
            # 64-bit #
            else:
                (
                    p_type,
                    p_flags,
                    p_offset,
                    p_vaddr,
                    p_paddr,
                    p_filesz,
                    p_memsz,
                    p_align,
                ) = struct.unpack("IIQQQQQQ", lbuf)

            return 0

        # call function #
        SysMgr.libcObj.dl_iterate_phdr(callback_t(callback), None)

    @staticmethod
    def saveObject(obj, path):
        # check cache dir #
        if not os.path.isdir(SysMgr.cacheDirPath):
            try:
                os.makedirs(SysMgr.cacheDirPath)
            except:
                SysMgr.printWarn(
                    "failed to make %s directory" % SysMgr.cacheDirPath,
                    reason=True,
                )

        # build cache path #
        cpath = "%s/%s" % (SysMgr.cacheDirPath, path.replace("/", "_"))

        return UtilMgr.saveObject2File(obj, cpath)

    @staticmethod
    def getCachedFilename(path):
        return "%s/%s" % (SysMgr.cacheDirPath, path.replace("/", "_"))

    @staticmethod
    def loadObject(path):
        # ignore file cache #
        if "NOFILECACHE" in SysMgr.environList:
            return None

        # build cache path #
        cpath = ElfAnalyzer.getCachedFilename(path)

        # check modified time #
        try:
            otime = os.stat(path).st_ctime
            ctime = os.stat(cpath).st_ctime

            # check expired cache #
            if otime > ctime:
                SysMgr.printWarn(
                    "'%s' is more recent than the cache '%s'" % (path, cpath)
                )
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # load object from file #
        obj = UtilMgr.loadObjectFromFile(cpath)
        if not obj:
            return None

        # check binary size #
        dpath = obj.path
        if obj.fileSize != os.stat(dpath).st_size:
            return None

        return obj

    @staticmethod
    def getObject(path, fobj=None, cache=True, overlay=None, log=False):
        # remove segment number #
        path = path.split(SysMgr.magicStr)[0]

        # save original path #
        origPath = path

        # convert file path on overlayfs #
        if path in ElfAnalyzer.overlayTable:
            path = ElfAnalyzer.overlayTable[path]

        # immediate return for cached object #
        if cache and path in ElfAnalyzer.cachedFiles:
            return ElfAnalyzer.cachedFiles[path]

        # check overlayfs #
        if overlay and path.startswith("/") and not os.path.exists(path):
            path = UtilMgr.convOverlayPath(path, overlay)
            if path != origPath:
                ElfAnalyzer.overlayTable[origPath] = path
            if path in ElfAnalyzer.failedFiles:
                ElfAnalyzer.failedFiles.pop(path, None)

        # check black-list #
        if path in ElfAnalyzer.failedFiles:
            return None

        # check deleted files #
        if "(deleted)" in path:
            ElfAnalyzer.failedFiles[path] = True
            SysMgr.printWarn(
                "failed to load %s because it is already deleted" % path
            )
            return None

        # check print flag for load messages #
        if "NOLOADMSG" in SysMgr.environList:
            printMsg = False
        else:
            printMsg = True

        # load files #
        if not cache or not path in ElfAnalyzer.cachedFiles:
            # check exceptional case #
            if path != "vdso" and not os.path.exists(path):
                return None

            # handle VDSO #
            if path == "vdso":
                fobj = SysMgr.getVDSO()

            # print load message #
            if printMsg:
                SysMgr.printInfo(
                    "load %s... " % path, prefix=False, suffix=False
                )
                prefix = False

            # return a exceptional file object #
            if fobj:
                if printMsg:
                    SysMgr.printInfo("[done]", prefix=False, title=False)
                return fobj

            # try to load a object from cache #
            fobj = ElfAnalyzer.loadObject(path)
            if fobj:
                if SysMgr.dwarfEnable and (
                    not "dwarfEnabled" in fobj.attr
                    or not fobj.attr["dwarfEnabled"]
                ):
                    pass
                else:
                    ElfAnalyzer.cachedFiles[path] = fobj
                    ElfAnalyzer.cachedFiles[path].saved = True

                    if printMsg:
                        SysMgr.printInfo("[cached]", prefix=False, title=False)

                    return fobj

            raiseExcept = False

            # create a new object #
            try:
                elfObj = ElfAnalyzer(path)
                if not elfObj or not elfObj.ret:
                    raiseExcept = True
                    raise Exception("no ELF format")

                ElfAnalyzer.cachedFiles[path] = elfObj

                if printMsg:
                    SysMgr.printInfo("[done]", prefix=False, title=False)
            except SystemExit:
                sys.exit(0)
            except:
                ElfAnalyzer.failedFiles[path] = True

                if printMsg:
                    failLog = UtilMgr.convColor("[fail]", "RED")
                    SysMgr.printInfo(failLog, prefix=False, title=False)

                SysMgr.printWarn(
                    "failed to load '%s' as an ELF object" % path, reason=True
                )

                if raiseExcept:
                    raise Exception("wrong binary")
                else:
                    return None

        # save object cache to file #
        if not ElfAnalyzer.cachedFiles[path].saved:
            ElfAnalyzer.saveObject(ElfAnalyzer.cachedFiles[path], path)
            ElfAnalyzer.cachedFiles[path].saved = True

        return ElfAnalyzer.cachedFiles[path]

    @staticmethod
    def demangleJavaSym(symbol):
        return symbol

    @staticmethod
    def demangleRustSymPre(symbol):
        """
        refer to https://rust-lang.github.io/rfcs/2603-rust-symbol-name-mangling-v0.html

        Symbols begin with _R from v0.
        """

        if not symbol.startswith("_ZN"):
            return symbol, False

        # remove E. suffix #
        if "E." in symbol:
            symbol = symbol[: symbol.rfind("E.")]

        hash_prefix_len = 3
        hash_len = 16
        hashTotal = hash_prefix_len + hash_len

        # remove 17 prefix #
        if symbol[:-hash_len].endswith("17h"):
            symbol = "_Z" + symbol[3:-hashTotal]

        return symbol, True

    @staticmethod
    def demangleRustSym(symbol):
        """
        refer to https://elixir.bootlin.com/linux/latest/source/tools/perf/util/demangle-rust.c #

        Legacy Rust symbols always end with E.
        Legacy Rust symbols also always end with a path segment
        that encodes a 16 hex digit hash, i.e. '17h[a-f0-9]{16}'.
        This early check, before any parse_ident calls, should
        quickly filter out most C++ symbols unrelated to Rust.
        """

        hash_prefix = "::h"
        hash_prefix_len = 3
        hash_len = 16
        hashTotal = hash_prefix_len + hash_len

        # check symbol #
        if len(symbol) <= hashTotal:
            return symbol

        # convert chars #
        for char in ElfAnalyzer.rustChars:
            symbol = symbol.replace(char[1], char[0])

        # check symbol #
        if len(symbol) <= hashTotal:
            return symbol

        if symbol[:-hash_len].endswith("::h"):
            symbol = symbol[:-hashTotal]

        return symbol

    @staticmethod
    def demangleSymbol(symbol, incArg=True):
        # pylint: disable=not-callable
        origSym = symbol
        symbol = symbol.replace("@@", "@")

        if not SysMgr.demangleEnable:
            return symbol

        # check mangling #
        if not symbol.startswith("_Z"):
            return symbol

        # check cache table #
        if symbol in ElfAnalyzer.cachedDemangleTable:
            return ElfAnalyzer.cachedDemangleTable[symbol]

        # get ctypes object #
        if not SysMgr.importPkgItems("ctypes", False):
            SysMgr.printWarn(
                (
                    "failed to import python package: ctypes "
                    "to demangle symbol, so that "
                    "disable demangle feature"
                ),
                True,
            )
            SysMgr.demangleEnable = False
            return symbol

        # try to demangle symbol #
        try:
            # load libc #
            ret = SysMgr.loadLibcObj()
            if not ret:
                return symbol

            # load demangle library #
            if not SysMgr.libdemangleObj:
                # update libllvm name #
                if "LIBLLVM" in SysMgr.environList:
                    SysMgr.libLLVMPath = SysMgr.environList["LIBLLVM"][0]

                # load llvm library #
                SysMgr.libLLVMObj = SysMgr.libdemangleObj = SysMgr.loadLib(
                    SysMgr.libLLVMPath
                )

                # load standard library #
                if not SysMgr.libdemangleObj:
                    SysMgr.libdemangleObj = SysMgr.loadLib(
                        SysMgr.libdemanglePath
                    )

            # check standard library #
            if not SysMgr.libdemangleObj:
                SysMgr.printWarn(
                    (
                        "failed to load demangle object: %s "
                        "to demangle symbol, so that "
                        "disable demangle feature"
                    )
                    % SysMgr.libdemanglePath,
                    True,
                )
                SysMgr.demangleEnable = False
                return symbol

            # declare demangler #
            if not SysMgr.demangleFunc:
                # llvm::itaniumDemangle() #
                llvmFunc = "_ZN4llvm15itaniumDemangleEPKcPcPmPi"
                if hasattr(SysMgr.libdemangleObj, llvmFunc):
                    SysMgr.demangleFunc = getattr(
                        SysMgr.libdemangleObj, llvmFunc
                    )
                # __cxa_demangle() #
                else:
                    SysMgr.demangleFunc = getattr(
                        SysMgr.libdemangleObj, "__cxa_demangle"
                    )

                # define return type for demangler #
                SysMgr.demangleFunc.restype = c_void_p

                # define arg types for free() #
                SysMgr.libcObj.free.argtypes = [c_void_p]

            # strip llvm info #
            symbol = symbol.split(".llvm.")[0]

            # remove suffixes for rust legacy #
            symbol, isRust = ElfAnalyzer.demangleRustSymPre(symbol)

            # remove optimization suffixes #
            symbol = symbol.split(".isra.")[0]
            symbol = symbol.split(".part.")[0]
            symbol = symbol.split(".constprop.")[0]

            # check version #
            if "@" in symbol:
                symbol, version = symbol.split("@")
                version = "@%s" % version
            else:
                version = ""

            # init variables #
            funcp = SysMgr.demangleFunc
            status = c_int()
            mSymbol = c_char_p(UtilMgr.encodeStr(symbol))

            # call to demangle symbol #
            ret = funcp(mSymbol, 0, 0, pointer(status))
            retc = cast(ret, c_char_p)

            # check 1st return status #
            origStat = status.value
            if origStat == 0:
                try:
                    dmSymbol = str(retc.value.decode())
                except SystemExit:
                    sys.exit(0)
                except:
                    dmSymbol = str(retc.value)
            else:
                # free demangled string array #
                SysMgr.libcObj.free(ret)

                # reinit variables #
                status = c_int()
                mSymbol = c_char_p(UtilMgr.encodeStr(origSym))

                # call to demangle symbol #
                ret = funcp(mSymbol, None, None, pointer(status))

                retc = cast(ret, c_char_p)

                # check 2nd return status #
                if status.value == 0:
                    try:
                        dmSymbol = str(retc.value.decode())
                    except:
                        dmSymbol = str(retc.value)
                else:
                    isRust = False
                    dmSymbol = symbol
                    if origStat == -1:
                        SysMgr.printWarn(
                            (
                                "failed to allocate memory to "
                                "demangle symbol %s"
                            )
                            % origSym
                        )
                    elif origStat == -2:
                        SysMgr.printWarn(
                            (
                                "failed to demangle %s because of "
                                "invalid name"
                            )
                            % origSym
                        )
                    elif origStat == -3:
                        SysMgr.printWarn(
                            (
                                "failed to demangle %s because of "
                                "invalid args"
                            )
                            % origSym
                        )
                    else:
                        SysMgr.printWarn(
                            (
                                "failed to demangle %s because of "
                                "unknown status %d"
                            )
                            % (origSym, origStat)
                        )

            # free demangled string array #
            SysMgr.libcObj.free(ret)

            # remove args info #
            if not incArg:
                try:
                    dmSymbol = dmSymbol.split("(", 1)[0]
                except:
                    pass

            # demangle symbols for rust #
            if isRust:
                dmSymbol = ElfAnalyzer.demangleRustSym(dmSymbol)

            # demangle symbols for java #
            """
            TODO: implement demangleJavaSym()
            dmSymbol = ElfAnalyzer.demangleJavaSym(dmSymbol)
            """

            demangledSym = dmSymbol + version
            ElfAnalyzer.cachedDemangleTable[origSym] = demangledSym
            return demangledSym
        except SystemExit:
            sys.exit(0)
        except:
            err = SysMgr.getErrMsg()
            SysMgr.printWarn(
                (
                    "failed to demangle symbol %s because %s "
                    "so that disable demangle feature"
                )
                % (symbol, err),
                True,
            )
            SysMgr.demangleEnable = False
            return origSym

    @staticmethod
    def getFilterFlags(symbol):
        inc = start = end = False

        if not symbol:
            inc = start = end = True
        elif symbol[0] == "*" and symbol[-1] == "*":
            symbol = symbol.strip("*")
            inc = True
        elif symbol[0] == "*":
            symbol = symbol.strip("*")
            end = True
        elif symbol[-1] == "*":
            symbol = symbol.strip("*")
            start = True

        return symbol, inc, start, end

    @staticmethod
    def getSymOffset(symbol, binPath, objdumpPath=None, loadAddr=False):
        syms = []

        if not objdumpPath:
            offsets = None

            # get offset #
            try:
                binObj = ElfAnalyzer.getObject(binPath)
                if not binObj:
                    raise Exception("no binary")
                elif binObj.onlyFunc:
                    binObj = ElfAnalyzer.getObject(binPath, cache=False)

                symbol, inc, start, end = ElfAnalyzer.getFilterFlags(symbol)

                offsets = binObj.getOffsetBySymbol(
                    symbol, inc=inc, start=start, end=end, onlyFunc=False
                )
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn(
                    "failed to get offset for %s from %s" % (symbol, binPath),
                    reason=True,
                )
                return None

            if type(offsets) is str:
                offsets = [[symbol, offsets]]

            if type(offsets) is list:
                for item in offsets:
                    sym = item[0]
                    offset = long(item[1], 16)

                    # handle executable #
                    if loadAddr:
                        offset -= binObj.loadAddr

                    syms.append([offset, sym, binPath])

            return syms

        # get subprocess object #
        subprocess = SysMgr.getPkg("subprocess")

        args = [objdumpPath, "-C", "-F", "-d", binPath]

        SysMgr.printStat("start finding %s... [ STOP(Ctrl+c) ]" % (symbol))

        # start objdump process #
        try:
            proc = subprocess.Popen(
                args,
                stdout=subprocess.PIPE,
                stderr=subprocess.PIPE,
                bufsize=-1,
            )
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to execute %s to get address from binary" % objdumpPath
            )
            sys.exit(-1)

        while 1:
            try:
                # read a line from objdump process #
                line = proc.stdout.readline()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("failed to read output from objdump", True)

            # handle error #
            if not line:
                err = proc.stderr.read()
                if err:
                    try:
                        proc.terminate()
                    except:
                        pass

                    SysMgr.printErr(err[err.find(":") + 2 :])
                    sys.exit(-1)
                break

            # parse line to find offset of symbol #
            line = str(line)
            m = re.match(
                (
                    r"\s*(?P<addr>\S*)\s*\<(?P<symbol>.*)\>\s*\("
                    r"File Offset:\s*(?P<offset>\S*)\s*\)"
                ),
                line,
            )
            if not m:
                continue

            d = m.groupdict()
            if d["symbol"] == symbol:
                try:
                    proc.terminate()
                except:
                    pass
                return d["offset"]
            elif symbol in d["symbol"]:
                syms.append([d["symbol"], d["offset"]])

        # check similar list #
        if not syms:
            return None
        else:
            return syms

    @staticmethod
    def isRelocFile(path):
        if path in ElfAnalyzer.relocTypes:
            return ElfAnalyzer.relocTypes[path]

        try:
            cachedObject = ElfAnalyzer.getObject(path)
            if not cachedObject:
                raise Exception("no binary")

            etype = cachedObject.attr["elfHeader"]["type"]
            if etype == "Relocatable" or etype == "Shared-object":
                ElfAnalyzer.relocTypes[path] = True
                return True
            else:
                ElfAnalyzer.relocTypes[path] = False
                return False
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn(
                "failed to check relocatable format for '%s'" % path,
                reason=True,
            )
            return False

        # check file name #
        if (
            path.endswith(".so")
            or path.endswith(".ttf")
            or path.endswith(".pak")
        ):
            ElfAnalyzer.relocTypes[path] = True
            return True
        else:
            ElfAnalyzer.relocTypes[path] = False
            return False

    def mergeSymTable(self, force=False, onlyFunc=True, removeOrig=False):
        # check already merged #
        if not force and self.mergedSymTable:
            return

        # save func flag #
        self.onlyFunc = onlyFunc

        # merge symbol tables #
        tempSymTable = UtilMgr.deepcopy(self.attr["symTable"])
        tempSymTable.update(self.attr["dynsymTable"])
        tempSymTable.update(self.attr["dwarfTable"])
        self.mergedSymTable = tempSymTable

        # add section symbols #
        for name, item in self.attr["sectionHeader"].items():
            if item["addr"] == 0:
                continue

            name = "[%s]" % name
            addr = hex(item["addr"])

            if addr in tempSymTable:
                tempSymTable[name] = tempSymTable[addr]
            else:
                tempSymTable[name] = {
                    "value": item["addr"],
                    "size": item["size"],
                    "type": "SECTION",
                    "bind": "GLOBAL",
                    "vis": "DEFAULT",
                    "ndx": 0,
                }

        mainSym = "?"
        prevAddr = None
        prevSize = 0
        prevLen = 0
        curLen = 0

        # set merge flag #
        if "ALLSYM" in SysMgr.environList:
            mergeFlag = True
        else:
            mergeFlag = False

        # sort and convert table #
        for idx, item in sorted(
            tempSymTable.items(), key=lambda e: e[1]["value"], reverse=False
        ):

            # skip useless symbol #
            if item["size"] == 0:
                continue

            # skip symbols except for function #
            if onlyFunc and item["type"] != "FUNC":
                continue

            # update symbol length #
            prevLen = curLen
            curLen = idx.find("@")
            if curLen < 0:
                curLen = len(idx)

            # update representatives among symbols with the same address #
            if prevAddr == item["value"]:
                # merge all symbols #
                if mergeFlag:
                    mainSym += "/%s" % idx
                # ignore _SYMBOL #
                elif idx.startswith("_") and not mainSym.startswith("_"):
                    pass
                # choose the shortest symbol #
                elif (
                    ("@" in idx and not "@" in mainSym)
                    or (not idx.startswith("_") and mainSym.startswith("_"))
                    or (curLen < prevLen)
                ):
                    mainSym = idx
                continue

            # register symbol #
            if prevAddr:
                self.sortedAddrTable.append(prevAddr)
                self.sortedSymTable.append([mainSym, prevSize])

            # update previous symbol info #
            mainSym = idx
            prevAddr = item["value"]
            prevSize = item["size"]
            prevLen = sys.maxsize

        # register last symbol #
        if prevAddr:
            self.sortedAddrTable.append(prevAddr)
            self.sortedSymTable.append([mainSym, prevSize])

        # except dwarf table #
        if (
            "dwarf" in self.attr
            and "EXCEPTDWARF" in SysMgr.environList
            and UtilMgr.isValidStr(
                self.path, SysMgr.environList["EXCEPTDWARF"]
            )
        ):
            del self.attr["dwarf"]

        # remove useless symbols after merge #
        if removeOrig:
            self.attr["symTable"].clear()
            self.attr["dynsymTable"].clear()
            self.attr["dwarfTable"].clear()
            self.addrTable.clear()

    def getRangeBySymbol(self, symbol):
        # use unified symbol table #
        if symbol in self.mergedSymTable:
            val = self.mergedSymTable[symbol]
            return [val["value"], val["value"] + val["size"]]
        else:
            return None

        # use each symbol tables #
        if symbol in self.attr["symTable"]:
            val = self.attr["symTable"][symbol]
            return [val["value"], val["value"] + val["size"]]
        elif symbol in self.attr["dynsymTable"]:
            val = self.attr["dynsymTable"][symbol]
            return [val["value"], val["value"] + val["size"]]
        else:
            return None

    def getAnonRangeByOffset(self, offset):
        # check symbol table #
        if not self.sortedSymTable:
            self.mergeSymTable()

        try:
            if UtilMgr.isString(offset):
                try:
                    offset = long(offset, 16)
                except:
                    offset = long(offset)

            addrTable = self.sortedAddrTable
            symTable = self.sortedSymTable

            # get target index from address table #
            idx = UtilMgr.bisect_left(self.sortedAddrTable, offset) - 1
            if idx < 0:
                idx = 0

            if addrTable[idx] > offset:
                if idx > 0:
                    start = addrTable[idx - 1] + symTable[idx - 1][1] + 1
                    end = addrTable[idx] - 1
                else:
                    start = 0
                    end = addrTable[idx] - 1
            else:
                start = addrTable[idx] + symTable[idx][1] + 1
                end = addrTable[idx + 1] - 1

            return [start, end]
        except SystemExit:
            sys.exit(0)
        except:
            return [0, 0]

    def getSymbolByOffset(self, offset, onlyFunc=True):
        # check symbol table #
        if not self.sortedSymTable:
            self.mergeSymTable(onlyFunc=onlyFunc)

        try:
            if UtilMgr.isString(offset):
                try:
                    offset = long(offset, 16)
                except:
                    offset = long(offset)

            addrTable = self.sortedAddrTable
            symTable = self.sortedSymTable

            # get target index from address table #
            idx = UtilMgr.bisect_left(self.sortedAddrTable, offset) - 1
            if idx < 0:
                idx = 0

            while 1:
                if addrTable[idx] > offset:
                    return "??", "??"

                # set symbol scope to it's size #
                if True:
                    size = symTable[idx][1]
                    maxAddr = addrTable[idx] + size
                # set symbol scope to next one's start offset #
                else:
                    size = "??"
                    maxAddr = addrTable[idx + 1]

                if offset >= addrTable[idx] and offset <= maxAddr:
                    return symTable[idx][0], size

                idx += 1
        except SystemExit:
            sys.exit(0)
        except:
            return "??", "??"

    def getOffsetBySymbol(
        self, symbol, inc=False, start=False, end=False, onlyFunc=True
    ):

        # check symbol table #
        if not self.sortedSymTable:
            self.mergeSymTable(onlyFunc=onlyFunc)

        clist = []

        # get offset or symbol list #
        try:
            for idx, val in enumerate(self.sortedSymTable):
                target = val[0].split("@")[0]
                offset = hex(self.sortedAddrTable[idx]).rstrip("L")
                if (
                    (start and target.startswith(symbol))
                    or (end and target.endswith(symbol))
                    or (inc and symbol in target)
                ):
                    clist.append([val[0], offset])
                elif symbol == val[0] or symbol == target:
                    return offset
        except SystemExit:
            sys.exit(0)
        except:
            return None

        if not clist:
            return None
        else:
            return clist

    def getSectionInfo(self, fd, pos=0):
        fd.seek(pos)

        if self.is32Bit:
            return struct.unpack("IIIIIIIIII", fd.read(40))
        else:
            return struct.unpack("IIQQQQIIQQ", fd.read(64))

    def __del__(self):
        pass

    def getCFI(self, table, pos, size, prt=False):
        def _getBlockArgs(table, pos):
            size = struct.unpack("b", table[pos : pos + 1])[0]
            pos += 1

            args = []
            for _ in xrange(size):
                args.append(struct.unpack("B", table[pos : pos + 1])[0])
                pos += 1

            return args, pos

        # define shortcut variable for DWARF constants #
        DW = ElfAnalyzer.DW_INST
        DWM = ElfAnalyzer.DW_INST_MAP

        cfi = []

        while pos < size:
            args = []

            opcode = struct.unpack("B", table[pos : pos + 1])[0]
            pos += 1

            primary = opcode & DW["DW_PRIMARY_MASK"]
            primaryArg = opcode & DW["DW_PRIMARY_ARG_MASK"]

            if primary == DW["DW_CFA_advance_loc"]:
                inst = "DW_CFA_advance_loc"
                args = [primaryArg]
            elif primary == DW["DW_CFA_offset"]:
                data = table[pos : pos + 1024].decode("latin-1")
                arg, nsize = UtilMgr.decodeULEB128(data)
                pos += nsize

                inst = "DW_CFA_offset"
                args = [primaryArg, arg]
            elif primary == DW["DW_CFA_restore"]:
                inst = "DW_CFA_restore"
                args = [primaryArg]
            # primary == 0 and real opcode is extended
            elif opcode in (
                DW["DW_CFA_nop"],
                DW["DW_CFA_remember_state"],
                DW["DW_CFA_restore_state"],
            ):
                inst = DWM[opcode]
                args = []
            elif opcode == DW["DW_CFA_set_loc"]:
                if self.is32Bit:
                    word = 4
                    val = struct.unpack("I", table[pos : pos + word])[0]
                else:
                    word = 8
                    val = struct.unpack("Q", table[pos : pos + word])[0]

                inst = DWM[opcode]
                args = [val]
            elif opcode == DW["DW_CFA_advance_loc1"]:
                val = struct.unpack("B", table[pos : pos + 1])[0]
                pos += 1

                inst = DWM[opcode]
                args = [val]
            elif opcode == DW["DW_CFA_advance_loc2"]:
                val = struct.unpack("H", table[pos : pos + 2])[0]
                pos += 2

                inst = DWM[opcode]
                args = [val]
            elif opcode == DW["DW_CFA_advance_loc4"]:
                val = struct.unpack("I", table[pos : pos + 4])[0]
                pos += 4

                inst = DWM[opcode]
                args = [val]
            elif opcode in (
                DW["DW_CFA_offset_extended"],
                DW["DW_CFA_register"],
                DW["DW_CFA_def_cfa"],
                DW["DW_CFA_val_offset"],
            ):
                data = table[pos : pos + 1024].decode("latin-1")
                arg1, nsize = UtilMgr.decodeULEB128(data)
                pos += nsize
                data = table[pos : pos + 1024].decode("latin-1")
                arg2, nsize = UtilMgr.decodeULEB128(data)
                pos += nsize

                inst = DWM[opcode]
                args = [arg1, arg2]
            elif opcode in (
                DW["DW_CFA_restore_extended"],
                DW["DW_CFA_undefined"],
                DW["DW_CFA_same_value"],
                DW["DW_CFA_def_cfa_register"],
                DW["DW_CFA_def_cfa_offset"],
            ):
                inst = DWM[opcode]
                data = table[pos : pos + 1024].decode("latin-1")
                arg, nsize = UtilMgr.decodeULEB128(data)
                args = [arg]
                pos += nsize
            elif opcode == DW["DW_CFA_def_cfa_offset_sf"]:
                inst = DWM[opcode]
                data = table[pos : pos + 1024].decode("latin-1")
                arg, nsize = UtilMgr.decodeSLEB128(data)
                args = [arg]
                pos += nsize
            elif opcode == DW["DW_CFA_def_cfa_expression"]:
                inst = DWM[opcode]
                data = table[pos : pos + 1024].decode("latin-1")
                args, pos = _getBlockArgs(table, pos)
            elif opcode in (
                DW["DW_CFA_expression"],
                DW["DW_CFA_val_expression"],
            ):
                inst = DWM[opcode]
                data = table[pos : pos + 1024].decode("latin-1")
                arg1, nsize = UtilMgr.decodeULEB128(data)
                pos += nsize
                data = table[pos : pos + 1024].decode("latin-1")
                arg2, pos = _getBlockArgs(table, pos)
                args = [arg1, arg2]
            elif opcode in (
                DW["DW_CFA_offset_extended_sf"],
                DW["DW_CFA_def_cfa_sf"],
                DW["DW_CFA_val_offset_sf"],
            ):
                data = table[pos : pos + 1024].decode("latin-1")
                arg1, nsize = UtilMgr.decodeULEB128(data)
                pos += nsize
                data = table[pos : pos + 1024].decode("latin-1")
                arg2, nsize = UtilMgr.decodeSLEB128(data)
                pos += nsize

                inst = DWM[opcode]
                args = [arg1, arg2]
            elif opcode == DW["DW_CFA_GNU_args_size"]:
                inst = DWM[opcode]
                data = table[pos : pos + 1024].decode("latin-1")
                arg, nsize = UtilMgr.decodeULEB128(data)
                pos += nsize
                args = [arg]
            else:
                inst = None
                SysMgr.printErr(
                    "failed to recognize CFI opcode %s for %s"
                    % (hex(opcode), self.path)
                )
                break

            cfi.append([inst, opcode, args])

        return cfi

    def getString(self, strtable, start=0, retlen=False):
        if not strtable:
            return ""

        idx = start
        end = self.fileSize - start

        while 1:
            if strtable[idx : idx + 1] == b"\x00":
                break
            elif idx >= end:
                break

            idx += 1

        # pick symbol string #
        if start == idx:
            symbol = ""
        else:
            try:
                symbol = strtable[start:idx].decode()
            except SystemExit:
                sys.exit(0)
            except:
                symbol = strtable[start:idx]

        # return #
        if retlen:
            return symbol, idx - start
        else:
            return symbol

    def isInSection(self, section, addr):
        try:
            attr = self.attr["sectionHeader"][section]
            if attr["addr"] <= addr <= attr["addr"] + attr["size"]:
                return True
            else:
                return False
        except:
            SysMgr.printWarn("failed to check %s area" % section, reason=True)
            return None

    def isInPlt(self, addr):
        try:
            return self.isInSection(".plt", addr)
        except:
            return None

    def getSectionHeader(self, name):
        try:
            return self.attr["sectionHeader"][name]
        except:
            return None

    def __str__(self):
        self.__init__(self.path, debug=True, printer=True)
        return "\n".join(self.logList)

    def __init__(
        self,
        path=None,
        debug=False,
        onlyHeader=False,
        fd=None,
        size=sys.maxsize,
        incArg=False,
        printer=False,
        origPath=None,
    ):
        def _printer(item):
            if not hasattr(self, "logList"):
                self.logList = []
            self.logList.append(item)

        # set printer #
        if printer:
            printer = _printer
        else:
            printer = SysMgr.printPipe

        # structures #
        """
        #define EI_NIDENT 16

        /* Type for a 16-bit quantity.  */
        typedef uint16_t Elf32_Half;
        typedef uint16_t Elf64_Half;

        /* Types for signed and unsigned 32-bit quantities.  */
        typedef uint32_t Elf32_Word;
        typedef int32_t  Elf32_Sword;
        typedef uint32_t Elf64_Word;
        typedef int32_t  Elf64_Sword;

        /* Types for signed and unsigned 64-bit quantities.  */
        typedef uint64_t Elf32_Xword;
        typedef int64_t  Elf32_Sxword;
        typedef uint64_t Elf64_Xword;
        typedef int64_t  Elf64_Sxword;

        /* Type of addresses.  */
        typedef uint32_t Elf32_Addr;
        typedef uint64_t Elf64_Addr;

        /* Type of file offsets.  */
        typedef uint32_t Elf32_Off;
        typedef uint64_t Elf64_Off;

        /* Type for section indices, which are 16-bit quantities.  */
        typedef uint16_t Elf32_Section;
        typedef uint16_t Elf64_Section;

        /* Type for version symbol information.  */
        typedef Elf32_Half Elf32_Versym;
        typedef Elf64_Half Elf64_Versym;

        typedef struct
        {
          unsigned char e_ident[EI_NIDENT];     /* Magic number and other info */
          Elf32_Half    e_type;                 /* Object file type */
          Elf32_Half    e_machine;              /* Architecture */
          Elf32_Word    e_version;              /* Object file version */
          Elf32_Addr    e_entry;                /* Entry point virtual address */
          Elf32_Off     e_phoff;                /* Program header table file offset */
          Elf32_Off     e_shoff;                /* Section header table file offset */
          Elf32_Word    e_flags;                /* Processor-specific flags */
          Elf32_Half    e_ehsize;               /* ELF header size in bytes */
          Elf32_Half    e_phentsize;            /* Program header table entry size */
          Elf32_Half    e_phnum;                /* Program header table entry count */
          Elf32_Half    e_shentsize;            /* Section header table entry size */
          Elf32_Half    e_shnum;                /* Section header table entry count */
          Elf32_Half    e_shstrndx;             /* Section header string table index */
        } Elf32_Ehdr;

        typedef struct
        {
          unsigned char e_ident[EI_NIDENT];     /* Magic number and other info */
          Elf64_Half    e_type;                 /* Object file type */
          Elf64_Half    e_machine;              /* Architecture */
          Elf64_Word    e_version;              /* Object file version */
          Elf64_Addr    e_entry;                /* Entry point virtual address */
          Elf64_Off     e_phoff;                /* Program header table file offset */
          Elf64_Off     e_shoff;                /* Section header table file offset */
          Elf64_Word    e_flags;                /* Processor-specific flags */
          Elf64_Half    e_ehsize;               /* ELF header size in bytes */
          Elf64_Half    e_phentsize;            /* Program header table entry size */
          Elf64_Half    e_phnum;                /* Program header table entry count */
          Elf64_Half    e_shentsize;            /* Section header table entry size */
          Elf64_Half    e_shnum;                /* Section header table entry count */
          Elf64_Half    e_shstrndx;             /* Section header string table index */
        } Elf64_Ehdr;

        typedef struct
        {
          Elf32_Word    sh_name;                /* Section name (string tbl index) */
          Elf32_Word    sh_type;                /* Section type */
          Elf32_Word    sh_flags;               /* Section flags */
          Elf32_Addr    sh_addr;                /* Section virtual addr at execution */
          Elf32_Off     sh_offset;              /* Section file offset */
          Elf32_Word    sh_size;                /* Section size in bytes */
          Elf32_Word    sh_link;                /* Link to another section */
          Elf32_Word    sh_info;                /* Additional section information */
          Elf32_Word    sh_addralign;           /* Section alignment */
          Elf32_Word    sh_entsize;             /* Entry size if section holds table */
        } Elf32_Shdr;

        typedef struct
        {
          Elf64_Word    sh_name;                /* Section name (string tbl index) */
          Elf64_Word    sh_type;                /* Section type */
          Elf64_Xword   sh_flags;               /* Section flags */
          Elf64_Addr    sh_addr;                /* Section virtual addr at execution */
          Elf64_Off     sh_offset;              /* Section file offset */
          Elf64_Xword   sh_size;                /* Section size in bytes */
          Elf64_Word    sh_link;                /* Link to another section */
          Elf64_Word    sh_info;                /* Additional section information */
          Elf64_Xword   sh_addralign;           /* Section alignment */
          Elf64_Xword   sh_entsize;             /* Entry size if section holds table */
        } Elf64_Shdr;

        typedef struct
        {
          Elf32_Word    p_type;                 /* Segment type */
          Elf32_Off     p_offset;               /* Segment file offset */
          Elf32_Addr    p_vaddr;                /* Segment virtual address */
          Elf32_Addr    p_paddr;                /* Segment physical address */
          Elf32_Word    p_filesz;               /* Segment size in file */
          Elf32_Word    p_memsz;                /* Segment size in memory */
          Elf32_Word    p_flags;                /* Segment flags */
          Elf32_Word    p_align;                /* Segment alignment */
        } Elf32_Phdr;

        typedef struct
        {
          Elf64_Word    p_type;                 /* Segment type */
          Elf64_Word    p_flags;                /* Segment flags */
          Elf64_Off     p_offset;               /* Segment file offset */
          Elf64_Addr    p_vaddr;                /* Segment virtual address */
          Elf64_Addr    p_paddr;                /* Segment physical address */
          Elf64_Xword   p_filesz;               /* Segment size in file */
          Elf64_Xword   p_memsz;                /* Segment size in memory */
          Elf64_Xword   p_align;                /* Segment alignment */
        } Elf64_Phdr;

        typedef struct {
                Elf32_Sword d_tag;
                union {
                        Elf32_Word      d_val;
                        Elf32_Addr      d_ptr;
                        Elf32_Off       d_off;
                } d_un;
        } Elf32_Dyn;

        typedef struct {
                Elf64_Xword d_tag;
                union {
                        Elf64_Xword     d_val;
                        Elf64_Addr      d_ptr;
                } d_un;
        } Elf64_Dyn;

        typedef struct
        {
          Elf32_Word    st_name;                /* Symbol name (string tbl index) */
          Elf32_Addr    st_value;               /* Symbol value */
          Elf32_Word    st_size;                /* Symbol size */
          unsigned char st_info;                /* Symbol type and binding */
          unsigned char st_other;               /* Symbol visibility */
          Elf32_Section st_shndx;               /* Section index */
        } Elf32_Sym;

        typedef struct
        {
          Elf64_Word    st_name;                /* Symbol name (string tbl index) */
          unsigned char st_info;                /* Symbol type and binding */
          unsigned char st_other;               /* Symbol visibility */
          Elf64_Section st_shndx;               /* Section index */
          Elf64_Addr    st_value;               /* Symbol value */
          Elf64_Xword   st_size;                /* Symbol size */
        } Elf64_Sym;

        typedef struct
        {
          Elf32_Addr    r_offset;               /* Address */
          Elf32_Word    r_info;                 /* Relocation type and symbol index */
        } Elf32_Rel;

        /* I have seen two different definitions of the Elf64_Rel and
           Elf64_Rela structures, so we'll leave them out until Novell (or
           whoever) gets their act together.  */
        /* The following, at least, is used on Sparc v9, MIPS, and Alpha.  */

        typedef struct
        {
          Elf64_Addr    r_offset;               /* Address */
          Elf64_Xword   r_info;                 /* Relocation type and symbol index */
        } Elf64_Rel;

        /* Relocation table entry with addend (in section of type SHT_RELA).  */

        typedef struct
        {
          Elf32_Addr    r_offset;               /* Address */
          Elf32_Word    r_info;                 /* Relocation type and symbol index */
          Elf32_Sword   r_addend;               /* Addend */
        } Elf32_Rela;

        typedef struct
        {
          Elf64_Addr    r_offset;               /* Address */
          Elf64_Xword   r_info;                 /* Relocation type and symbol index */
          Elf64_Sxword  r_addend;               /* Addend */
        } Elf64_Rela;

        /* Version definition sections.  */

        typedef struct
        {
          Elf32_Half    vd_version;             /* Version revision */
          Elf32_Half    vd_flags;               /* Version information */
          Elf32_Half    vd_ndx;                 /* Version Index */
          Elf32_Half    vd_cnt;                 /* Number of associated aux entries */
          Elf32_Word    vd_hash;                /* Version name hash value */
          Elf32_Word    vd_aux;                 /* Offset in bytes to verdaux array */
          Elf32_Word    vd_next;                /* Offset in bytes to next verdef
                                                   entry */
        } Elf32_Verdef;

        typedef struct
        {
          Elf64_Half    vd_version;             /* Version revision */
          Elf64_Half    vd_flags;               /* Version information */
          Elf64_Half    vd_ndx;                 /* Version Index */
          Elf64_Half    vd_cnt;                 /* Number of associated aux entries */
          Elf64_Word    vd_hash;                /* Version name hash value */
          Elf64_Word    vd_aux;                 /* Offset in bytes to verdaux array */
          Elf64_Word    vd_next;                /* Offset in bytes to next verdef
                                                   entry */
        } Elf64_Verdef;

        /* Auxialiary version information.  */

        typedef struct
        {
          Elf32_Word    vda_name;               /* Version or dependency names */
          Elf32_Word    vda_next;               /* Offset in bytes to next verdaux
                                                   entry */
        } Elf32_Verdaux;

        typedef struct
        {
          Elf64_Word    vda_name;               /* Version or dependency names */
          Elf64_Word    vda_next;               /* Offset in bytes to next verdaux
                                                   entry */
        } Elf64_Verdaux;


        /* Version dependency section.  */

        typedef struct
        {
          Elf32_Half    vn_version;             /* Version of structure */
          Elf32_Half    vn_cnt;                 /* Number of associated aux entries */
          Elf32_Word    vn_file;                /* Offset of filename for this
                                                   dependency */
          Elf32_Word    vn_aux;                 /* Offset in bytes to vernaux array */
          Elf32_Word    vn_next;                /* Offset in bytes to next verneed
                                                   entry */
        } Elf32_Verneed;

        typedef struct
        {
          Elf64_Half    vn_version;             /* Version of structure */
          Elf64_Half    vn_cnt;                 /* Number of associated aux entries */
          Elf64_Word    vn_file;                /* Offset of filename for this
                                                   dependency */
          Elf64_Word    vn_aux;                 /* Offset in bytes to vernaux array */
          Elf64_Word    vn_next;                /* Offset in bytes to next verneed
                               entry */
        } Elf64_Verneed;

        /* Auxiliary needed version information.  */

        typedef struct
        {
          Elf32_Word    vna_hash;               /* Hash value of dependency name */
          Elf32_Half    vna_flags;              /* Dependency specific information */
          Elf32_Half    vna_other;              /* Unused */
          Elf32_Word    vna_name;               /* Dependency name string offset */
          Elf32_Word    vna_next;               /* Offset in bytes to next vernaux
                                                   entry */
        } Elf32_Vernaux;

        typedef struct
        {
          Elf64_Word    vna_hash;               /* Hash value of dependency name */
          Elf64_Half    vna_flags;              /* Dependency specific information */
          Elf64_Half    vna_other;              /* Unused */
          Elf64_Word    vna_name;               /* Dependency name string offset */
          Elf64_Word    vna_next;               /* Offset in bytes to next vernaux
                                                   entry */
        } Elf64_Vernaux;

        /* This holds instructions for unwinding frame at a particular PC location
           described by an FDE.  */
        typedef struct
        {
          /* This frame description covers PC values in [start, end).  */
          Dwarf_Addr start;
          Dwarf_Addr end;

          Dwarf_CFI *cache;

          /* Previous state saved by DW_CFA_remember_state, or .cie->initial_state,
             or NULL in an initial_state pseudo-frame.  */
          Dwarf_Frame *prev;

          /* The FDE that generated this frame state.  This points to its CIE,
             which has the return_address_register and signal_frame flag.  */
          struct dwarf_fde *fde;

          /* The CFA is unknown, is R+N, or is computed by a DWARF expression.
             A bogon in the CFI can indicate an invalid/incalculable rule.
             We store that as cfa_invalid rather than barfing when processing it,
             so callers can ignore the bogon unless they really need that CFA.  */
          enum { cfa_undefined, cfa_offset, cfa_expr, cfa_invalid } cfa_rule;
          union
          {
            Dwarf_Op offset;
            Dwarf_Block expr;
          } cfa_data;
          /* We store an offset rule as a DW_OP_bregx operation.  */
        #define cfa_val_reg cfa_data.offset.number
        #define cfa_val_offset  cfa_data.offset.number2

          size_t nregs;
          struct dwarf_frame_register regs[];
        } Dwarf_Frame;

        typedef GElf_Off Dwarf_Off;
        typedef Elf64_Off GElf_Off;

        typedef Elf64_Xword GElf_Xword;
        typedef uint64_t Elf64_Xword;

        typedef Elf64_Sxword GElf_Sxword;
        typedef int64_t  Elf64_Sxword;

        /* This describes one Common Information Entry read from a CFI section.
           Pointers here point into the DATA->d_buf block passed to dwarf_next_cfi.  */
        typedef struct
        {
          Dwarf_Off CIE_id;  /* Always DW_CIE_ID_64 in Dwarf_CIE structures.  */

          /* Instruction stream describing initial state used by FDEs.  If
             we did not understand the whole augmentation string and it did
             not use 'z', then there might be more augmentation data here
             (and in FDEs) before the actual instructions.  */
          const uint8_t *initial_instructions;
          const uint8_t *initial_instructions_end;

          Dwarf_Word code_alignment_factor;
          Dwarf_Sword data_alignment_factor;
          Dwarf_Word return_address_register;

          const char *augmentation; /* Augmentation string.  */

          /* Augmentation data, might be NULL.  The size is correct only if
             we understood the augmentation string sufficiently.  */
          const uint8_t *augmentation_data;
          size_t augmentation_data_size;
          size_t fde_augmentation_data_size;
        } Dwarf_CIE;

        /* This describes one Frame Description Entry read from a CFI section.
           Pointers here point into the DATA->d_buf block passed to dwarf_next_cfi.  */
        typedef struct
        {
          /* Section offset of CIE this FDE refers to.  This will never be
             DW_CIE_ID_64 in an FDE.  If this value is DW_CIE_ID_64, this is
             actually a Dwarf_CIE structure.  */
          Dwarf_Off CIE_pointer;

          /* We can't really decode anything further without looking up the CIE
             and checking its augmentation string.  Here follows the encoded
             initial_location and address_range, then any augmentation data,
             then the instruction stream.  This FDE describes PC locations in
             the byte range [initial_location, initial_location+address_range).
             When the CIE augmentation string uses 'z', the augmentation data is
             a DW_FORM_block (self-sized).  Otherwise, when we understand the
             augmentation string completely, fde_augmentation_data_size gives
             the number of bytes of augmentation data before the instructions.  */
          const uint8_t *start;
          const uint8_t *end;
        } Dwarf_FDE;
        """

        # define attributes #
        self.addrTable = {}
        self.ret = True
        self.path = path
        self.attr = {}
        self.is32Bit = True
        self.saved = False
        self.sortedSymTable = []
        self.sortedAddrTable = []
        self.mergedSymTable = {}
        self.cfaTableTitle = ""
        self.fileSize = size
        self.onlyFunc = False
        self.loadAddr = 0

        if fd is None:
            if "NODEBUG" in SysMgr.environList:
                debugPath = None
            else:
                # check debug file #
                dirname, filename = UtilMgr.getPath(path)
                # .debug #
                debugPath = "%s/.debug/%s" % (dirname, filename)
                if not os.path.isfile(debugPath):
                    # /usr/lib/debug/usr #
                    debugPath = "/usr/lib/debug%s" % path
                    if not os.path.isfile(debugPath):
                        try:
                            # /usr/lib/debug/lib #
                            newPos = path.find("/", 2)
                            debugPath = "/usr/lib/debug%s" % path[newPos:]
                            if not os.path.isfile(debugPath):
                                debugPath = None
                        except SystemExit:
                            sys.exit(0)
                        except:
                            pass

            # merge a debug file #
            if debugPath:
                SysMgr.printInfo("merge %s's debug symbols" % debugPath)

                dobj = ElfAnalyzer(debugPath, debug=debug, origPath=self.path)
                if dobj:
                    dobj.mergeSymTable()
                    self.addrTable.update(dobj.addrTable)
                    dobj.addrTable.clear()
                self.attr["symTable"] = UtilMgr.deepcopy(dobj.attr["symTable"])
                self.attr["dynsymTable"] = UtilMgr.deepcopy(
                    dobj.attr["dynsymTable"]
                )
                if "dwarf" in dobj.attr:
                    self.attr["dwarf"] = UtilMgr.deepcopy(dobj.attr["dwarf"])
                del dobj

            # check file #
            if not os.path.exists(path):
                raise Exception("no file")

            # open file #
            try:
                fd = open(path, "rb")
            except:
                if debug:
                    SysMgr.printOpenErr(path)
                else:
                    SysMgr.printOpenWarn(path)

                err = SysMgr.getErrMsg()
                raise Exception(err)

            # get file size #
            self.fileSize = os.stat(path).st_size

        # update absolute path #
        try:
            abspath = os.path.realpath(fd.name)
            if os.path.exists(abspath):
                self.path = abspath
        except:
            pass

        # define default file type #
        e_type = e_class = "dummpy"
        EI_NIDENT = 16

        # define err string #
        errStr = "failed to recognize '%s' as an ELF object because %s"

        # check size #
        if self.fileSize < EI_NIDENT:
            size = UtilMgr.convSize2Unit(self.fileSize)
            SysMgr.printWarn(
                errStr % (path, "it's size is just %s" % size), debug
            )
            self.ret = None
            return None

        # parse ELF header #
        ei_ident = struct.unpack("16B", fd.read(EI_NIDENT))
        (
            ei_mag0,
            ei_mag1,
            ei_mag2,
            ei_mag3,
            ei_class,
            ei_data,
            ei_version,
            ei_pad,
        ) = ei_ident[:8]
        ei_nident = ei_ident[8:]

        # check magic number #
        if (
            ei_mag0 != 0x7F
            and ei_mag1 != ord("E")
            and ei_mag2 != ord("L")
            and ei_mag3 != ord("F")
        ):
            SysMgr.printWarn(
                errStr % (path, "it is not the ELF object"), debug
            )
            self.ret = None
            return None

        # check 32/64-bit type #
        if ei_class == 1:
            self.is32Bit = True
            e_class = "32-bit objects"
            wordSize = 4
        elif ei_class == 2:
            self.is32Bit = False
            e_class = "64-bit objects"
            wordSize = 8
        else:
            SysMgr.printWarn(errStr % (path, "it is invalid class"), debug)
            self.ret = None
            return None

        # check data encoding (endian) #
        if ei_data == 1:
            e_data = "ELFDATA2LSB"
        elif ei_data == 2:
            e_data = "ELFDATA2MSB"
        else:
            SysMgr.printWarn(
                errStr % (path, "it is invalid for data encoding"), debug
            )
            self.ret = None
            return None

        # check file type #
        ei_type = struct.unpack("H", fd.read(2))[0]
        try:
            e_type = ElfAnalyzer.EI_TYPE[ei_type]
        except:
            e_type = "N/A"

        # check machine type #
        ei_machine = struct.unpack("H", fd.read(2))[0]
        if ei_machine in ElfAnalyzer.EI_MACHINE_TYPE:
            e_machine = ElfAnalyzer.EI_MACHINE_TYPE[ei_machine]
        else:
            e_machine = "Unknow machine"

        # update Program Table on arch #
        if e_machine.startswith("ARM"):
            ElfAnalyzer.PT_TYPE.update(
                {0x70000000: "ARCHEXT", 0x70000001: "EXIDX"}
            )

            if e_machine.startswith("ARM 32"):
                ElfAnalyzer.SH_TYPE.update(
                    {
                        0x70000001: "EXIDX",
                        0x70000002: "PREEMPTMAP",
                        0x70000003: "ATTRIBUTES",
                    }
                )

                ElfAnalyzer.RELOC_TYPE = ElfAnalyzer.RELOC_TYPE_ARM
                regList = ConfigMgr.REGS_ARM
            else:
                ElfAnalyzer.RELOC_TYPE = ElfAnalyzer.RELOC_TYPE_AARCH64
                regList = ConfigMgr.REGS_AARCH64
        elif e_machine.startswith("AMD x86-64") or e_machine.startswith(
            "Intel IA-64"
        ):
            ElfAnalyzer.PT_TYPE.update(
                {
                    0x60000012: "HP_OPT_ANOT",
                    0x60000013: "HP_HSL_ANOT",
                    0x60000014: "HP_STACK",
                    0x70000000: "ARCHEXT",
                    0x70000001: "UNWIND",
                }
            )

            ElfAnalyzer.SH_TYPE.update(
                {0x70000000: "EXT", 0x70000001: "UNWIND"}
            )

            ElfAnalyzer.RELOC_TYPE = ElfAnalyzer.RELOC_TYPE_x64
            regList = ConfigMgr.REGS_X64
        elif e_machine.startswith("Intel "):
            ElfAnalyzer.RELOC_TYPE = ElfAnalyzer.RELOC_TYPE_x86
            regList = ConfigMgr.REGS_X86

        # check version #
        ei_version = struct.unpack("I", fd.read(4))[0]
        if ei_version == 0:
            e_version = "illegal version"
        else:
            e_version = str(ei_version)

        # parse 32-bit ELF header #
        if self.is32Bit:
            (
                e_entry,
                e_phoff,
                e_shoff,
                e_flags,
                e_ehsize,
                e_phentsize,
                e_phnum,
                e_shentsize,
                e_shnum,
                e_shstrndx,
            ) = struct.unpack("IIIIHHHHHH", fd.read(28))
        # parse 64-bit ELF header #
        else:
            (
                e_entry,
                e_phoff,
                e_shoff,
                e_flags,
                e_ehsize,
                e_phentsize,
                e_phnum,
                e_shentsize,
                e_shnum,
                e_shstrndx,
            ) = struct.unpack("QQQIHHHHHH", fd.read(40))

        # save header info #
        self.attr.setdefault("elfHeader", {})
        self.attr["elfHeader"][
            "magic"
        ] = "%02x %02x %02x %02x %02x %02x %02x %02x" % (
            ei_mag0,
            ei_mag1,
            ei_mag2,
            ei_mag3,
            ei_class,
            ei_data,
            ei_version,
            ei_pad,
        )
        self.attr["elfHeader"]["class"] = e_class
        self.attr["elfHeader"]["data"] = e_data
        self.attr["elfHeader"]["type"] = e_type
        self.attr["elfHeader"]["machine"] = e_machine
        self.attr["elfHeader"]["version"] = e_version
        self.attr["elfHeader"]["entry"] = e_entry
        self.attr["elfHeader"]["phoff"] = e_phoff
        self.attr["elfHeader"]["shoff"] = e_shoff
        self.attr["elfHeader"]["flags"] = e_flags
        self.attr["elfHeader"]["ehsize"] = e_ehsize
        self.attr["elfHeader"]["phentsize"] = e_phentsize
        self.attr["elfHeader"]["shnum"] = e_shnum
        self.attr["elfHeader"]["shentsize"] = e_shentsize
        self.attr["elfHeader"]["shnum"] = e_shnum
        self.attr["elfHeader"]["shstrndx"] = e_shstrndx

        # check onlyHeader flag #
        if onlyHeader:
            return None

        # print header info #
        if debug:
            printer(
                """\

[ELF Header]
%s
Path: %s
Magic: %s
Class: %s
Data: %s
Type: %s
Machine: %s
Version: %s
Entry point address: 0x%x
Start of program headers: %d (bytes into file)
Start of section headers: %d (bytes into file)
Flags: 0x%02x
Size of this header: %d (bytes)
Size of program header: %d (bytes)
Number of program headers: %d
Size of section headers: %d (bytes)
Number of section headers: %d
Section header string table index: %d
%s
            """
                % (
                    twoLine,
                    self.path,
                    self.attr["elfHeader"]["magic"],
                    e_class,
                    e_data,
                    e_type,
                    e_machine,
                    e_version,
                    e_entry,
                    e_phoff,
                    e_shoff,
                    e_flags,
                    e_ehsize,
                    e_phentsize,
                    e_shnum,
                    e_shentsize,
                    e_shnum,
                    e_shstrndx,
                    twoLine,
                )
            )

        # parse string section #
        str_section = ""
        if e_shstrndx > 0:
            (
                sh_name,
                sh_type,
                sh_flags,
                sh_addr,
                sh_offset,
                sh_size,
                sh_link,
                sh_info,
                sh_addralign,
                sh_entsize,
            ) = self.getSectionInfo(fd, e_shoff + e_shentsize * e_shstrndx)
            fd.seek(sh_offset)
            str_section = fd.read(sh_size)

        # define program info #
        self.attr["progHeader"] = []
        e_notelist = {}

        # print program header title #
        if debug:
            printer(
                (
                    "[Program Headers]\n%s\n"
                    "%16s %10s %16s %16s %12s %12s %10s\n%s"
                )
                % (
                    twoLine,
                    "Type",
                    "Offset",
                    "VirtAddr",
                    "PhysAddr",
                    "FileSize",
                    "MemSize",
                    "Flags",
                    twoLine,
                )
            )

        # parse program sections #
        e_shinterpndx = -1
        for i in xrange(e_phnum):
            fd.seek(e_phoff + e_phentsize * i)

            # 32-bit #
            if self.is32Bit:
                (
                    p_type,
                    p_offset,
                    p_vaddr,
                    p_paddr,
                    p_filesz,
                    p_memsz,
                    p_flags,
                    p_align,
                ) = struct.unpack("IIIIIIII", fd.read(32))
            # 64-bit #
            else:
                (
                    p_type,
                    p_flags,
                    p_offset,
                    p_vaddr,
                    p_paddr,
                    p_filesz,
                    p_memsz,
                    p_align,
                ) = struct.unpack("IIQQQQQQ", fd.read(56))

            # INTERP #
            if p_type == 3:
                e_shinterpndx = i

            # get flags #
            if p_flags in ElfAnalyzer.PT_FLAGS:
                flags = ElfAnalyzer.PT_FLAGS[p_flags]
            else:
                flags = ""

            # convert type #
            if p_type in ElfAnalyzer.PT_TYPE:
                typeval = ElfAnalyzer.PT_TYPE[p_type]
            else:
                typeval = p_type

            # save program info #
            self.attr["progHeader"].append(
                [typeval, p_offset, p_vaddr, p_paddr, p_filesz, p_memsz, flags]
            )

            # convert type for print #
            if p_type in ElfAnalyzer.PT_TYPE:
                typestr = ElfAnalyzer.PT_TYPE[p_type]
            elif (
                p_type >= ElfAnalyzer.PT_TYPE["LOOS"]
                and p_type <= ElfAnalyzer.PT_TYPE["HIOS"]
            ):
                typestr = "LOOS+0x%lx" % (p_type - ElfAnalyzer.PT_TYPE["LOOS"])
            else:
                typestr = "<unknown>"

            # save load address #
            if typestr == "LOAD" and flags == "RE":
                self.loadAddr = p_vaddr
            elif typestr == "NOTE":
                e_notelist.setdefault(p_offset, p_filesz)

            if not debug:
                continue

            # print program header #
            printer(
                "%16s 0x%08x 0x%014x 0x%014x 0x%010x 0x%010x %010s"
                % (
                    typestr,
                    p_offset,
                    p_vaddr,
                    p_paddr,
                    p_filesz,
                    p_memsz,
                    flags,
                )
            )

        if debug:
            printer(oneLine)

        if e_shinterpndx >= 0:
            fd.seek(e_phoff + e_phentsize * e_shinterpndx)

            # 32-bit #
            if self.is32Bit:
                (
                    p_type,
                    p_offset,
                    p_vaddr,
                    p_paddr,
                    p_filesz,
                    p_memsz,
                    p_flags,
                    p_align,
                ) = struct.unpack("IIIIIIII", fd.read(32))
            # 64-bit #
            else:
                (
                    p_type,
                    p_flags,
                    p_offset,
                    p_vaddr,
                    p_paddr,
                    p_filesz,
                    p_memsz,
                    p_align,
                ) = struct.unpack("IIQQQQQQ", fd.read(56))

            fd.seek(p_offset)
            interp = fd.read(p_filesz)

        # initialize indexes #
        e_shsymndx = -1
        e_shstrndx = -1
        e_shdynsym = -1
        e_shdynstr = -1
        e_shdynamic = -1
        e_shversym = -1
        e_shverneed = -1
        e_shverdef = -1
        e_shrellist = []
        e_shrelalist = []
        e_shnotelist = {}
        e_shehframe = -1
        e_shdbgframe = -1
        e_shdbginfo = -1
        e_shdbgstr = -1
        e_shdbglinestr = -1
        e_shdbgline = -1
        e_shdbgabbrev = -1
        e_shehframehdr = -1
        e_sharmidx = -1
        e_shframe = -1

        # define section info #
        self.attr.setdefault("sectionHeader", {})

        # print section header title #
        if debug and e_shnum > 0:
            printer(
                (
                    "\n[Section Headers]\n%s\n"
                    "[NR] %50s%15s%12s%12s%13s(%5s)%8s%5s%5s%7s%6s\n%s"
                )
                % (
                    twoLine,
                    "Name",
                    "Type",
                    "Address",
                    "Offset",
                    "Size",
                    "%",
                    "EntSize",
                    "Flag",
                    "Link",
                    "Info",
                    "Align",
                    twoLine,
                )
            )

        # parse section headers #
        for i in xrange(e_shnum):
            (
                sh_name,
                sh_type,
                sh_flags,
                sh_addr,
                sh_offset,
                sh_size,
                sh_link,
                sh_info,
                sh_addralign,
                sh_entsize,
            ) = self.getSectionInfo(fd, e_shoff + e_shentsize * i)

            # check permission #
            f = ""
            if sh_flags & ElfAnalyzer.SHF_WRITE:
                f = "%sW" % f
            if sh_flags & ElfAnalyzer.SHF_ALLOC:
                f = "%sA" % f
            if sh_flags & ElfAnalyzer.SHF_EXECINSTR:
                f = "%sX" % f
            if sh_flags & ElfAnalyzer.SHF_MASKPROC:
                f = "%sM" % f

            # get symbol string #
            symbol = self.getString(str_section, sh_name)

            stype = (
                ElfAnalyzer.SH_TYPE[sh_type]
                if sh_type in ElfAnalyzer.SH_TYPE
                else sh_type
            )

            self.attr["sectionHeader"][symbol] = {
                "type": stype,
                "addr": sh_addr,
                "offset": sh_offset,
                "size": sh_size,
                "entSize": sh_entsize,
                "flag": f,
                "link": sh_link,
                "info": sh_info,
                "align": sh_addralign,
            }

            # print section header #
            if debug:
                try:
                    size_per = sh_size / float(self.fileSize) * 100
                except:
                    size_per = 0

                size_str = "%s(%4.1f%%)" % (UtilMgr.convNum(sh_size), size_per)

                printer(
                    "[%02d] %50s%15s%12s%12s%20s%8s%5s%5s%7s%6s"
                    % (
                        i,
                        symbol,
                        ElfAnalyzer.SH_TYPE[sh_type]
                        if sh_type in ElfAnalyzer.SH_TYPE
                        else hex(sh_type),
                        "0x%x" % sh_addr,
                        "0x%x" % sh_offset,
                        size_str,
                        sh_entsize,
                        f,
                        sh_link,
                        sh_info,
                        sh_addralign,
                    )
                )

            # get header index #
            if symbol == ".symtab":
                e_shsymndx = i
            elif symbol == ".strtab":
                e_shstrndx = i
            elif symbol == ".dynsym":
                e_shdynsym = i
            elif symbol == ".dynstr":
                e_shdynstr = i
            elif symbol == ".dynamic":
                e_shdynamic = i
            elif symbol == ".eh_frame":
                e_shehframe = i
            elif symbol == ".debug_frame" or symbol == ".zdebug_frame":
                e_shdbgframe = i
            elif symbol == ".debug_str":
                e_shdbgstr = i
            elif symbol == ".debug_line_str":
                e_shdbglinestr = i
            elif symbol == ".debug_line":
                e_shdbgline = i
            elif symbol == ".debug_info" or symbol == ".zdebug_info":
                e_shdbginfo = i
            elif symbol == ".debug_abbrev" or symbol == ".zdebug_abbrev":
                e_shdbgabbrev = i
            elif symbol == ".eh_frame_hdr":
                e_shehframehdr = i
            elif symbol.startswith(".note."):
                e_shnotelist.setdefault(symbol, i)
            elif stype == "GNU_versym":
                e_shversym = i
            elif stype == "GNU_verdef":
                e_shverdef = i
            elif stype == "GNU_verneed":
                e_shverneed = i
            elif stype == "REL":
                e_shrellist.append(i)
            elif stype == "RELA":
                e_shrelalist.append(i)
            elif stype == "EXIDX":
                e_sharmidx = i
            elif stype == "PLTREL":
                pass
            elif stype == "JMPREL":
                pass

        if debug and e_shnum > 0:
            printer(oneLine)

        # define versym info #
        self.attr["versymList"] = []

        # parse .gnu.version table #
        if e_shversym >= 0:
            # get .gnu.version section info #
            (
                sh_name,
                sh_type,
                sh_flags,
                sh_addr,
                sh_offset,
                sh_size,
                sh_link,
                sh_info,
                sh_addralign,
                sh_entsize,
            ) = self.getSectionInfo(fd, e_shoff + e_shentsize * e_shversym)

            # read .gnu.version data #
            fd.seek(sh_offset)
            versym_section = fd.read(sh_size)

            for i in xrange(long(sh_size / sh_entsize)):
                target = versym_section[i * sh_entsize : (i + 1) * sh_entsize]
                symidx = struct.unpack("H", target)[0]
                self.attr["versymList"].append(symidx)

        # define .dynsym info #
        self.attr.setdefault("dynsymTable", {})
        self.attr.setdefault("dynsymList", [""])  # STN_UNDEF == 0
        self.attr.setdefault("versionTable", {})

        # parse .dynsym table #
        if (
            e_shdynsym >= 0
            and e_shdynstr >= 0
            and self.attr["sectionHeader"][".dynsym"]["type"] != "NOBITS"
            and self.attr["sectionHeader"][".dynstr"]["type"] != "NOBITS"
        ):
            # get .dynstr section info #
            (
                sh_name,
                sh_type,
                sh_flags,
                sh_addr,
                sh_offset,
                sh_size,
                sh_link,
                sh_info,
                sh_addralign,
                sh_entsize,
            ) = self.getSectionInfo(fd, e_shoff + e_shentsize * e_shdynstr)

            # backup .dynstr offset #
            dynstr_offset = sh_offset

            # read .dynstr data #
            fd.seek(sh_offset)
            dynstr_section = fd.read(sh_size)
            try:
                dynstr_section_decoded = dynstr_section.decode()
            except:
                dynstr_section_decoded = dynstr_section

            lastnull = 0
            dynsymTable = {}
            for i, s in enumerate(dynstr_section_decoded):
                if s == "\0":
                    try:
                        dynsymTable[lastnull] = dynstr_section[
                            lastnull:i
                        ].decode()
                    except:
                        dynsymTable[lastnull] = dynstr_section[lastnull:i]
                    lastnull = i + 1

            # parse .gnu.version_d table #
            if e_shverdef >= 0:
                # get .gnu.version_d section info #
                (
                    sh_name,
                    sh_type,
                    sh_flags,
                    sh_addr,
                    sh_offset,
                    sh_size,
                    sh_link,
                    sh_info,
                    sh_addralign,
                    sh_entsize,
                ) = self.getSectionInfo(fd, e_shoff + e_shentsize * e_shverdef)

                # read .gnu.version_d data #
                fd.seek(sh_offset)
                verdef_section = fd.read(sh_size)

                # get verdef values #
                vdidx = 1
                offset = 0
                entsize = 20
                sentsize = 8
                for idx in xrange(sh_info):
                    target = verdef_section[offset : offset + entsize]
                    (
                        vd_version,
                        vd_flags,
                        vd_ndx,
                        vd_cnt,
                        vd_hash,
                        vd_aux,
                        vd_next,
                    ) = struct.unpack("HHHHIII", target)

                    # get verdef strings #
                    soffset = offset + vd_aux
                    for vidx in xrange(vd_cnt):
                        starget = verdef_section[soffset : soffset + sentsize]
                        vda_name, vda_next = struct.unpack("II", starget)

                        if vidx == 0:
                            self.attr["versionTable"][vdidx] = self.getString(
                                dynstr_section, vda_name
                            )

                            vdidx += 1

                        soffset += vda_next

                    offset += vd_next

            # parse .gnu.version_r table #
            if e_shverneed >= 0:
                # get .gnu.version_r section info #
                (
                    sh_name,
                    sh_type,
                    sh_flags,
                    sh_addr,
                    sh_offset,
                    sh_size,
                    sh_link,
                    sh_info,
                    sh_addralign,
                    sh_entsize,
                ) = self.getSectionInfo(
                    fd, e_shoff + e_shentsize * e_shverneed
                )

                # read .gnu.version_r data #
                fd.seek(sh_offset)
                verneed_section = fd.read(sh_size)

                # get verneed values #
                offset = 0
                entsize = 16
                for idx in xrange(sh_info):
                    target = verneed_section[offset : offset + entsize]
                    (
                        vn_version,
                        vn_cnt,
                        vn_file,
                        vn_aux,
                        vn_next,
                    ) = struct.unpack("HHIII", target)

                    # get verneed strings #
                    soffset = offset + entsize
                    for vidx in xrange(vn_cnt):
                        starget = verneed_section[soffset : soffset + entsize]
                        (
                            vna_hash,
                            vna_flags,
                            vna_other,
                            vna_name,
                            vna_next,
                        ) = struct.unpack("IHHII", starget)

                        self.attr["versionTable"][vna_other] = self.getString(
                            dynstr_section, vna_name
                        )

                        soffset += entsize

                    offset += vn_next

            # get .dynsym section info #
            (
                sh_name,
                sh_type,
                sh_flags,
                sh_addr,
                sh_offset,
                sh_size,
                sh_link,
                sh_info,
                sh_addralign,
                sh_entsize,
            ) = self.getSectionInfo(fd, e_shoff + e_shentsize * e_shdynsym)

            # read .dynsym data #
            fd.seek(sh_offset)
            dynsym_section = fd.read(sh_size)

            # print .dynsym table title #
            if debug:
                printer(
                    (
                        "\n[.dynsym Section]\n%s\n"
                        "%04s %16s%10s%10s%10s%10s%10s %30s\n%s"
                    )
                    % (
                        twoLine,
                        "Num",
                        "Value",
                        "Size",
                        "Type",
                        "Bind",
                        "Vis",
                        "Ndx",
                        "Name",
                        twoLine,
                    )
                )

            nrItems = long(sh_size / sh_entsize)
            if nrItems == 0:
                printer("\tNone")

            printCnt = 0

            for i in xrange(nrItems):
                target = dynsym_section[i * sh_entsize : (i + 1) * sh_entsize]
                # 32-bit #
                if self.is32Bit:
                    (
                        st_name,
                        st_value,
                        st_size,
                        st_info,
                        st_other,
                        st_shndx,
                    ) = struct.unpack("IIIBBH", target)
                # 64-bit #
                else:
                    (
                        st_name,
                        st_info,
                        st_other,
                        st_shndx,
                        st_value,
                        st_size,
                    ) = struct.unpack("IBBHQQ", target)

                # get symbol string #
                symbol = self.getString(dynstr_section, st_name)

                # convert manged string #
                if symbol:
                    symbol = ElfAnalyzer.demangleSymbol(symbol)

                # concatenate symbol with it's required version #
                try:
                    symIdx = len(self.attr["dynsymList"])
                    vsIdx = self.attr["versymList"][symIdx]
                    if symbol:
                        symbol = "%s@%s" % (
                            symbol,
                            self.attr["versionTable"][vsIdx],
                        )
                    else:
                        symbol = ""
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

                # add symbol to table #
                self.attr["dynsymTable"][symbol] = {
                    "value": st_value,
                    "size": st_size,
                    "type": ElfAnalyzer.ST_TYPE[
                        ElfAnalyzer.ELF_ST_TYPE(st_info)
                    ],
                    "bind": ElfAnalyzer.ST_BIND_TYPE[
                        ElfAnalyzer.ELF_ST_BIND(st_info)
                    ],
                    "vis": ElfAnalyzer.ST_VISIBILITY_TYPE[
                        ElfAnalyzer.ELF_ST_VISIBILITY(st_other)
                    ],
                    "ndx": st_shndx,
                }

                # add address-symbol mapping info #
                if SysMgr.dwarfEnable:
                    self.addrTable[st_value] = symbol

                # register symbol to dynamic symbol list #
                self.attr["dynsymList"].append(symbol)

                # get index #
                if st_shndx in ElfAnalyzer.SHN_TYPE:
                    if ElfAnalyzer.SHN_TYPE[st_shndx] == "SHN_UNDEF":
                        st_shndx = "UND"
                    elif ElfAnalyzer.SHN_TYPE[st_shndx] == "SHN_ABS":
                        st_shndx = "ABS"

                # print .dynsym table #
                if debug:
                    # apply filter #
                    if SysMgr.filterGroup:
                        if not UtilMgr.isValidStr(symbol):
                            continue

                    printer(
                        "%04d %016x%10d%10s%10s%10s%10s %s"
                        % (
                            i,
                            st_value,
                            st_size,
                            ElfAnalyzer.ST_TYPE[
                                ElfAnalyzer.ELF_ST_TYPE(st_info)
                            ],
                            ElfAnalyzer.ST_BIND_TYPE[
                                ElfAnalyzer.ELF_ST_BIND(st_info)
                            ],
                            ElfAnalyzer.ST_VISIBILITY_TYPE[
                                ElfAnalyzer.ELF_ST_VISIBILITY(st_other)
                            ],
                            st_shndx,
                            symbol,
                        )
                    )

                    printCnt += 1

            if debug:
                if printCnt == 0:
                    printer("\tNone")
                printer(oneLine)

        # define .sym info #
        self.attr.setdefault("symTable", {})

        # parse .symtab table #
        if (
            e_shsymndx >= 0
            and e_shstrndx >= 0
            and self.attr["sectionHeader"][".symtab"]["type"] != "NOBITS"
            and self.attr["sectionHeader"][".strtab"]["type"] != "NOBITS"
        ):
            # get .symtab section info #
            (
                sh_name,
                sh_type,
                sh_flags,
                sh_addr,
                sh_offset,
                sh_size,
                sh_link,
                sh_info,
                sh_addralign,
                sh_entsize,
            ) = self.getSectionInfo(fd, e_shoff + e_shentsize * e_shstrndx)

            # backup .strtab offset #
            strtab_offset = sh_offset

            # read .strtab data #
            fd.seek(sh_offset)
            strtab_section = fd.read(sh_size)

            # get .symtab section info #
            (
                sh_name,
                sh_type,
                sh_flags,
                sh_addr,
                sh_offset,
                sh_size,
                sh_link,
                sh_info,
                sh_addralign,
                sh_entsize,
            ) = self.getSectionInfo(fd, e_shoff + e_shentsize * e_shsymndx)

            # read .symtab data #
            fd.seek(sh_offset)
            sym_section = fd.read(sh_size)

            # parse .sym table title #
            if debug:
                printer(
                    (
                        "\n[.symtab Section]\n%s\n"
                        "%04s %16s%10s%10s%10s%10s%10s%30s\n%s"
                    )
                    % (
                        twoLine,
                        "Num",
                        "Value",
                        "Size",
                        "Type",
                        "Bind",
                        "Vis",
                        "Ndx",
                        "Name",
                        twoLine,
                    )
                )

            nrItems = long(sh_size / sh_entsize)
            if nrItems == 0:
                printer("\tNone")

            printCnt = 0

            for i in xrange(nrItems):
                if self.is32Bit:
                    (
                        st_name,
                        st_value,
                        st_size,
                        st_info,
                        st_other,
                        st_shndx,
                    ) = struct.unpack(
                        "IIIBBH",
                        sym_section[i * sh_entsize : (i + 1) * sh_entsize],
                    )
                # 64-bit #
                else:
                    (
                        st_name,
                        st_info,
                        st_other,
                        st_shndx,
                        st_value,
                        st_size,
                    ) = struct.unpack(
                        "IBBHQQ",
                        sym_section[i * sh_entsize : (i + 1) * sh_entsize],
                    )

                # get symbol string #
                symbol = self.getString(strtab_section, st_name)

                # convert manged string #
                if symbol:
                    symbol = ElfAnalyzer.demangleSymbol(symbol)

                self.attr["symTable"][symbol] = {
                    "value": st_value,
                    "size": st_size,
                    "type": ElfAnalyzer.ST_TYPE[
                        ElfAnalyzer.ELF_ST_TYPE(st_info)
                    ],
                    "bind": ElfAnalyzer.ST_BIND_TYPE[
                        ElfAnalyzer.ELF_ST_BIND(st_info)
                    ],
                    "vis": ElfAnalyzer.ST_VISIBILITY_TYPE[
                        ElfAnalyzer.ELF_ST_VISIBILITY(st_other)
                    ],
                    "ndx": st_shndx,
                }

                # add address-symbol mapping info #
                if SysMgr.dwarfEnable:
                    self.addrTable[st_value] = symbol

                # get index #
                if st_shndx in ElfAnalyzer.SHN_TYPE:
                    if ElfAnalyzer.SHN_TYPE[st_shndx] == "SHN_UNDEF":
                        st_shndx = "UND"
                    elif ElfAnalyzer.SHN_TYPE[st_shndx] == "SHN_ABS":
                        st_shndx = "ABS"

                # parse .sym table #
                if debug:
                    # apply filter #
                    if SysMgr.filterGroup:
                        if not UtilMgr.isValidStr(symbol):
                            continue

                    printer(
                        "%04d %016x%10d%10s%10s%10s%10s %s"
                        % (
                            i,
                            st_value,
                            st_size,
                            ElfAnalyzer.ST_TYPE[
                                ElfAnalyzer.ELF_ST_TYPE(st_info)
                            ],
                            ElfAnalyzer.ST_BIND_TYPE[
                                ElfAnalyzer.ELF_ST_BIND(st_info)
                            ],
                            ElfAnalyzer.ST_VISIBILITY_TYPE[
                                ElfAnalyzer.ELF_ST_VISIBILITY(st_other)
                            ],
                            st_shndx,
                            symbol,
                        )
                    )

                    printCnt += 1
            if debug:
                if printCnt == 0:
                    printer("\tNone")
                printer(oneLine)
        else:
            ElfAnalyzer.strippedFiles[path] = True
            SysMgr.printWarn(
                "failed to get static symbol of %s (stripped)" % path
            )

        # parse REL table #
        for idx in e_shrellist:
            (
                sh_name,
                sh_type,
                sh_flags,
                sh_addr,
                sh_offset,
                sh_size,
                sh_link,
                sh_info,
                sh_addralign,
                sh_entsize,
            ) = self.getSectionInfo(fd, e_shoff + e_shentsize * idx)

            # get symbol string #
            shname = self.getString(str_section, sh_name)

            if debug:
                printer(
                    ("\n[%s Section]\n%s\n%16s %16s %32s %16s %s\n%s")
                    % (
                        shname,
                        twoLine,
                        "Offset",
                        "Info",
                        "Type",
                        "Sym.Value",
                        "Sym.Name",
                        twoLine,
                    )
                )

            fd.seek(sh_offset)

            nrItems = long(sh_size / sh_entsize)
            if nrItems == 0:
                printer("\tNone")

            printCnt = 0
            for i in xrange(nrItems):
                # 32-bit #
                if self.is32Bit:
                    sh_offset, sh_info = struct.unpack("II", fd.read(8))

                    rsym = ElfAnalyzer.ELF32_R_SYM(sh_info)
                    rtype = ElfAnalyzer.ELF32_R_TYPE(sh_info)
                # 64-bit #
                else:
                    sh_offset, sh_info = struct.unpack("QQ", fd.read(16))

                    rsym = ElfAnalyzer.ELF64_R_SYM(sh_info)
                    rtype = ElfAnalyzer.ELF64_R_TYPE(sh_info)

                try:
                    RTYPE = ElfAnalyzer.RELOC_TYPE[rtype]
                except:
                    RTYPE = rtype

                try:
                    symbol = self.attr["dynsymList"][rsym + 1]
                except:
                    symbol = rsym

                # convert manged string #
                if symbol:
                    symbol = ElfAnalyzer.demangleSymbol(symbol)

                # update address on dynsym table #
                if symbol in self.attr["dynsymTable"]:
                    if self.attr["dynsymTable"][symbol]["value"] == 0:
                        self.attr["dynsymTable"][symbol]["value"] = sh_offset

                # get address of symbol string #
                if symbol in self.attr["dynsymTable"]:
                    saddr = self.attr["dynsymTable"][symbol]["value"]
                else:
                    saddr = 0

                if debug:
                    # apply filter #
                    if SysMgr.filterGroup:
                        if not UtilMgr.isValidStr(symbol):
                            continue

                    printer(
                        "%016x %016x %32s %016x %s"
                        % (sh_offset, sh_info, RTYPE, saddr, symbol)
                    )

                    printCnt += 1

            if debug:
                if printCnt == 0:
                    printer("\tNone")
                printer(oneLine)

        # parse RELA table #
        for idx in e_shrelalist:
            (
                sh_name,
                sh_type,
                sh_flags,
                sh_addr,
                sh_offset,
                sh_size,
                sh_link,
                sh_info,
                sh_addralign,
                sh_entsize,
            ) = self.getSectionInfo(fd, e_shoff + e_shentsize * idx)

            # get symbol string #
            shname = self.getString(str_section, sh_name)

            if debug:
                printer(
                    ("\n[%s Section]\n%s\n%16s %16s %32s %16s %s\n%s")
                    % (
                        shname,
                        twoLine,
                        "Offset",
                        "Info",
                        "Type",
                        "Sym.Value",
                        "Sym.Name + Addend",
                        twoLine,
                    )
                )

            fd.seek(sh_offset)

            nrItems = long(sh_size / sh_entsize)
            if nrItems == 0:
                printer("\tNone")

            printCnt = 0

            for i in xrange(nrItems):
                # 32-bit #
                if self.is32Bit:
                    sh_offset, sh_info, sh_addend = struct.unpack(
                        "III", fd.read(12)
                    )

                    rsym = ElfAnalyzer.ELF32_R_SYM(sh_info)
                    rtype = ElfAnalyzer.ELF32_R_TYPE(sh_info)
                # 64-bit #
                else:
                    sh_offset, sh_info, sh_addend = struct.unpack(
                        "QQQ", fd.read(24)
                    )

                    rsym = ElfAnalyzer.ELF64_R_SYM(sh_info)
                    rtype = ElfAnalyzer.ELF64_R_TYPE(sh_info)

                try:
                    RTYPE = ElfAnalyzer.RELOC_TYPE[rtype]
                except:
                    RTYPE = rtype

                if RTYPE == "R_X86_64_RELATIVE":
                    val = " " * 16
                else:
                    val = "%016x" % 0

                try:
                    symbol = self.attr["dynsymList"][rsym + 1]
                except:
                    symbol = rsym

                # convert manged string #
                if symbol:
                    symbol = ElfAnalyzer.demangleSymbol(symbol)

                # update address on dynsym table #
                if symbol in self.attr["dynsymTable"]:
                    if self.attr["dynsymTable"][symbol]["value"] == 0:
                        self.attr["dynsymTable"][symbol]["value"] = sh_offset

                    self.attr["dynsymTable"][symbol]["rtype"] = rtype

                    if symbol:
                        symbol = "%s + " % symbol
                if debug:
                    # apply filter #
                    if SysMgr.filterGroup:
                        if not UtilMgr.isValidStr(symbol):
                            continue

                    printer(
                        "%016x %016x %32s %s %s"
                        % (
                            sh_offset,
                            sh_info,
                            RTYPE,
                            val,
                            "%s%x" % (symbol, sh_addend),
                        )
                    )

                    printCnt += 1

            if debug:
                if printCnt == 0:
                    printer("\tNone")
                printer(oneLine)

        # set DWARF Flag #
        if SysMgr.dwarfEnable:
            self.attr["dwarfEnabled"] = True
        else:
            self.attr["dwarfEnabled"] = False

        # check frame section #
        sectionHeader = self.attr["sectionHeader"]
        if (
            ".eh_frame" in sectionHeader
            and sectionHeader[".eh_frame"]["type"] != "NOBITS"
        ):
            frameSectName = "eh_frame"
            e_shframe = e_shehframe
        elif (
            ".debug_frame" in sectionHeader
            and sectionHeader[".debug_frame"]["type"] != "NOBITS"
        ):
            # TODO: need to implement more for DWARF v4 #
            frameSectName = "debug_frame"
            e_shframe = e_shdbgframe
        elif (
            ".zdebug_frame" in sectionHeader
            and sectionHeader[".zdebug_frame"]["type"] != "NOBITS"
        ):
            frameSectName = "debug_frame"
            e_shframe = e_shdbgframe
        else:
            frameSectName = ""

        # check frame section #
        self.attr["dwarfTable"] = {}
        if SysMgr.dwarfEnable and e_shframe >= 0 and frameSectName:

            def _getEncType(encoding):
                if encoding == ENC_FLAGS["DW_EH_PE_omit"]:
                    SysMgr.printErr(
                        "failed to decode initial location for FDE"
                    )
                    return None, None, None

                basicEnc = encoding & 0x0F
                encMod = encoding & 0xF0

                # get format #
                DW_EH_ENCODING_MAP = ElfAnalyzer.DW_EH_ENCODING_MAP
                if basicEnc in DW_EH_ENCODING_MAP:
                    encFormat = DW_EH_ENCODING_MAP[basicEnc]
                else:
                    encFormat = None

                return basicEnc, encMod, encFormat

            def _decodeAddr(addr, shaddr, offset, encoding):
                if encoding == ENC_FLAGS["DW_EH_PE_absptr"]:
                    pass
                elif encoding == ENC_FLAGS["DW_EH_PE_pcrel"]:
                    addr += shaddr + offset
                elif encoding == ENC_FLAGS["DW_EH_PE_datarel"]:
                    addr += shaddr
                else:
                    SysMgr.printErr(
                        "failed to recognize modifier %x" % encoding
                    )
                    sys.exit(-1)
                return addr

            def _decodeData(encFormat, fd):
                if encFormat == "DW_EH_PE_sdata4":
                    val = struct.unpack("i", fd.read(4))[0]
                elif encFormat == "DW_EH_PE_sdata8":
                    val = struct.unpack("q", fd.read(8))[0]
                elif encFormat == "DW_EH_PE_sdata2":
                    val = struct.unpack("h", fd.read(2))[0]
                elif (
                    encFormat == "DW_EH_PE_uleb128"
                    or encFormat == "DW_EH_PE_sleb128"
                ):
                    data = UtilMgr.readLEB128(fd)
                    data = data.decode("latin-1")
                    if encFormat == "DW_EH_PE_uleb128":
                        val, nsize = UtilMgr.decodeULEB128(data)
                    else:
                        val, nsize = UtilMgr.decodeSLEB128(data)
                elif encFormat == "DW_EH_PE_absptr":
                    if self.is32Bit:
                        val = struct.unpack("I", fd.read(4))[0]
                    else:
                        val = struct.unpack("Q", fd.read(8))[0]
                elif encFormat == "DW_EH_PE_udata4":
                    val = struct.unpack("I", fd.read(4))[0]
                elif encFormat == "DW_EH_PE_udata8":
                    val = struct.unpack("Q", fd.read(8))[0]
                elif encFormat == "DW_EH_PE_udata2":
                    val = struct.unpack("H", fd.read(2))[0]
                else:
                    SysMgr.printErr(
                        "failed to recognize basic encoding %s" % encFormat
                    )
                    sys.exit(-1)

                return val

            def _getAugData(string, table, pos, size):
                if size == 0:
                    return {}, "", ""

                augdata = table[pos : pos + size]

                # parse data #
                augpos = 0
                augdict = {}
                for idx, char in enumerate(string):
                    if augpos >= len(augdata):
                        break

                    try:
                        data = ord(augdata[augpos])
                    except SystemExit:
                        sys.exit(0)
                    except:
                        data = augdata[augpos]

                    if char == "z":
                        augdict["length"] = size
                    elif char == "L":
                        augdict["lsdaEncoding"] = data
                        augpos += 1
                    elif char == "R":
                        augdict["fdeEncoding"] = data
                        augpos += 1
                    elif char == "S":
                        augpos += 1
                    elif char == "P":
                        # get basic encoding #
                        augdict["personality"] = dict(encoding=data)
                        basicEnc = data & 0x0F
                        augpos += 1

                        # get format #
                        DW_EH_ENCODING_MAP = ElfAnalyzer.DW_EH_ENCODING_MAP
                        if basicEnc in DW_EH_ENCODING_MAP:
                            encFormat = DW_EH_ENCODING_MAP[basicEnc]
                        else:
                            encFormat = None
                        augdict["personality"]["format"] = encFormat

                        # decoding #
                        if encFormat == "DW_EH_PE_sdata4":
                            data = augdata[augpos : augpos + 4]
                            func = struct.unpack("i", data)[0]
                            augpos += 4
                        elif encFormat == "DW_EH_PE_sdata8":
                            data = augdata[augpos : augpos + 8]
                            func = struct.unpack("q", data)[0]
                            augpos += 8
                        elif encFormat == "DW_EH_PE_sdata2":
                            data = augdata[augpos : augpos + 2]
                            func = struct.unpack("h", data)[0]
                            augpos += 2
                        elif (
                            encFormat == "DW_EH_PE_uleb128"
                            or encFormat == "DW_EH_PE_sleb128"
                        ):
                            data = augdata[augpos:].decode("latin-1")
                            if encFormat == "DW_EH_PE_uleb128":
                                func, nsize = UtilMgr.decodeULEB128(data)
                            else:
                                func, nsize = UtilMgr.decodeSLEB128(data)
                            augpos += nsize
                        elif encFormat == "DW_EH_PE_absptr":
                            if self.is32Bit:
                                data = augdata[augpos : augpos + 4]
                                func = struct.unpack("I", data)[0]
                                augpos += 4
                            else:
                                data = augdata[augpos : augpos + 8]
                                func = struct.unpack("Q", data)[0]
                                augpos += 8
                        elif encFormat == "DW_EH_PE_udata4":
                            data = augdata[augpos : augpos + 4]
                            func = struct.unpack("I", data)[0]
                            augpos += 4
                        elif encFormat == "DW_EH_PE_udata8":
                            data = augdata[augpos : augpos + 8]
                            func = struct.unpack("Q", data)[0]
                            augpos += 8
                        elif encFormat == "DW_EH_PE_udata2":
                            data = augdata[augpos : augpos + 2]
                            func = struct.unpack("H", data)[0]
                            augpos += 2
                        else:
                            SysMgr.printErr(
                                "failed to recognize encoding format %x"
                                % basicEnc
                            )
                            sys.exit(-1)

                        augdict["personality"]["func"] = func
                    elif char == "e" and string[idx + 1] == "h":
                        pass
                    elif char == "h" and string[idx - 1] == "e":
                        augpos += 1
                    else:
                        SysMgr.printErr(
                            'failed to recognize augmentation "%s"' % char
                        )
                        sys.exit(-1)

                adstr = UtilMgr.convStr2Bytes(augdata)

                return augdict, adstr.strip(), augdata

            def _decodeCFI(self, entry, cfi, cie, offset):
                def _add2Order(regnum):
                    """
                    DW_CFA_restore and others remove registers from curLine,
                    but they stay in reg_order. Avoid duplicates.
                    """
                    if regnum not in regOrder:
                        regOrder.append(regnum)

                CFARule = ElfAnalyzer.CFARule
                RegisterRule = ElfAnalyzer.RegisterRule
                regIdx = ElfAnalyzer.CFARule.REG
                offsetIdx = ElfAnalyzer.CFARule.OFFSET
                exprIdx = ElfAnalyzer.CFARule.EXPR
                getRule = ElfAnalyzer.getCFARule

                copy = SysMgr.getPkg("copy", False)

                # CIE #
                if entry == "CIE":
                    myObj = cie
                    curLine = dict(pc=0, cfa=getRule(reg=None, offset=0))
                    regOrder = []
                # FDE #
                else:
                    myObj = self.attr["dwarf"]["FDE"][offset]
                    cieTable = cie["table"]
                    if cieTable:
                        cieLastLine = copy.copy(cieTable[-1])
                        curLine = copy.copy(cieLastLine)
                    else:
                        curLine = dict(cfa=getRule(reg=None, offset=0))
                    curLine["pc"] = myObj["initLoc"]
                    regOrder = copy.copy(cie["regOrder"])

                table = []

                # stack for DW_CFA_{remember|restore}_state instructions #
                lineStack = []

                """
                Throughout this loop, curLine is the current line.
                Some instructions add it to the table,
                but most instructions just update it
                without adding it to the table.
                """
                for instr in cfi:
                    name = instr[0]
                    args = instr[2]

                    if name == "DW_CFA_set_loc":
                        table.append(copy.copy(curLine))
                        curLine["pc"] = args[0]
                    elif name in (
                        "DW_CFA_advance_loc1",
                        "DW_CFA_advance_loc2",
                        "DW_CFA_advance_loc4",
                        "DW_CFA_advance_loc",
                    ):
                        table.append(copy.copy(curLine))
                        curLine["pc"] += args[0] * cie["caf"]
                    elif name == "DW_CFA_def_cfa":
                        curLine["cfa"] = getRule(reg=args[0], offset=args[1])
                    elif name == "DW_CFA_def_cfa_sf":
                        curLine["cfa"] = getRule(
                            reg=args[0], offset=args[1] * cie["daf"]
                        )
                    elif name == "DW_CFA_def_cfa_register":
                        curLine["cfa"] = getRule(
                            reg=args[0], offset=curLine["cfa"][offsetIdx]
                        )
                    elif name == "DW_CFA_def_cfa_offset":
                        curLine["cfa"] = getRule(
                            reg=curLine["cfa"][regIdx], offset=args[0]
                        )
                    elif name == "DW_CFA_def_cfa_offset_sf":
                        curLine["cfa"] = getRule(
                            reg=curLine["cfa"][regIdx],
                            offset=args[0] * cie["daf"],
                        )
                    elif name == "DW_CFA_def_cfa_expression":
                        curLine["cfa"] = getRule(expr=args[0])
                    elif name == "DW_CFA_undefined":
                        _add2Order(args[0])
                        curLine[args[0]] = RegisterRule(RegisterRule.UNDEFINED)
                    elif name == "DW_CFA_same_value":
                        _add2Order(args[0])
                        curLine[args[0]] = RegisterRule(
                            RegisterRule.SAME_VALUE
                        )
                    elif name in (
                        "DW_CFA_offset",
                        "DW_CFA_offset_extended",
                        "DW_CFA_offset_extended_sf",
                    ):
                        _add2Order(args[0])
                        curLine[args[0]] = RegisterRule(
                            RegisterRule.OFFSET, args[1] * cie["daf"]
                        )
                    elif name in ("DW_CFA_val_offset", "DW_CFA_val_offset_sf"):
                        _add2Order(args[0])
                        curLine[args[0]] = RegisterRule(
                            RegisterRule.VAL_OFFSET, args[1] * cie["daf"]
                        )
                    elif name == "DW_CFA_register":
                        _add2Order(args[0])
                        curLine[args[0]] = RegisterRule(
                            RegisterRule.REGISTER, args[1]
                        )
                    elif name == "DW_CFA_expression":
                        _add2Order(args[0])
                        curLine[args[0]] = RegisterRule(
                            RegisterRule.EXPRESSION, args[1]
                        )
                    elif name == "DW_CFA_val_expression":
                        _add2Order(args[0])
                        curLine[args[0]] = RegisterRule(
                            RegisterRule.VAL_EXPRESSION, args[1]
                        )
                    elif name in ("DW_CFA_restore", "DW_CFA_restore_extended"):
                        _add2Order(args[0])
                        if entry != "FDE":
                            SysMgr.printErr(
                                "%s instruction must be in a FDE" % name
                            )
                        if args[0] in cieLastLine:
                            curLine[args[0]] = cieLastLine[args[0]]
                        else:
                            curLine.pop(args[0], None)
                    elif name == "DW_CFA_remember_state":
                        lineStack.append(UtilMgr.deepcopy(curLine))
                    elif name == "DW_CFA_restore_state":
                        pc = curLine["pc"]
                        curLine = lineStack.pop()
                        curLine["pc"] = pc
                    elif name == "DW_CFA_nop":
                        pass
                    else:
                        """
                        SysMgr.printWarn(
                            'skipped to update current line by %s' % name)
                        """
                        self.nrSkipUpdate += 1

                """
                The current line is appended to the table after
                all instructions have ended, if there were instructions.
                """
                if curLine["cfa"][regIdx] is not None or len(curLine) > 2:
                    table.append(curLine)

                # save result #
                myObj["table"] = table
                myObj["regOrder"] = regOrder

                return table, regOrder

            def _makeCFATable(self, entry, offset, regList, prt=False):
                def _getCFARule(cfa):
                    regIdx = ElfAnalyzer.CFARule.REG
                    offsetIdx = ElfAnalyzer.CFARule.OFFSET
                    exprIdx = ElfAnalyzer.CFARule.EXPR

                    if cfa[exprIdx]:
                        return "exp"
                    else:
                        return "%s%+d" % (regList[cfa[regIdx]], cfa[offsetIdx])

                def _getRegRule(reg):
                    typeIdx = ElfAnalyzer.RegisterRule.TYPE
                    argIdx = ElfAnalyzer.RegisterRule.ARG

                    s = ElfAnalyzer.DW_CFI_REGISTER_RULE_TYPE[reg[typeIdx]]

                    if reg[typeIdx] in ("OFFSET", "VAL_OFFSET"):
                        s += "%+d" % reg[argIdx]
                    elif reg[typeIdx] == "REGISTER":
                        s += regList[reg[argIdx]]

                    return s

                myObj = self.attr["dwarf"][entry][offset]
                table = myObj["table"]
                regOrder = myObj["regOrder"]

                if "initLoc" in myObj:
                    initLoc = myObj["initLoc"]
                else:
                    initLoc = 0

                # get return address register #
                if "rar" in myObj:
                    rar = myObj["rar"]
                else:
                    rar = myObj["CIE"]["rar"]

                # register to CFA table #
                if initLoc > 0:
                    self.attr["dwarf"]["CFAIndex"].append(initLoc)
                    self.attr["dwarf"]["CFATable"][initLoc] = table

                if prt:
                    # remove return address register #
                    try:
                        regOrder.remove(rar)
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass

                    # define default title #
                    if not self.cfaTableTitle:
                        self.cfaTableTitle = "{0:^16} {1:<10}".format(
                            "LOC", "CFA"
                        )

                    # copy default title #
                    s = str(self.cfaTableTitle)

                    # add reg name #
                    for regnum in regOrder:
                        s += "%-6s" % regList[regnum]
                    s += "%-6s\n" % "ra"
                    regOrder.append(rar)

                    # mark line #
                    s = "." * len(s) + "\n" + s

                # add decoded CFA lines #
                for line in table:
                    pc = line["pc"]

                    if not prt:
                        continue

                    # pc #
                    s += "%016x" % pc

                    # cfa #
                    if line["cfa"]:
                        cfa = line["cfa"]
                    else:
                        cfa = "u"
                    s += " %-10s" % _getCFARule(cfa)

                    # reg #
                    for regnum in regOrder:
                        if regnum in line:
                            reginfo = _getRegRule(line[regnum])
                        else:
                            reginfo = "u"
                        s += "%-6s" % reginfo

                    s += "\n"

                if prt:
                    printer(s)

            def _printCFIs(cfi, cie=None, pc=None, regList=None):
                def _convRegName(arg, regList):
                    return regList[arg]

                s = ""
                for inst in cfi:
                    name = inst[0]
                    args = inst[2]

                    if name in (
                        "DW_CFA_offset",
                        "DW_CFA_offset_extended",
                        "DW_CFA_offset_extended_sf",
                        "DW_CFA_val_offset",
                        "DW_CFA_val_offset_sf",
                    ):
                        s += " %s: %s at cfa%+d\n" % (
                            name,
                            _convRegName(args[0], regList),
                            args[1] * cie["daf"],
                        )
                    elif name in (
                        "DW_CFA_restore",
                        "DW_CFA_restore_extended",
                        "DW_CFA_undefined",
                        "DW_CFA_same_value",
                        "DW_CFA_def_cfa_register",
                    ):
                        s += " %s: %s\n" % (
                            name,
                            _convRegName(args[0], regList),
                        )
                    elif name == "DW_CFA_register":
                        s += " %s: %s in %s" % (
                            name,
                            _convRegName(args[0], regList),
                            _convRegName(args[1], regList),
                        )
                    elif name == "DW_CFA_set_loc":
                        pc = args[0]
                        s += " %s: %08x\n" % (name, pc)
                    elif name in (
                        "DW_CFA_advance_loc1",
                        "DW_CFA_advance_loc2",
                        "DW_CFA_advance_loc4",
                        "DW_CFA_advance_loc",
                    ):
                        factoredOffset = args[0] * cie["caf"]
                        s += " %s: %s to %08x\n" % (
                            name,
                            factoredOffset,
                            factoredOffset + pc,
                        )
                        pc += factoredOffset
                    elif name in (
                        "DW_CFA_remember_state",
                        "DW_CFA_restore_state",
                        "DW_CFA_nop",
                    ):
                        s += " %s\n" % name
                    elif name == "DW_CFA_def_cfa":
                        s += " %s: %s ofs %s\n" % (
                            name,
                            _convRegName(args[0], regList),
                            args[1],
                        )
                    elif name == "DW_CFA_def_cfa_sf":
                        s += " %s: %s ofs %s\n" % (
                            name,
                            _convRegName(args[0], regList),
                            args[1] * cie["daf"],
                        )
                    elif name in (
                        "DW_CFA_def_cfa_offset",
                        "DW_CFA_GNU_args_size",
                    ):
                        s += " %s: %s\n" % (name, args[0])
                    elif name in ("DW_CFA_def_cfa_offset_sf"):
                        s += " %s: %s\n" % (name, args[0] * cie["daf"])
                    elif name == "DW_CFA_def_cfa_expression":
                        """
                        expr_dumper = ExprDumper(entry.structs)
                        s += ' %s (%s)\n' % \
                            (name, expr_dumper.dump_expr(args[0]))
                        """
                        s += " %s: %s\n" % (name, args)
                    elif name == "DW_CFA_expression":
                        """
                        expr_dumper = ExprDumper(entry.structs)
                        s += ' %s: %s (%s)\n' % (
                            name, _convRegName(args[0], regList),
                                 expr_dumper.dump_expr(args[1]))
                        """
                        s += " %s: %s\n" % (name, args)
                    else:
                        s += " %s: <??>\n" % name

                printer(s.rstrip("\n"))

            (
                sh_name,
                sh_type,
                sh_flags,
                sh_addr,
                sh_offset,
                sh_size,
                sh_link,
                sh_info,
                sh_addralign,
                sh_entsize,
            ) = self.getSectionInfo(fd, e_shoff + e_shentsize * e_shframe)

            self.attr.setdefault("dwarf", {})
            self.attr["dwarf"]["CIE"] = {}
            self.attr["dwarf"]["FDE"] = {}
            self.attr["dwarf"].setdefault("general", {})
            self.attr["dwarf"].setdefault("CFAIndex", [])
            self.attr["dwarf"].setdefault("CFATable", {})
            ENC_FLAGS = ElfAnalyzer.DW_EH_ENCODING_FLAGS
            nrCIE = nrFDE = 0

            # get symbol string #
            shname = self.getString(str_section, sh_name)

            if debug:
                printer("\n[%s Section]\n%s" % (shname, twoLine))

            # set position #
            fd.seek(sh_offset)

            # decompress section #
            origFd = fd
            isCompressed = False
            if shname.startswith(".z"):
                decompSect, decompSize = UtilMgr.unzip(fd, shname)
                if decompSize:
                    isCompressed = True
                    origFd = fd
                    sh_size = decompSize
                    fd = MemoryFile(size=sh_offset + sh_size, name=shname)
                    fd.seek(sh_offset)
                    fd.write(decompSect)

            # initialize the number of decode error #
            self.nrSkipUpdate = 0

            while 1:
                # offset #
                offset = fd.tell() - sh_offset
                if offset >= sh_size:
                    break

                # length #
                size = struct.unpack("I", fd.read(4))[0]
                # terminator #
                if size == 0:
                    break
                # extended length 8 bytes are needed #
                elif size == 0xFFFFFFFF:
                    size = struct.unpack("Q", fd.read(8))[0]

                # format #
                dwarfFormat = 64 if size == 0xFFFFFFFF else 32

                # initial length #
                initLenField = 4 if dwarfFormat == 32 else 12

                # start position #
                startPos = fd.tell()

                # CIE ID #
                cid = struct.unpack("I", fd.read(4))[0]

                # check CIE #
                if frameSectName == "eh_frame":
                    isCIE = cid == 0
                else:
                    isCIE = (
                        dwarfFormat == 32 and cid == 0xFFFFFFFF
                    ) or cid == 0xFFFFFFFFFFFFFFFF

                # -------------------- CIE --------------------#
                if isCIE:
                    entry = "CIE"
                    nrCIE += 1
                    initLoc = 0

                    # version #
                    ver = struct.unpack("B", fd.read(1))[0]

                    # data #
                    dataSize = size - 5
                    table = fd.read(dataSize)

                    # Augmentation String #
                    if frameSectName == "eh_frame":
                        augstr = self.getString(table)
                        pos = len(augstr) + 1
                    else:
                        augstr = ""
                        pos = 1

                    # ehdata #
                    if "eh" in augstr:
                        if self.is32Bit:
                            ehdata = fd.read(4)
                        else:
                            ehdata = fd.read(8)

                    # size for address and segment in DWARF v4 #
                    if ver >= 4:
                        addrSize = struct.unpack("B", table[pos : pos + 1])[0]
                        pos += 1
                        segmentSize = struct.unpack("B", table[pos : pos + 1])[
                            0
                        ]
                        pos += 1
                    else:
                        addrSize = segmentSize = -1

                    # Call Alignment Factor #
                    data = table[pos : pos + 1024].decode("latin-1")
                    caf, nsize = UtilMgr.decodeULEB128(data)
                    pos += nsize

                    # Data Alignment Factor #
                    data = table[pos : pos + 1024].decode("latin-1")
                    daf, nsize = UtilMgr.decodeSLEB128(data)
                    pos += nsize

                    # Return Address Register #
                    data = table[pos : pos + 1024].decode("latin-1")
                    rar, nsize = UtilMgr.decodeULEB128(data)
                    pos += nsize

                    # Augmentation Size #
                    if "z" in augstr:
                        data = table[pos : pos + 1024].decode("latin-1")
                        augsize, nsize = UtilMgr.decodeULEB128(data)
                        pos += nsize
                    else:
                        augsize = 0

                    # Augmentation Data #
                    if frameSectName == "eh_frame":
                        augdict, augdatastr, augdata = _getAugData(
                            augstr, table, pos, augsize
                        )
                        pos += augsize
                    else:
                        augdict = {}
                        augdatastr = ""
                        augdata = ""

                    # decode Call Frame Instructions #
                    cfi = self.getCFI(table, pos, dataSize)

                    # save info #
                    cie = self.attr["dwarf"]["CIE"][offset] = {
                        "offset": offset,
                        "length": size,
                        "id": cid,
                        "version": ver,
                        "addrsize": addrSize,
                        "segmentsize": segmentSize,
                        "caf": caf,
                        "daf": daf,
                        "rar": rar,
                        "augsize": augsize,
                        "augstr": augstr,
                        "augdict": augdict,
                        "augdata": augdata,
                        "augdatastr": augdatastr,
                        "cfi": cfi,
                        "table": [],
                    }

                    # print info #
                    if debug:
                        printStr = "\n%08x %016x %08x CIE\n" % (
                            offset,
                            size,
                            cid,
                        )
                        printStr += " %-22s %s\n" % ("Version:", ver)
                        printStr += ' %-22s "%s"\n' % ("Augmentation:", augstr)
                        if addrSize >= 0:
                            printStr += " %-22s %s\n" % (
                                "Pointer Size:",
                                addrSize,
                            )
                        if segmentSize >= 0:
                            printStr += " %-22s %s\n" % (
                                "Segment Size:",
                                segmentSize,
                            )
                        printStr += " %-22s %x\n" % (
                            "Code alignment factor:",
                            caf,
                        )
                        printStr += " %-22s %x\n" % (
                            "Data alignment factor:",
                            daf,
                        )
                        printStr += " %-22s %d\n" % (
                            "Return address column:",
                            rar,
                        )
                        if augdatastr:
                            printStr += " %-22s %s\n\n" % (
                                "Augmentation data: ",
                                augdatastr,
                            )
                        printer(printStr)

                # -------------------- FDE --------------------#
                else:
                    entry = "FDE"
                    nrFDE += 1

                    # CIE pointer #
                    ciePtr = cid

                    # CIE #
                    try:
                        if frameSectName == "eh_frame":
                            cieOffset = offset + dwarfFormat // 8 - ciePtr
                            cie = self.attr["dwarf"]["CIE"][cieOffset]
                        elif frameSectName == "debug_frame":
                            cieOffset = 0
                            cie = self.attr["dwarf"]["CIE"][ciePtr]
                    except:
                        SysMgr.printWarn(
                            "failed to get CIE info for FDE", reason=True
                        )
                        continue

                    # check encoding #
                    if frameSectName == "eh_frame":
                        augstr = cie["augstr"]
                        augdict = cie["augdict"]
                        augdatastr = None

                        if not "fdeEncoding" in augdict:
                            SysMgr.printErr(
                                (
                                    "failed to find FDE encoding data "
                                    "from CIE %x"
                                )
                                % cie["id"]
                            )
                            sys.exit(-1)
                    else:
                        augstr = ""
                        augdict = {}
                        augdatastr = None

                    # get offset #
                    curOffset = fd.tell() - sh_offset

                    # get encoding #
                    if frameSectName == "eh_frame":
                        encoding = cie["augdict"]["fdeEncoding"]
                        basicEnc, encMod, encFormat = _getEncType(encoding)
                        if basicEnc is None:
                            continue
                    else:
                        encoding = ""
                        basicEnc = ""
                        encMod = ENC_FLAGS["DW_EH_PE_absptr"]
                        encFormat = "DW_EH_PE_absptr"

                    # get function address #
                    initLoc = _decodeData(encFormat, fd)

                    # convert function address #
                    initLoc = _decodeAddr(initLoc, sh_addr, curOffset, encMod)

                    # Range Length #
                    lenSize = _decodeData(encFormat, fd)

                    # Augmentation Size #
                    if "z" in augstr:
                        augsize = UtilMgr.readLEB128(fd)
                        if not augsize:
                            augsize = 0
                            nsize = 1
                        else:
                            augsize, nsize = UtilMgr.decodeULEB128(augsize)
                    else:
                        augsize = 0

                    # Augmentation Data #
                    if (
                        augsize == 0
                        and "personality" in augdict
                        and "lsdaEncoding" in augdict
                    ):
                        # get encoding format #
                        encFormat = augdict["personality"]["format"]

                        # decode data for size #
                        curPos = fd.tell()
                        data = _decodeData(encFormat, fd)
                        datasize = fd.tell() - curPos
                        fd.seek(curPos)

                        # load data #
                        augdata = fd.read(datasize)
                        augdatastr = UtilMgr.convStr2Bytes(augdata)

                    # read remain part #
                    remain = fd.tell() - startPos
                    loadSize = size - remain
                    if loadSize > 0:
                        table = fd.read(loadSize)

                        # decode Call Frame Instructions #
                        cfi = self.getCFI(table, pos=0, size=len(table))
                    # wrong FDE #
                    else:
                        fd.seek(loadSize, 1)
                        cfi = []

                    # save FDE info #
                    self.attr["dwarf"]["FDE"][offset] = {
                        "offset": offset,
                        "length": size,
                        "id": cid,
                        "CIE": cie,
                        "initLoc": initLoc,
                        "lenSize": lenSize,
                        "cfi": cfi,
                        "table": [],
                    }

                    if initLoc in self.addrTable and self.addrTable[initLoc]:
                        symbol = self.addrTable[initLoc]
                        self.attr["dwarf"]["FDE"][offset]["symbol"] = symbol
                    else:
                        symbol = ""

                        # register stripped function info #
                        self.attr["dwarfTable"][hex(initLoc)] = {
                            "value": initLoc,
                            "size": lenSize,
                            "type": "FUNC",
                        }

                    # print info #
                    if debug:
                        # apply filter #
                        if SysMgr.filterGroup:
                            if not UtilMgr.isValidStr(symbol):
                                continue

                        # type info #
                        printStr = "\n%08x %016x %08x FDE cie=%08x " % (
                            offset,
                            size,
                            cid,
                            cieOffset,
                        )

                        # address info #
                        printStr += "pc=%016x..%016x" % (
                            initLoc,
                            initLoc + lenSize,
                        )

                        # symbol info #
                        if symbol:
                            printStr += " sym=%s" % symbol

                        printStr += "\n"

                        # augmentation info #
                        if augdatastr:
                            printStr += " %-22s %s\n\n" % (
                                "Augmentation data: ",
                                augdatastr,
                            )

                        # print line #
                        printer(printStr)

                # decode instructions to make CFA table #
                _decodeCFI(self, entry, cfi, cie, offset)

                # print CFI #
                if debug:
                    _printCFIs(cfi, cie, initLoc, regList)

                # make CFA table #
                _makeCFATable(self, entry, offset, regList, prt=debug)

            # print the number of instructions for skip-update-current-line #
            if self.nrSkipUpdate > 0:
                SysMgr.printWarn(
                    (
                        "skipped to update current line "
                        "by %s DWARF instructions for %s"
                    )
                    % (UtilMgr.convNum(self.nrSkipUpdate), self.path),
                    True,
                )

            # sort address list for CFA #
            self.attr["dwarf"]["CFAIndex"].sort()

            # add general info #
            self.attr["dwarf"]["general"]["nrCIE"] = nrCIE
            self.attr["dwarf"]["general"]["nrFDE"] = nrFDE

            # remove useless data #
            for name in list(self.attr["dwarf"]):
                if not name in ("CFAIndex", "CFATable", "info", "abbrev"):
                    del self.attr["dwarf"][name]

            if debug:
                printer(
                    "\n< Total CIE: %s / FDE: %s >\n%s"
                    % (UtilMgr.convNum(nrCIE), UtilMgr.convNum(nrFDE), oneLine)
                )

            # recover original fd #
            if isCompressed:
                fd = origFd

        # check .eh_frame_hdr section #
        if (
            SysMgr.dwarfEnable
            and e_shehframehdr >= 0
            and self.attr["sectionHeader"][".eh_frame_hdr"]["type"] != "NOBITS"
        ):
            (
                sh_name,
                sh_type,
                sh_flags,
                sh_addr,
                sh_offset,
                sh_size,
                sh_link,
                sh_info,
                sh_addralign,
                sh_entsize,
            ) = self.getSectionInfo(fd, e_shoff + e_shentsize * e_shehframehdr)

            self.attr.setdefault("dwarf", {})
            self.attr["dwarf"]["hdr"] = {}
            ENC_FLAGS = ElfAnalyzer.DW_EH_ENCODING_FLAGS

            # get symbol string #
            shname = self.getString(str_section, sh_name)

            if debug:
                printer("\n[%s Section]\n%s" % (shname, twoLine))

            # set position #
            fd.seek(sh_offset)

            # version #
            ver = struct.unpack("B", fd.read(1))[0]

            # eh_frame_ptr_enc #
            ehframePtrEnc = struct.unpack("B", fd.read(1))[0]
            basicEnc, efpEncMod, efpEncFormat = _getEncType(ehframePtrEnc)

            # fde_count_enc #
            fdeCntEnc = struct.unpack("B", fd.read(1))[0]
            basicEnc, fcEncMod, fcEncFormat = _getEncType(fdeCntEnc)

            # table_enc #
            tableEnc = struct.unpack("B", fd.read(1))[0]
            basicEnc, tEncMod, tEncFormat = _getEncType(tableEnc)

            # eh_frame_ptr #
            ehframePtr = _decodeData(efpEncFormat, fd) + sh_offset + 4

            # fde_count #
            fdeCnt = _decodeData(fcEncFormat, fd)

            # print summary #
            if debug:
                printer(
                    (
                        "eh_frame pointer: %016x, FDE count: %s\n%s"
                        % (ehframePtr, UtilMgr.convNum(fdeCnt), oneLine)
                    )
                )

                # print menu #
                printer(
                    "{0:^5} {1:^16} {2:^16}".format(
                        "IDX", "FUNC ADDR", "FDE ADDR"
                    )
                )

            # table #
            printCnt = 0
            for idx in xrange(fdeCnt):
                curPos = fd.tell() - sh_offset

                # address for the function #
                initLoc = _decodeData(tEncFormat, fd)
                initLoc = _decodeAddr(initLoc, sh_addr, curPos, tEncMod)

                # address for the FDE #
                addr = _decodeData(tEncFormat, fd)
                addr = _decodeAddr(addr, sh_addr, curPos, tEncMod)

                if debug:
                    output = "%05s %016x %016x" % (idx, initLoc, addr)

                    # apply filter #
                    if SysMgr.filterGroup:
                        if not UtilMgr.isValidStr(output):
                            continue

                    printer(output)

                    printCnt += 1

            if debug:
                if printCnt == 0:
                    printer("%s\n\tNone" % oneLine)
                printer(oneLine)

        # check .ARM.IDX section #
        if SysMgr.dwarfEnable and e_sharmidx >= 0:
            # parse section header #
            (
                sh_name,
                sh_type,
                sh_flags,
                sh_addr,
                sh_offset,
                sh_size,
                sh_link,
                sh_info,
                sh_addralign,
                sh_entsize,
            ) = self.getSectionInfo(fd, e_shoff + e_shentsize * e_sharmidx)

            # refer to https://github.com/eliben/pyelftools #
            def _expandPrel31(address, place):
                location = address & 0x7FFFFFFF
                if location & 0x04000000:
                    location |= 0xFFFFFFFF80000000
                return location + place & 0xFFFFFFFFFFFFFFFF

            # refer to https://github.com/eliben/pyelftools #
            def _decodeEntry(
                self,
                idx,
                foffset,
                personality=None,
                bytecode=None,
                tableoffset=None,
                debug=False,
            ):

                # decode code #
                dobj = ElfAnalyzer.EHABIBytecodeDecoder(bytecode, self.path)

                if debug:
                    printer("Entry %s:" % idx)

                # get table offset #
                if personality == -1:
                    toffset = "[cantunwind]"
                elif foffset in self.addrTable:
                    toffset = self.addrTable[foffset]
                # fixed address code #
                elif foffset + self.loadAddr in self.addrTable:
                    foffset += self.loadAddr
                    toffset = self.addrTable[foffset]
                # THUMB code #
                elif foffset + 1 in self.addrTable:
                    toffset = self.addrTable[foffset + 1]
                elif tableoffset:
                    toffset = "@%s" % hex(tableoffset).rstrip("L")
                else:
                    toffset = "N/A"

                # register to CFA table #
                if foffset != 1:
                    self.attr["dwarf"]["CFAIndex"].append(foffset)
                    self.attr["dwarf"]["CFATable"][foffset] = [dobj.cfa_table]
                    self.attr["dwarf"]["CFATable"][foffset][0]["pc"] = foffset

                    # register stripped function info #
                    if (
                        not foffset in self.addrTable
                        or not self.addrTable[foffset]
                    ):
                        self.attr["dwarfTable"][hex(foffset)] = {
                            "value": foffset,
                            "size": 1,
                            "type": "FUNC",
                        }

                if debug:
                    printer(
                        " Function offset %s: %s"
                        % (hex(foffset).rstrip("L"), toffset)
                    )

                if personality == -1:
                    if debug:
                        printer("\n")
                    return

                if debug:
                    printer(" Compact model index: %s" % personality)

                    # print op code #
                    for line in dobj.mnemonic_array:
                        printer(" %s" % line)

                    printer("\n")

            self.attr.setdefault("dwarf", {})
            self.attr["dwarf"].setdefault("general", {})
            self.attr["dwarf"].setdefault("CFAIndex", [])
            self.attr["dwarf"].setdefault("CFATable", {})

            # define entry size #
            EHABI_INDEX_ENTRY_SIZE = 8

            # get the number of item #
            nrItems = long(sh_size / EHABI_INDEX_ENTRY_SIZE)

            # get symbol string #
            shname = self.getString(str_section, sh_name)

            if debug:
                printer("\n[%s Section]\n%s\n" % (shname, twoLine))

            for idx in xrange(nrItems):
                # read value #
                fd.seek(sh_offset + idx * EHABI_INDEX_ENTRY_SIZE)
                data = fd.read(EHABI_INDEX_ENTRY_SIZE)
                word0, word1 = struct.unpack("II", data)

                # check corruption #
                if word0 & 0x80000000 != 0:
                    SysMgr.printWarn(
                        "corrupted ARM exception handler entry: %x" % idx
                    )
                    continue

                foffset = _expandPrel31(
                    word0, sh_offset + (idx * EHABI_INDEX_ENTRY_SIZE)
                )

                if word1 == 1:
                    # 0x1 means cannot unwind #
                    _decodeEntry(self, idx, foffset, -1, debug=debug)
                    continue

                elif word1 & 0x80000000 == 0:
                    # highest bit is zero, point to .ARM.extab data
                    eh_table_offset = _expandPrel31(
                        word1, sh_offset + idx * EHABI_INDEX_ENTRY_SIZE + 4
                    )

                    # read value #
                    fd.seek(eh_table_offset)
                    data = fd.read(long(EHABI_INDEX_ENTRY_SIZE / 2))
                    word0 = struct.unpack("I", data)[0]

                    if word0 & 0x80000000 == 0:
                        # highest bit is one, generic model #
                        personality = _expandPrel31(word0, eh_table_offset)
                        _decodeEntry(
                            self, idx, foffset, personality, debug=debug
                        )

                    # highest bit is one, arm compact model #
                    # highest half must be 0b1000 for compact model #
                    if word0 & 0x70000000 != 0:
                        SysMgr.printWarn(
                            "corrupted ARM exception handler entry: %x" % idx
                        )
                        _decodeEntry(self, idx, 1)
                        continue

                    per_index = (word0 >> 24) & 0x7F
                    if per_index == 0:
                        # arm compact model 0 #
                        opcode = [
                            (word0 & 0xFF0000) >> 16,
                            (word0 & 0xFF00) >> 8,
                            word0 & 0xFF,
                        ]

                        _decodeEntry(
                            self, idx, foffset, per_index, opcode, debug=debug
                        )
                    elif per_index == 1 or per_index == 2:
                        # arm compact model 1/2 #
                        more_word = (word0 >> 16) & 0xFF
                        opcode = [(word0 >> 8) & 0xFF, (word0 >> 0) & 0xFF]

                        fd.seek(eh_table_offset + 4)

                        for i in xrange(more_word):
                            # read value #
                            data = fd.read(long(EHABI_INDEX_ENTRY_SIZE / 2))
                            r = struct.unpack("I", data)[0]
                            opcode.append((r >> 24) & 0xFF)
                            opcode.append((r >> 16) & 0xFF)
                            opcode.append((r >> 8) & 0xFF)
                            opcode.append((r >> 0) & 0xFF)

                        _decodeEntry(
                            self,
                            idx,
                            foffset,
                            per_index,
                            opcode,
                            eh_table_offset,
                            debug=debug,
                        )
                    else:
                        SysMgr.printWarn(
                            "unknown ARM compact model %d at entry: %x"
                            % (per_index, idx)
                        )
                        _decodeEntry(self, idx, 1)
                else:
                    # highest bit is one, compact model must be 0 #
                    if word1 & 0x7F000000 != 0:
                        SysMgr.printWarn(
                            "corrupted ARM compact model entry: %x" % idx
                        )
                        continue

                    opcode = [
                        (word1 & 0xFF0000) >> 16,
                        (word1 & 0xFF00) >> 8,
                        word1 & 0xFF,
                    ]

                    _decodeEntry(self, idx, foffset, 0, opcode, debug=debug)

            # sort address list for CFA #
            self.attr["dwarf"]["CFAIndex"].sort()

            if debug:
                printer(oneLine)

        def _readNoteSection(fd, offset, size):
            # set position #
            fd.seek(sh_offset)

            while 1:
                # read meta-data #
                namesz, descsz, ntype = struct.unpack("III", fd.read(12))

                # get name #
                if namesz > 0:
                    # 4-byte alignment #
                    nameszRemain = namesz % 4
                    if nameszRemain > 0:
                        namesz = namesz + 4 - nameszRemain

                    # read name #
                    name = fd.read(namesz).rstrip(b"\x00").decode()
                else:
                    name = "N/A"

                # get description #
                if descsz > 0:
                    # 4-byte alignment #
                    descszRemain = descsz % 4
                    if descszRemain > 0:
                        descsz = descsz + 4 - descszRemain

                    # read description #
                    desc = fd.read(descsz)

                    # convert description to bytes #
                    descstr = UtilMgr.convStr2Bytes(desc)
                else:
                    descstr = "N/A"

                printer(
                    "%20s %16s [type:%x] %s"
                    % (name, hex(descsz), ntype, descstr)
                )

                # align pos by 4 byte #
                pos = fd.tell()
                posRemain = pos % 4
                if posRemain > 0:
                    fd.seek(pos + 4 - posRemain)

                if sh_offset + size <= fd.tell():
                    break

            printer(oneLine)

        # check note sections #
        if debug:
            for sh_offset, size in e_notelist.items():
                # print note section title #
                printer(
                    "\n[Note %s Section]\n%s\n%20s %16s %s\n%s"
                    % (
                        hex(sh_offset).rstrip("L"),
                        twoLine,
                        "Owner",
                        "Data size",
                        "Description",
                        twoLine,
                    )
                )

                _readNoteSection(fd, sh_offset, size)

            # check .note sections #
            for name, idx in e_shnotelist.items():
                (
                    sh_name,
                    sh_type,
                    sh_flags,
                    sh_addr,
                    sh_offset,
                    sh_size,
                    sh_link,
                    sh_info,
                    sh_addralign,
                    sh_entsize,
                ) = self.getSectionInfo(fd, e_shoff + e_shentsize * idx)

                # get symbol string #
                shname = self.getString(str_section, sh_name)

                # print .note section title #
                printer(
                    "\n[%s Section]\n%s\n%20s %16s %s\n%s"
                    % (
                        shname,
                        twoLine,
                        "Owner",
                        "Data size",
                        "Description",
                        twoLine,
                    )
                )

                _readNoteSection(fd, sh_offset, sh_size)

        # check debug option #
        if not "DEBUGINFO" in SysMgr.environList or not SysMgr.dwarfEnable:
            debuginfo = False
        elif "DEBUGINFO" in SysMgr.environList:
            if (
                SysMgr.environList["DEBUGINFO"][0] == "SET"
                or self.path in SysMgr.environList["DEBUGINFO"]
                or origPath in SysMgr.environList["DEBUGINFO"]
            ):
                debuginfo = True
            else:
                debuginfo = False
        else:
            debuginfo = True

        # check debug_str section #
        if debuginfo and e_shdbgstr >= 0:
            (
                sh_name,
                sh_type,
                sh_flags,
                sh_addr,
                sh_offset,
                sh_size,
                sh_link,
                sh_info,
                sh_addralign,
                sh_entsize,
            ) = self.getSectionInfo(fd, e_shoff + e_shentsize * e_shdbgstr)

            # parse debug_str section #
            fd.seek(sh_offset)
            dbgstr_section = fd.read(sh_size)
        else:
            dbgstr_section = ""

        # check debug_line_str section #
        if debuginfo and e_shdbglinestr >= 0:
            (
                sh_name,
                sh_type,
                sh_flags,
                sh_addr,
                sh_offset,
                sh_size,
                sh_link,
                sh_info,
                sh_addralign,
                sh_entsize,
            ) = self.getSectionInfo(fd, e_shoff + e_shentsize * e_shdbglinestr)
            # parse debug_line_str section #
            fd.seek(sh_offset)
            dbglinestr_section = fd.read(sh_size)
        else:
            dbglinestr_section = ""

        # check debug_abbrev section #
        if debuginfo and e_shdbginfo >= 0:
            (
                sh_name,
                sh_type,
                sh_flags,
                sh_addr,
                sh_offset,
                sh_size,
                sh_link,
                sh_info,
                sh_addralign,
                sh_entsize,
            ) = self.getSectionInfo(fd, e_shoff + e_shentsize * e_shdbgabbrev)

            # get debug_abbrev string #
            shname = self.getString(str_section, sh_name)

            if debug:
                printer("\n[%s Section]\n%s" % (shname, twoLine))

            # set position #
            fd.seek(sh_offset)

            # decompress section #
            origFd = fd
            isCompressed = False
            if shname.startswith(".z"):
                decompSect, decompSize = UtilMgr.unzip(fd, shname)
                if decompSize:
                    isCompressed = True
                    origFd = fd
                    sh_size = decompSize
                    fd = MemoryFile(size=sh_offset + sh_size, name=shname)
                    fd.seek(sh_offset)
                    fd.write(decompSect)

            # init variables #
            idx = 0
            typeDict = [{}]
            abbrevDict = [{}]
            self.attr.setdefault("dwarf", {})
            self.attr["dwarf"]["info"] = {}
            self.attr["dwarf"]["abbrev"] = typeDict
            attrDict = {
                "DW_AT_byte_size": "size",
                "DW_AT_encoding": "encoding",
                "DW_AT_name": "name",
                "DW_AT_type": "type",
                "DW_AT_sibling": "sibling",
                "DW_AT_data_member_location": "offset",
                "DW_AT_const_value": "value",
                "DW_AT_frame_base": "frame",
                "DW_AT_location": "loc",
                "DW_AT_low_pc": "addr",
                "DW_AT_decl_file": "file",
                "DW_AT_decl_line": "line",
            }

            # data #
            pos = 0
            table = fd.read(sh_size)

            while 1:
                # check final end #
                if pos + 1 >= sh_size:
                    break

                # abbrev_code #
                data = table[pos : pos + 64].decode("latin-1")
                abbrevCode, nsize = UtilMgr.decodeULEB128(data)
                pos += nsize

                # create a new table #
                if abbrevCode == 0:
                    abbrevDict.append({})
                    typeDict.append({})
                    idx += 1
                    continue

                # tag #
                data = table[pos : pos + 64].decode("latin-1")
                tag, nsize = UtilMgr.decodeULEB128(data)
                pos += nsize

                # children_flag #
                childFlag = struct.unpack("B", table[pos : pos + 1])[0]
                pos += 1

                abbrevDict[idx][abbrevCode] = {
                    "tag": tag,
                    "child": childFlag,
                    "attrs": [],
                }

                while 1:
                    # name data #
                    data = table[pos : pos + 64].decode("latin-1")
                    name, nsize = UtilMgr.decodeULEB128(data)
                    pos += nsize

                    # form data #
                    data = table[pos : pos + 64].decode("latin-1")
                    form, nsize = UtilMgr.decodeULEB128(data)
                    pos += nsize

                    # check end #
                    if name == form == 0:
                        break

                    abbrevDict[idx][abbrevCode]["attrs"].append([name, form])

            if debug:
                printStr = "%4s     %s   [%s]\n" % ("Num", "TAG", "Child")
                printStr += "%s\n" % twoLine

                for idx in xrange(len(abbrevDict)):
                    printStr += "\n"
                    for name, value in abbrevDict[idx].items():
                        if value["child"]:
                            children = "has children"
                        else:
                            children = "no children"

                        # tag name #
                        if value["tag"] in ElfAnalyzer.DW_TAG_MAP:
                            tag = ElfAnalyzer.DW_TAG_MAP[value["tag"]]
                        else:
                            tag = None

                        printStr += "%4s     %s   [%s]\n" % (
                            name,
                            tag,
                            children,
                        )

                        for item in value["attrs"]:
                            # name #
                            if item[0] in ElfAnalyzer.DW_AT_MAP:
                                name = ElfAnalyzer.DW_AT_MAP[item[0]]
                            else:
                                name = "N/A"

                            # form #
                            if item[1] in ElfAnalyzer.DW_FORM_MAP:
                                form = ElfAnalyzer.DW_FORM_MAP[item[1]]
                            else:
                                form = "N/A"

                            printStr += "%4s %-20s %s\n" % (" ", name, form)

                printer(printStr)
                printer(oneLine)

            # recover original fd #
            if isCompressed:
                fd = origFd

        # parse debug_info section #
        if debuginfo and e_shdbginfo >= 0:
            (
                sh_name,
                sh_type,
                sh_flags,
                sh_addr,
                sh_offset,
                sh_size,
                sh_link,
                sh_info,
                sh_addralign,
                sh_entsize,
            ) = self.getSectionInfo(fd, e_shoff + e_shentsize * e_shdbginfo)

            def _decodeOp(value, dwarfFormat):
                if not value:
                    return None, None, ""

                # check opcode #
                op = value[0]
                if not op in ElfAnalyzer.DW_OPS_NAMES_MAP:
                    return None, None, ""

                opcode = ElfAnalyzer.DW_OPS_NAMES_MAP[op]

                # print data #
                if debug:
                    verbStr = "%s byte block: " % len(value)
                    verbStr += " ".join(list(map(hex, value)))
                else:
                    verbStr = None

                # convert value type to bytes #
                if not opcode in ElfAnalyzer.DW_OPS_NOARGS:
                    vals = bytes(value[1:])

                # decode value #
                opval = None
                if opcode in ElfAnalyzer.DW_OPS_NOARGS:
                    pass
                elif opcode == "DW_OP_addr":
                    if dwarfFormat == 32:
                        sig = "I"
                        sz = 4
                    else:
                        sig = "Q"
                        sz = 8
                    opval = unpack(sig, vals[:sz])[0]
                elif opcode in (
                    "DW_OP_addrx",
                    "DW_OP_constu",
                    "DW_OP_plus_uconst",
                    "DW_OP_regx",
                    "DW_OP_piece",
                    "DW_OP_GNU_convert",
                ):
                    opval, nsize = UtilMgr.decodeULEB128(vals)
                elif opcode in ("DW_OP_const1u", "DW_OP_pick"):
                    opval = unpack("B", vals[:1])[0]
                elif opcode in (
                    "DW_OP_const1s",
                    "DW_OP_deref_size",
                    "DW_OP_xderef_size",
                ):
                    opval = unpack("b", vals[:1])[0]
                elif opcode in ("DW_OP_const2u", "DW_OP_call2"):
                    opval = unpack("H", vals[:2])[0]
                elif opcode in ("DW_OP_const2s", "DW_OP_bra", "DW_OP_skip"):
                    opval = unpack("h", vals[:2])[0]
                elif opcode in ("DW_OP_const4u", "DW_OP_call4"):
                    opval = unpack("I", vals[:4])[0]
                elif opcode == "DW_OP_const4s":
                    opval = unpack("i", vals[:4])[0]
                elif opcode == "DW_OP_const8u":
                    opval = unpack("Q", vals[:8])[0]
                elif opcode == "DW_OP_const8s":
                    opval = unpack("q", vals[:8])[0]
                elif opcode in ("DW_OP_call_ref", "DW_OP_GNU_parameter_ref"):
                    # TODO: implement more #
                    if dwarfFormat == 32:
                        sig = "I"
                        sz = 4
                    else:
                        sig = "Q"
                        sz = 8
                    opval = unpack(sig, vals[:sz])[0]
                elif opcode in (
                    "DW_OP_fbreg",
                    "DW_OP_consts",
                ) or opcode.startswith("DW_OP_breg"):
                    vals = vals.decode("latin-1")
                    opval, nsize = UtilMgr.decodeSLEB128(vals)
                elif opcode == "DW_OP_GNU_entry_value":
                    osize, nsize = UtilMgr.decodeULEB128(vals)
                    olist = vals[nsize : nsize + osize]
                    if olist:
                        for b in olist:
                            b = b if type(b) == long else ord(b)
                            if not b in ElfAnalyzer.DW_OPS_NAMES_MAP:
                                break
                            opval = ElfAnalyzer.DW_OPS_NAMES_MAP[b]
                            # TODO: implement nested code parser #
                            break
                elif opcode == "DW_OP_implicit_value":
                    osize, nsize = UtilMgr.decodeULEB128(vals)
                    # TODO: read blob of osize #
                elif opcode == "DW_OP_bregx":
                    try:
                        osize, nsize = UtilMgr.decodeULEB128(vals)
                        osize, nsize = UtilMgr.decodeSLEB128(vals[osize:])
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass
                else:
                    # TODO: implement more opcodes #
                    """
                    elif opcode == 'DW_OP_bit_piece':
                    elif opcode == 'DW_OP_GNU_regval_type':
                    elif opcode == 'DW_OP_GNU_implicit_pointer':
                    elif opcode == 'DW_OP_GNU_const_type':
                    elif opcode == 'DW_OP_GNU_deref_type':
                    """
                    SysMgr.printWarn(
                        "failed to decode '%s' because no implementation"
                        % opcode
                    )

                # print data expression #
                if debug:
                    if opval and not opcode in ElfAnalyzer.DW_OPS_DEC_ARGS:
                        try:
                            opval = hex(opval)
                        except SystemExit:
                            sys.exit(0)
                        except:
                            pass

                    verbStr += " (%s%s)" % (
                        opcode,
                        ": %s" % opval if opval else "",
                    )

                return opcode, opval, verbStr

            # get symbol string #
            shname = self.getString(str_section, sh_name)

            if debug:
                printer("\n[%s Section]\n%s" % (shname, twoLine))

            # set position #
            fd.seek(sh_offset)

            # decompress section #
            origFd = fd
            isCompressed = False
            if shname.startswith(".z"):
                decompSect, decompSize = UtilMgr.unzip(fd, shname)
                if decompSize:
                    isCompressed = True
                    origFd = fd
                    sh_size = decompSize
                    fd = MemoryFile(size=sh_offset + sh_size, name=shname)
                    fd.seek(sh_offset)
                    fd.write(decompSect)

            # init variables #
            pos = 0
            idx = -1
            error = False
            pack = struct.pack
            unpack = struct.unpack
            decULEB = UtilMgr.decodeULEB128
            decSLEB = UtilMgr.decodeSLEB128
            lstrip = UtilMgr.lstrip
            table = fd.read(sh_size)

            while 1:
                # check final end #
                if pos >= sh_size:
                    break

                # pos variables #
                parentPos = None
                posStack = []

                # length #
                size = unpack("I", table[pos : pos + 4])[0]
                pos += 4
                addrPos = 4
                # extended length 8 bytes are needed #
                if size == 0xFFFFFFFF:
                    size = unpack("Q", table[pos : pos + 8])[0]
                    pos += 8
                    addrPos += 8

                # format #
                dwarfFormat = 64 if size == 0xFFFFFFFF else 32

                # data #
                startPos = pos
                endPos = startPos + size

                # version #
                ver = unpack("H", table[pos : pos + 2])[0]
                pos += 2

                if ver >= 5:
                    # unit type #
                    unitType = unpack("B", table[pos : pos + 1])[0]
                    pos += 1

                    # address size #
                    addrSize = unpack("B", table[pos : pos + 1])[0]
                    pos += 1

                    # debug_abbrev_offset #
                    if dwarfFormat == 32:
                        dao = unpack("I", table[pos : pos + 4])[0]
                        pos += 4
                    else:
                        dao = unpack("Q", table[pos : pos + 8])[0]
                        pos += 8
                else:
                    # unit type #
                    unitType = None

                    # debug_abbrev_offset #
                    if dwarfFormat == 32:
                        dao = unpack("I", table[pos : pos + 4])[0]
                        pos += 4
                    else:
                        dao = unpack("Q", table[pos : pos + 8])[0]
                        pos += 8

                    # address size #
                    addrSize = unpack("B", table[pos : pos + 1])[0]
                    pos += 1

                # print #
                if debug:
                    printStr = "\nCompilation Unit @ offset 0x%x\n" % (
                        startPos - addrPos
                    )
                    printStr += "%-13s: 0x%x (%s-Bit)\n" % (
                        "Length",
                        size,
                        dwarfFormat,
                    )
                    printStr += "%-13s: %s\n" % ("Version", ver)
                    printStr += "%-13s: 0x%x\n" % ("Abbrev Offset", dao)
                    printStr += "%-13s: %s\n" % ("Pointer Size", addrSize)
                    if unitType:
                        addStr = (
                            ElfAnalyzer.DW_UT_MAP[unitType]
                            if unitType in ElfAnalyzer.DW_UT_MAP
                            else ""
                        )
                        addStr = " (%s)" % addStr if addStr else ""
                        printStr += "%-13s: %s%s\n" % (
                            "Unit Type",
                            unitType,
                            addStr,
                        )
                    printer(printStr)
                    printStr = "\n"

                # update variables #
                depth = 0
                if idx + 1 < len(abbrevDict):
                    idx += 1

                while 1:
                    # abbrev_code #
                    data = table[pos : pos + 64].decode("latin-1")
                    abbrevCode, nsize = decULEB(data)
                    origPos = pos
                    pos += nsize

                    # check end #
                    if abbrevCode == 0:
                        depth -= 1
                        if posStack:
                            parentPos = posStack.pop()
                        else:
                            parentPos = None

                        # print #
                        if debug:
                            printer(
                                " <%s><%x>: Abbrev Number: %s"
                                % (depth + 1, origPos, abbrevCode)
                            )

                        # check depth #
                        if depth == 0:
                            break
                        else:
                            continue

                    try:
                        # get a DIE #
                        if not abbrevCode in abbrevDict[idx]:
                            raise Exception("no table")
                        value = abbrevDict[idx][abbrevCode]
                        tagid = value["tag"]
                        tag = ElfAnalyzer.DW_TAG_MAP[tagid]
                        child = value["child"]
                        attrs = value["attrs"]

                        # print #
                        if debug:
                            printStr = (
                                " <%s><%x>: Abbrev Number: %s (%s)\n"
                                % (depth, origPos, abbrevCode, tag)
                            )

                        # increase depth #
                        if child:
                            depth += 1
                            if parentPos:
                                posStack.append(parentPos)
                            parentPos = origPos

                        # register variable type #
                        typeAttr = typeDict[idx][origPos] = {"type": tagid}

                        # register member/formal_parameter to parent #
                        if tagid in (0x0D, 0x05, 0x34):
                            # set name #
                            if tagid == 0x0D:
                                arg = "member"
                            elif tagid == 0x05:
                                arg = "param"
                            elif tagid == 0x34:
                                arg = "var"

                            # register value #
                            typeAttr["parent"] = parentPos
                            if parentPos in typeDict[idx]:
                                parent = typeDict[idx][parentPos]
                                parent.setdefault(arg, [])
                                parent[arg].append(origPos)

                        # get data from FORM attributes #
                        for attr in attrs:
                            addStr = ""

                            # name #
                            at = attr[0]
                            if at in ElfAnalyzer.DW_AT_MAP:
                                name = ElfAnalyzer.DW_AT_MAP[at]
                            else:
                                name = "Unknown AT"

                            # form #
                            form = attr[1]
                            if form in ElfAnalyzer.DW_FORM_MAP:
                                formstr = ElfAnalyzer.DW_FORM_MAP[form]
                            elif form in ElfAnalyzer.DW_AT_MAP:
                                formstr = ElfAnalyzer.DW_AT_MAP[form]
                            else:
                                raise Exception("no form")

                            # save original pos #
                            origPos = pos

                            # addr #
                            if form == 0x1:
                                sig = "I" if addrSize == 32 else "Q"
                                value = unpack(
                                    sig, table[pos : pos + addrSize]
                                )[0]
                                pos += addrSize
                            # addrx/udata/ref_udata/indirect #
                            elif form in (0x1B, 0x0F, 0x15, 0x16):
                                data = table[pos : pos + 64].decode("latin-1")
                                value, nsize = decULEB(data)
                                pos += nsize
                            # addrx1/data1/strx1/flag/ref1 #
                            elif form in (0x25, 0x0B, 0x25, 0x0C, 0x11):
                                value = unpack("B", table[pos : pos + 1])[0]
                                pos += 1
                            # addrx2/data2/strx2/ref2 #
                            elif form in (0x26, 0x05, 0x26, 0x12):
                                value = unpack("H", table[pos : pos + 2])[0]
                                pos += 2
                            # addrx3 #
                            elif form == 0x27:
                                value = unpack("3B", table[pos : pos + 3])[0]
                                pos += 3
                            # addrx4/data4/strx4/ref/ref4 #
                            elif form in (0x28, 0x06, 0x28, 0x02, 0x13):
                                value = unpack("I", table[pos : pos + 4])[0]
                                pos += 4
                            # data8/ref8/ref_sig8 #
                            elif form in (0x07, 0x14, 0x20):
                                value = unpack("Q", table[pos : pos + 8])[0]
                                pos += 8
                            # block/block1/block2/block4 #
                            elif form in (0x09, 0x0A, 0x03, 0x04):
                                # block1 #
                                if form == 0x0A:
                                    sig = "B"
                                    bsize = 1
                                # block2 #
                                elif form == 0x03:
                                    sig = "H"
                                    bsize = 2
                                # block4 #
                                elif form == 0x04:
                                    sig = "I"
                                    bsize = 4

                                # block #
                                if form == 0x9:
                                    data = table[pos : pos + 64].decode(
                                        "latin-1"
                                    )
                                    sz, nsize = decULEB(data)
                                    pos += nsize
                                else:
                                    # get size #
                                    sz = unpack(sig, table[pos : pos + bsize])[
                                        0
                                    ]
                                    pos += bsize

                                # get data #
                                value = table[pos : pos + sz]
                                pos += sz
                                value = unpack("B" * sz, value)

                                # decode data #
                                opcode, opval, verbStr = _decodeOp(
                                    value, dwarfFormat
                                )
                                if verbStr:
                                    addStr += verbStr
                            # sdata #
                            elif form == 0x0D:
                                data = table[pos : pos + 64].decode("latin-1")
                                value, nsize = decSLEB(data)
                                pos += nsize
                            # string #
                            elif form == 0x08:
                                # convert string #
                                value, sz = self.getString(
                                    table[pos:], retlen=True
                                )
                                pos += sz + 1
                            # strp/sec_offset/line_strp/strp_alt/ref_alt #
                            elif form in (0x0E, 0x17, 0x1F, 0x1F21, 0x1F20):
                                if dwarfFormat == 32:
                                    value = unpack("I", table[pos : pos + 4])[
                                        0
                                    ]
                                    pos += 4
                                else:
                                    value = unpack("Q", table[pos : pos + 8])[
                                        0
                                    ]
                                    pos += 8

                                # strp #
                                if form == 0x0E:
                                    value = self.getString(
                                        dbgstr_section, value
                                    )
                                # line_strp #
                                elif form == 0x1F:
                                    value = self.getString(
                                        dbglinestr_section, value
                                    )
                            # strx3 #
                            elif form == 0x27:
                                value = unpack("3B", table[pos : pos + 3])[0]
                                pos += 3
                            # ref_addr #
                            elif form == 0x10:
                                if ver == 2:
                                    sig = "I" if addrSize == 32 else "Q"
                                    value = unpack(
                                        sig, table[pos : pos + addrSize]
                                    )[0]
                                    pos += addrSize
                                elif dwarfFormat == 32:
                                    value = unpack("I", table[pos : pos + 4])[
                                        0
                                    ]
                                    pos += 4
                                else:
                                    value = unpack("Q", table[pos : pos + 8])[
                                        0
                                    ]
                                    pos += 8
                            # exprloc #
                            elif form == 0x18:
                                # get size #
                                data = table[pos : pos + 64].decode("latin-1")
                                sz, nsize = decULEB(data)
                                pos += nsize

                                # get data #
                                value = table[pos : pos + sz]
                                pos += sz
                                value = list(
                                    map(long, unpack("B" * sz, value))
                                )

                                # decode data #
                                opcode, opval, verbStr = _decodeOp(
                                    value, dwarfFormat
                                )
                                if verbStr:
                                    addStr += verbStr
                            # flag_present #
                            elif form == 0x19:
                                value = 1
                            else:
                                SysMgr.printErr(
                                    (
                                        "failed to recognize %s(0x%x) attributes "
                                        "from debug_info"
                                    )
                                    % (form, form),
                                    True,
                                )
                                sys.exit(-1)

                            # add variable attributes #
                            if typeAttr and name in attrDict:
                                typeAttr[attrDict[name]] = value
                                # subprogram #
                                if tagid == 0x2E and at == 0x11:
                                    dwarfInfo = self.attr["dwarf"]["info"]
                                    dwarfInfo[value] = typeAttr
                                    dwarfInfo[value]["abbrev"] = idx
                                # pointer type #
                                elif tagid == 0x0F:
                                    typeAttr["name"] = "*"
                                # const type #
                                elif tagid == 0x26:
                                    typeAttr["name"] = "const"
                                # location #
                                elif at == 0x40:
                                    typeAttr["frame"] = opcode
                                # location #
                                elif at == 0x02:
                                    # exprloc #
                                    if form == 0x18:
                                        typeAttr["loc"] = [opcode, opval]
                                    # sec_offset #
                                    elif form == 0x17:
                                        typeAttr["loc"] = value

                            # print #
                            if debug:
                                # type/sibling/abstract_origin #
                                if at in (0x49, 0x01, 0x31):
                                    try:
                                        addStr += "<0x%x>" % value
                                    except SystemExit:
                                        sys.exit(0)
                                    except:
                                        pass
                                # low_pc/high_pc/ranges/location #
                                elif at in (0x11, 0x12, 0x55, 0x02):
                                    try:
                                        addStr += hex(value)
                                    except SystemExit:
                                        sys.exit(0)
                                    except:
                                        pass
                                # language #
                                elif at == 0x13:
                                    if value in ElfAnalyzer.DW_LANG_MAP:
                                        lang = ElfAnalyzer.DW_LANG_MAP[value]
                                        addStr += lstrip(lang, "DW_LANG_")
                                # encoding #
                                elif at == 0x3E:
                                    if value in ElfAnalyzer.DW_ATE_MAP:
                                        enc = ElfAnalyzer.DW_ATE_MAP[value]
                                        addStr += "%s (%s)" % (
                                            value,
                                            lstrip(enc, "DW_ATE_"),
                                        )

                                helper = addStr if addStr else value
                                printStr += "    <%x>   %-18s: %s" % (
                                    origPos,
                                    name,
                                    helper,
                                )
                                printer(printStr)
                                printStr = ""
                    except SystemExit:
                        sys.exit(0)
                    except:
                        error = True
                        SysMgr.printErr(
                            (
                                "failed to get %s(0x%x) attributes "
                                "from debug_info"
                            )
                            % (abbrevCode, abbrevCode),
                            True,
                        )
                        break

                    # check end #
                    if pos >= endPos:
                        break

                # check error #
                if error:
                    break

            if debug:
                printer("%s\n" % oneLine)
                if "DEBUGINFODICT" in SysMgr.environList:
                    SysMgr.printPipe(
                        UtilMgr.convDict2Str(typeDict, pretty=True)
                    )

            # recover original fd #
            if isCompressed:
                fd = origFd

        # remove useless data #
        del self.attr["dynsymList"]
        del self.attr["versymList"]

        # check dynamic section #
        if e_shdynamic < 0:
            return None

        # parse dynamic section #
        (
            sh_name,
            sh_type,
            sh_flags,
            sh_addr,
            sh_offset,
            sh_size,
            sh_link,
            sh_info,
            sh_addralign,
            sh_entsize,
        ) = self.getSectionInfo(fd, e_shoff + e_shentsize * e_shdynamic)

        fd.seek(sh_offset)
        dynamic_section = fd.read(sh_size)

        if debug:
            printer(
                ("\n[.dynamic Section]\n%s\n%16s %20s %1s\n%s")
                % (twoLine, "Tag", "Type", "Value", twoLine)
            )

        nrItems = long(sh_size / sh_entsize)
        if nrItems == 0:
            printer("\tNone")

        for i in xrange(nrItems):
            fd.seek(sh_offset + i * sh_entsize)

            if self.is32Bit:
                d_tag, d_un = struct.unpack("II", fd.read(sh_entsize))
            else:
                d_tag, d_un = struct.unpack("QQ", fd.read(sh_entsize))

            # NULL termination #
            if d_tag == d_un == 0:
                break

            if not debug:
                continue

            if d_tag in ElfAnalyzer.DT_TYPE:
                if (
                    ElfAnalyzer.DT_TYPE[d_tag] == "NEEDED"
                    or ElfAnalyzer.DT_TYPE[d_tag] == "SONAME"
                    or ElfAnalyzer.DT_TYPE[d_tag] == "RPATH"
                ):
                    printer(
                        "%016x %20s %1s"
                        % (
                            d_tag,
                            ElfAnalyzer.DT_TYPE[d_tag],
                            dynsymTable[d_un],
                        )
                    )
                elif (
                    ElfAnalyzer.DT_TYPE[d_tag] == "STRSZ"
                    or ElfAnalyzer.DT_TYPE[d_tag] == "SYMENT"
                    or ElfAnalyzer.DT_TYPE[d_tag] == "RELSZ"
                    or ElfAnalyzer.DT_TYPE[d_tag] == "RELENT"
                    or ElfAnalyzer.DT_TYPE[d_tag] == "PLTRELSZ"
                    or ElfAnalyzer.DT_TYPE[d_tag] == "VERDEFNUM"
                    or ElfAnalyzer.DT_TYPE[d_tag] == "VERNEEDNUM"
                    or ElfAnalyzer.DT_TYPE[d_tag] == "RELCOUNT"
                ):
                    printer(
                        "%016x %20s %1s"
                        % (d_tag, ElfAnalyzer.DT_TYPE[d_tag], d_un)
                    )
                else:
                    printer(
                        "%016x %20s %1s"
                        % (d_tag, ElfAnalyzer.DT_TYPE[d_tag], hex(d_un))
                    )
            else:
                printer("%016x %20s %1s" % (d_tag, d_tag, hex(d_un)))

        if debug:
            printer("%s\n\n\n" % oneLine)


class TaskAnalyzer(object):
    """Analyzer for thread profiling"""

    reportData = {}
    lifeIntData = {}
    lifeProcData = {}
    lifecycleData = {}
    procTotData = {}
    procIntData = []
    procEventData = []
    dbusData = {"totalCnt": 0, "totalErr": 0}
    dbgObj = None

    # request type #
    requestType = ["LOG", "EVENT", "PRINT", "REPORT", "THRESHOLD"]

    init_procTotData = {
        "comm": "",
        "ppid": 0,
        "nrThreads": 0,
        "pri": "",
        "startIdx": 0,
        "cpu": 0,
        "cpuMax": 0,
        "cpuMin": -1,
        "cpuAvg": 0,
        "dly": 0,
        "initMem": 0,
        "lastMem": 0,
        "memDiff": 0,
        "minMem": 0,
        "maxMem": 0,
        "minVss": 0,
        "maxVss": 0,
        "blk": 0,
        "blkrd": 0,
        "blkwr": 0,
    }

    init_procIntData = {
        "cpu": 0,
        "cpuMax": 0,
        "cpuMin": -1,
        "cpuAvg": 0,
        "dly": 0,
        "mem": 0,
        "memDiff": 0,
        "blk": 0,
        "blkrd": 0,
        "blkwr": 0,
        "die": False,
    }

    @staticmethod
    def checkFilter(comm, pid):
        found = False

        if UtilMgr.isValidStr(comm.strip("*")):
            return True

        for idx in list(SysMgr.filterGroup):
            # check exclusion condition #
            if idx.startswith("^"):
                cond = idx[1:]
                if pid == cond or UtilMgr.isValidStr(comm, [cond]):
                    found = False
                    break
                else:
                    found = True
                    continue

            # check inclusion condition #
            if pid == idx:
                found = True
                break

        return found

    @staticmethod
    def getSummaryData(fname):
        # load file #
        SysMgr.reloadFileBuffer(fname)

        # recognize data #
        start = end = -1
        reverse = True
        for idx, item in enumerate(SysMgr.procBuffer):
            if "Top Summary Info" in item:
                reverse = False
            if start == -1 and "[Top Info] " in item:
                start = idx
            if start >= 0 and not "[Top Info]" in item:
                end = idx
                break

        # check data #
        if start == end == -1:
            SysMgr.printErr("failed to recognize %s" % fname)
            sys.exit(-1)

        # check data #
        SysMgr.procBuffer = SysMgr.procBuffer[start:end]

        # reverse sequence #
        if reverse:
            SysMgr.procBuffer = list(reversed(SysMgr.procBuffer))

        return SysMgr.procBuffer

    @staticmethod
    def doSumReport(flist):
        def _printSummary(fdata, onlyTotal, onlySummary):
            SysMgr.printLogo(big=True, onlyFile=True)

            # update proc buffer #
            SysMgr.procBuffer = fdata

            # print summary #
            try:
                SysMgr.printStat("start summarizing...")

                TaskAnalyzer.printIntervalUsage(onlyTotal, onlySummary)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "failed to print interval summary", reason=True
                )
                return

            # close all files #
            SysMgr.closeAllForPrint()

        if not flist:
            SysMgr.printErr("no input file")
            sys.exit(-1)

        # get ONLYTOTAL flag #
        if "ONLYTOTAL" in SysMgr.environList:
            onlyTotal = True
        else:
            onlyTotal = False

        # get ONLYSUMMARY flag #
        if "ONLYSUMMARY" in SysMgr.environList:
            onlySummary = True
        else:
            onlySummary = False

        # get NOMERGE flag #
        if "NOMERGE" in SysMgr.environList:
            merge = False
        else:
            merge = True

        # merge files #
        fdata = []
        if "REVERSEFILE" in SysMgr.environList:
            flist = reversed(flist)
        else:
            flist = sorted(flist)

        for fname in flist:
            # update output file #
            SysMgr.inputFile = fname

            # get file size #
            fsize = UtilMgr.getFileSizeStr(fname)

            SysMgr.printStat("start loading '%s'%s" % (fname, fsize))

            # summarize data #
            data = TaskAnalyzer.getSummaryData(fname)
            if not "REVERSESAMPLE" in SysMgr.environList:
                data.reverse()

            # no merge #
            if not merge:
                _printSummary(data, onlyTotal, onlySummary)
                continue

            # remove redundant data #
            newData = []
            for item in data:
                if item in fdata:
                    continue
                newData.append(item)

            # merge data #
            fdata = newData + fdata

        if merge:
            _printSummary(fdata, onlyTotal, onlySummary)

    @staticmethod
    def doDiffReports(flist):
        def _getProcName(pinfo):
            namelist = pinfo.split("(")
            if len(namelist) <= 2:
                if namelist[0] == "":
                    return "(%s" % namelist[1]
                return namelist[0]
            else:
                return "(%s" % "".join(namelist[:-1])

        # enable RSS flag #
        SysMgr.rssEnable = True

        # get stats from files #
        flist = UtilMgr.getFileList(flist, exceptDir=True)
        if not flist:
            SysMgr.printErr("no input for path")
            sys.exit(-1)

        # define variable and table #
        nrFiles = len(flist)
        unionCpuList = {}
        unionGpuList = {}
        unionRssList = {}
        statFileList = {}

        # get diff type #
        if SysMgr.cpuAvgEnable:
            item = "average"
            diffType = "AvgDiff"
        else:
            item = "total"
            diffType = "TotDiff"

        # parse stats from multiple files #
        for idx, lfile in enumerate(flist):
            try:
                gstats, cstats = TaskAnalyzer.getStatsFile(
                    lfile, applyOpt=False
                )
            except SystemExit:
                sys.exit(0)
            except:
                sys.exit(-1)

            # save all stats in a file #
            statFileList[lfile] = gstats

            # define proc usage #
            cpuProcUsage = gstats["cpuProcUsage"]
            memProcUsage = gstats["memProcUsage"]
            gpuProcUsage = gstats["gpuProcUsage"] = {}

            # get total CPU info #
            cpuUsage = gstats["cpuUsage"]
            if not cpuUsage:
                break
            cpuProcUsage["TOTAL"] = {
                "usage": cpuUsage,
                "average": sum(cpuUsage) / float(len(cpuUsage)),
                "minimum": min(cpuUsage),
                "maximum": max(cpuUsage),
            }

            # get total GPU info #
            gpuProcUsage = gstats["gpuUsage"]

            # get total free info #
            memFree = gstats["memFree"]
            memProcUsage["FREE"] = {
                "rssUsage": memFree,
                "average": sum(memFree) / len(memFree),
                "minRss": min(memFree),
                "maxRss": max(memFree),
            }

            # remove * characters #
            for pinfo in sorted(cpuProcUsage):
                if pinfo.startswith("*"):
                    cpuProcUsage[pinfo[1:]] = cpuProcUsage.pop(pinfo)
                else:
                    break

            # merge tasks having same name #
            prevTask = None
            for pinfo in sorted(cpuProcUsage):
                pname = _getProcName(pinfo)

                # convert usage string to list #
                try:
                    cpuProcUsage[pinfo]["usage"] = list(
                        map(long, cpuProcUsage[pinfo]["usage"].split())
                    )
                except:
                    pass

                # register the first task #
                if prevTask != pname:
                    prevTask = pname

                    target = cpuProcUsage[pinfo]
                    cpuProcUsage.setdefault(pname, target)
                    target["cnt"] = 1
                    target["total"] = sum(target["usage"])
                    target["average"] = target["total"] / float(
                        len(target["usage"])
                    )
                    if "(" in pinfo:
                        cpuProcUsage.pop(pinfo)

                    continue

                # merge tasks #
                target = cpuProcUsage[pname]
                target["usage"] = list(
                    map(
                        sum,
                        zip(*[target["usage"], cpuProcUsage[pinfo]["usage"]]),
                    )
                )

                # update stats #
                target["cnt"] += 1
                target["minimum"] = min(target["usage"])
                target["maximum"] = max(target["usage"])
                target["total"] = sum(target["usage"])
                target["average"] = target["total"] / float(
                    len(target["usage"])
                )

                # pop this task #
                if "(" in pinfo:
                    cpuProcUsage.pop(pinfo)

            # iterate CPU list #
            for pinfo, value in sorted(cpuProcUsage.items()):
                if not cpuProcUsage:
                    break

                pname = _getProcName(pinfo)

                # register comm #
                unionCpuList.setdefault("TOTAL", 0)
                unionCpuList.setdefault(pname, 0)

                # save diff itself #
                if idx > 0:
                    targetList = {}
                    prevProcList = statFileList[flist[idx - 1]]["cpuProcUsage"]

                    for proc, pval in prevProcList.items():
                        if _getProcName(proc) == pname:
                            targetList.setdefault(pname, pval)

                    # get diff #
                    if not targetList:
                        value["diff"] = value[item]
                    elif len(targetList) == 1:
                        target = targetList.popitem()[1]
                        value["diff"] = value[item] - target[item]
                    else:
                        pass

            # set diff to the union list if this file is latest one #
            if nrFiles == 1:
                cpuStats = statFileList[lfile]["cpuProcUsage"]
                for pname in list(unionCpuList):
                    try:
                        unionCpuList[pname] = cpuStats[pname]["average"]
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass
            elif idx == nrFiles - 1 and nrFiles > 1:
                prevProcList = statFileList[flist[-2]]["cpuProcUsage"]
                lastProcList = statFileList[flist[-1]]["cpuProcUsage"]
                for pname, value in unionCpuList.items():
                    if pname in lastProcList:
                        try:
                            unionCpuList[pname] = (
                                lastProcList[pname]["average"]
                                - prevProcList[pname]["average"]
                            )
                        except:
                            unionCpuList[pname] = lastProcList[pname][
                                "average"
                            ]
                    elif pname in prevProcList:
                        unionCpuList[pname] = -(prevProcList[pname]["average"])

            # remove * characters #
            for pinfo in sorted(gpuProcUsage):
                if pinfo.startswith("*"):
                    gpuProcUsage[pinfo[1:]] = gpuProcUsage.pop(pinfo)
                else:
                    break

            # merge tasks having same name #
            prevTask = None
            for pinfo in sorted(gpuProcUsage):
                pname = _getProcName(pinfo)

                # convert usage string to list #
                try:
                    gusage = list(map(long, gpuProcUsage[pinfo].split()))
                    gpuProcUsage[pinfo] = {"usage": gusage}
                    gstats["gpuProcUsage"][pinfo] = gpuProcUsage[pinfo]
                except:
                    pass

                # register the first task #
                if prevTask != pname:
                    prevTask = pname

                    target = gpuProcUsage[pinfo]
                    target["cnt"] = 1
                    target["minimum"] = min(target["usage"])
                    target["maximum"] = max(target["usage"])
                    target["total"] = sum(target["usage"])
                    target["average"] = target["total"] / float(
                        len(target["usage"])
                    )

                    gpuProcUsage.setdefault(pname, target)

                    if "(" in pinfo:
                        gpuProcUsage.pop(pinfo)

                    continue

                # merge tasks #
                target = gpuProcUsage[pname]
                target["usage"] = list(
                    map(
                        sum,
                        zip(*[target["usage"], gpuProcUsage[pinfo]["usage"]]),
                    )
                )

                # update stats #
                target["cnt"] += 1
                target["minimum"] = min(target["usage"])
                target["maximum"] = max(target["usage"])
                target["total"] = sum(target["usage"])
                target["average"] = target["total"] / float(
                    len(target["usage"])
                )

                # pop this task #
                if "(" in pinfo:
                    gpuProcUsage.pop(pinfo)

            # iterate GPU list #
            for pinfo, value in gpuProcUsage.items():
                pname = _getProcName(pinfo)

                # register comm #
                unionGpuList.setdefault(pname, 0)

                # save diff itself #
                if idx > 0:
                    targetList = {}
                    prevProcList = statFileList[flist[idx - 1]]["gpuProcUsage"]

                    for proc, pval in prevProcList.items():
                        if _getProcName(proc) == pname:
                            targetList.setdefault(proc, pval)

                    # get diff #
                    if not targetList:
                        value["diff"] = value[item]
                    elif len(targetList) == 1:
                        target = targetList.popitem()[1]
                        value["diff"] = value[item] - target[item]
                    else:
                        pass

                # set diff to the union list if this file is latest one #
                if nrFiles == 1:
                    gpuStats = statFileList[lfile]["gpuProcUsage"]
                    for pname in list(unionGpuList):
                        try:
                            unionGpuList[pname] = gpuStats[pname]["average"]
                        except SystemExit:
                            sys.exit(0)
                        except:
                            pass
                elif idx == nrFiles and nrFiles > 1:
                    unionGpuList[pname] = value["diff"]

            # remove * characters #
            for pinfo in sorted(memProcUsage):
                if pinfo.startswith("*"):
                    memProcUsage[pinfo[1:]] = memProcUsage.pop(pinfo)
                else:
                    break

            # merge tasks having same name #
            prevTask = None
            for pinfo in sorted(memProcUsage):
                pname = _getProcName(pinfo)

                # convert usage string to list #
                try:
                    rssList = memProcUsage[pinfo]["rssUsage"]
                    if type(rssList) is str:
                        rssList = rssList.split()
                    memProcUsage[pinfo]["rssUsage"] = list(map(long, rssList))
                except:
                    continue

                # register the first task #
                if prevTask != pname:
                    prevTask = pname

                    target = memProcUsage[pinfo]
                    memProcUsage.setdefault(pname, target)
                    target["cnt"] = 1
                    target["minRss"] = min(target["rssUsage"])
                    target["maxRss"] = max(target["rssUsage"])
                    target["avgRss"] = sum(target["rssUsage"]) / len(
                        target["rssUsage"]
                    )
                    if "(" in pinfo:
                        memProcUsage.pop(pinfo)

                    continue

                # merge tasks #
                target = memProcUsage[pname]
                target["rssUsage"] = list(
                    map(
                        sum,
                        zip(
                            *[
                                target["rssUsage"],
                                memProcUsage[pinfo]["rssUsage"],
                            ]
                        ),
                    )
                )

                # update stats #
                target["cnt"] += 1
                target["minRss"] = min(target["rssUsage"])
                target["maxRss"] = max(target["rssUsage"])
                target["avgRss"] = sum(target["rssUsage"]) / len(
                    target["rssUsage"]
                )

                # pop this task #
                if "(" in pinfo:
                    memProcUsage.pop(pinfo)

            # iterate rss list #
            for pinfo, value in memProcUsage.items():
                pname = _getProcName(pinfo)

                # register comm #
                unionRssList.setdefault("FREE", 0)
                unionRssList.setdefault(pname, 0)

                # set stat #
                if pname == "FREE":
                    stat = "minRss"
                else:
                    stat = "maxRss"

                # save diff itself #
                if idx > 0:
                    targetList = {}
                    prevProcList = statFileList[flist[idx - 1]]["memProcUsage"]

                    for proc, pval in prevProcList.items():
                        if _getProcName(proc) == pname:
                            targetList.setdefault(proc, pval)

                    # get diff by average #
                    try:
                        if not targetList:
                            if stat in value:
                                value["diff"] = value[stat]
                        elif len(targetList) == 1:
                            target = targetList.popitem()[1]
                            if stat in value:
                                value["diff"] = value[stat] - target[stat]
                        else:
                            pass
                    except:
                        continue

            # set diff to the union list if this file is latest one #
            if nrFiles == 1:
                memStats = statFileList[lfile]["memProcUsage"]
                for pname in list(unionRssList):
                    try:
                        unionRssList[pname] = memStats[pname]["maxRss"]
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass
            elif idx == nrFiles - 1 and nrFiles > 1:
                prevProcList = statFileList[flist[-2]]["memProcUsage"]
                lastProcList = statFileList[flist[-1]]["memProcUsage"]
                for pname, value in unionRssList.items():
                    # set stat #
                    if pname == "FREE":
                        stat = "minRss"
                    else:
                        stat = "maxRss"

                    if pname in lastProcList:
                        try:
                            unionRssList[pname] = (
                                lastProcList[pname][stat]
                                - prevProcList[pname][stat]
                            )
                        except:
                            unionRssList[pname] = lastProcList[pname][stat]
                    elif pname in prevProcList:
                        unionRssList[pname] = -(prevProcList[pname][stat])

        # define shortcut functions #
        convNum = UtilMgr.convNum
        convColor = UtilMgr.convColor

        # define color description #
        colors = "(Color: %s|%s|%s)" % (
            convColor("Increased", "RED"),
            convColor("Decreased", "GREEN"),
            convColor("Removed", "WARNING"),
        )

        # print CPU diff #
        SysMgr.printPipe(
            "\n[Diff CPU Info] (NrTask: %s) %s\n%s"
            % (convNum(len(unionCpuList) - 2), colors, twoLine)
        )

        emptyCpuStat = "%7s(%2s)(%5s/%7s/%5s/%6s) |" % (
            "-",
            "-",
            "-",
            "-",
            "-",
            "-",
        )
        menuStat = "%7s(%2s)(%5s/%7s/%5s/%6s) |" % (
            diffType,
            "Nr",
            "Min",
            "Avg",
            "Max",
            "Tot",
        )
        lenCpuStat = len(emptyCpuStat)

        # print file names #
        totalBuf = ""
        menuBuf = "{0:^16} | ".format("Task")
        printBuf = "{0:^16} | ".format("File")
        for fname in flist:
            printBuf = ("{0:1} {1:^%d}|" % (lenCpuStat - 1)).format(
                printBuf, fname[-lenCpuStat + 1 :]
            )
            menuBuf = ("{0:1} {1:^%d}" % len(menuStat)).format(
                menuBuf, menuStat
            )
        printBuf = "%s\n%s\n%s\n%s" % (printBuf, oneLine, menuBuf, twoLine)
        SysMgr.printPipe(printBuf)

        for pname, value in sorted(
            unionCpuList.items(), key=lambda e: float(e[1]), reverse=True
        ):

            if pname == "[ TOTAL ]":
                continue
            elif pname == "TOTAL":
                printBuf = "%16s | " % "[CPU/AVG]"
            else:
                printBuf = "%16s | " % pname[-16:]

            for idx, fname in enumerate(flist):
                try:
                    prevCpuProcList = statFileList[flist[idx - 1]][
                        "cpuProcUsage"
                    ]
                except:
                    prevCpuProcList = None

                cpuProcList = statFileList[fname]["cpuProcUsage"]

                # no target process in this file #
                if not pname in cpuProcList:
                    if (
                        idx > 0
                        and prevCpuProcList
                        and pname in prevCpuProcList
                    ):

                        diff = "%6.1f%%" % -(prevCpuProcList[pname][item])
                        diff = convColor(diff, "WARNING", 6)
                        printBuf = "%s %6s%s" % (
                            printBuf,
                            diff,
                            emptyCpuStat[7:],
                        )
                    else:
                        printBuf = "%s %s" % (printBuf, emptyCpuStat)
                    continue

                cpuProcStat = cpuProcList[pname]
                if not "diff" in cpuProcStat:
                    diff = "-"
                elif cpuProcStat["diff"] > 0:
                    diff = "{0:>6}%".format(
                        "%6s"
                        % ("+%s" % convNum(cpuProcStat["diff"], isFloat=True))
                    )
                    diff = convColor(diff, "RED", 6)
                elif cpuProcStat["diff"] < 0:
                    diff = "{0:>6}%".format(
                        "%6s"
                        % (
                            "-%s"
                            % convNum(abs(cpuProcStat["diff"]), isFloat=True)
                        )
                    )
                    diff = convColor(diff, "GREEN", 6)
                else:
                    diff = "0"

                total = convNum(cpuProcStat["total"])

                newStat = "%7s(%2d)(%4s%%/%6.1f%%/%4s%%/%5s%%) |" % (
                    diff,
                    cpuProcStat["cnt"],
                    cpuProcStat["minimum"],
                    cpuProcStat["average"],
                    cpuProcStat["maximum"],
                    total,
                )

                printBuf = "%s %s" % (printBuf, newStat)

            if pname == "TOTAL":
                totalBuf = printBuf
            else:
                SysMgr.addPrint(printBuf + "\n", force=True)

        if totalBuf:
            SysMgr.printPipe("%s\n%s" % (totalBuf, oneLine))

        SysMgr.doPrint(newline=False, clear=True)

        if len(unionCpuList) < 2:
            SysMgr.printPipe("\tNone")

        SysMgr.printPipe(oneLine)

        # print GPU diff #
        SysMgr.printPipe("\n[Diff GPU Info] %s\n%s" % (colors, twoLine))

        emptyGpuStat = "%7s(%2s)(%5s/%7s/%5s/%6s) |" % (
            "-",
            "-",
            "-",
            "-",
            "-",
            "-",
        )
        menuStat = "%7s(%2s)(%5s/%7s/%5s/%6s) |" % (
            diffType,
            "Nr",
            "Min",
            "Avg",
            "Max",
            "Tot",
        )
        lenGpuStat = len(emptyCpuStat)

        menuBuf = "{0:^24} | ".format("Task")
        printBuf = "{0:^24} | ".format("File")
        for fname in flist:
            printBuf = ("{0:1} {1:^%d}|" % (len(emptyGpuStat) - 1)).format(
                printBuf, fname[-lenGpuStat + 1 :]
            )
            menuBuf = ("{0:1} {1:^%d}" % len(menuStat)).format(
                menuBuf, menuStat
            )
        printBuf = "%s\n%s\n%s\n%s" % (printBuf, oneLine, menuBuf, twoLine)
        SysMgr.printPipe(printBuf)

        for pname, value in sorted(
            unionGpuList.items(), key=lambda e: float(e[1]), reverse=True
        ):
            printBuf = "%24s | " % pname[-24:]
            for idx, fname in enumerate(flist):
                try:
                    prevGpuProcList = statFileList[flist[idx - 1]][
                        "gpuProcUsage"
                    ]
                except:
                    prevGpuProcList = None

                gpuProcList = statFileList[fname]["gpuProcUsage"]

                # no target process in this file #
                if not pname in gpuProcList:
                    if (
                        idx > 0
                        and prevGpuProcList
                        and pname in prevGpuProcList
                    ):

                        diff = "%6.1f%%" % -(prevGpuProcList[pname][item])
                        diff = convColor(diff, "WARNING", 6)
                        printBuf = "%s %6s%s" % (
                            printBuf,
                            diff,
                            emptyGpuStat[7:],
                        )
                    else:
                        printBuf = "%s %s" % (printBuf, emptyGpuStat)
                    continue

                gpuProcStat = gpuProcList[pname]
                if not "diff" in gpuProcStat:
                    diff = "-"
                elif gpuProcStat["diff"] > 0:
                    diff = "{0:>6}%".format(
                        "%6s"
                        % ("+%s" % convNum(gpuProcStat["diff"], isFloat=True))
                    )
                    diff = convColor(diff, "RED", 6)
                elif gpuProcStat["diff"] < 0:
                    diff = "{0:>6}%".format(
                        "%6s"
                        % (
                            "-%s"
                            % convNum(abs(gpuProcStat["diff"]), isFloat=True)
                        )
                    )
                    diff = convColor(diff, "GREEN", 6)
                else:
                    diff = "0"

                total = convNum(gpuProcStat["total"])

                newStat = "%7s(%2d)(%4s%%/%6.1f%%/%4s%%/%5s%%) |" % (
                    diff,
                    gpuProcStat["cnt"],
                    gpuProcStat["minimum"],
                    gpuProcStat["average"],
                    gpuProcStat["maximum"],
                    total,
                )

                printBuf = "%s %s" % (printBuf, newStat)

            SysMgr.addPrint(printBuf + "\n", force=True)

        SysMgr.doPrint(newline=False, clear=True)

        if not unionGpuList:
            SysMgr.printPipe("\tNone")

        SysMgr.printPipe(oneLine)

        # check memory type #
        if SysMgr.pssEnable:
            mtype = "PSS"
        elif SysMgr.ussEnable:
            mtype = "USS"
        else:
            mtype = "RSS"

        # print memory diff #
        SysMgr.printPipe(
            "\n[Diff %s Info] (NrTask: %s) %s\n%s"
            % (mtype, convNum(len(unionRssList) - 1), colors, twoLine)
        )

        emptyRssStat = "%7s(%2s)(%7s/%7s/%7s) |" % ("-", "-", "-", "-", "-")
        menuStat = "%7s(%2s)(%7s/%7s/%7s) |" % (
            "Diff",
            "Nr",
            "Min",
            "Avg",
            "Max",
        )
        lenRssStat = len(emptyRssStat)

        totalBuf = ""
        menuBuf = "{0:^16} | ".format("Task")
        printBuf = "{0:^16} | ".format("File")
        for fname in flist:
            printBuf = ("{0:1} {1:^%d}|" % (len(emptyRssStat) - 1)).format(
                printBuf, fname[-lenRssStat + 1 :]
            )
            menuBuf = ("{0:1} {1:^%d}" % len(menuStat)).format(
                menuBuf, menuStat
            )
        printBuf = "%s\n%s\n%s\n%s" % (printBuf, oneLine, menuBuf, twoLine)
        SysMgr.printPipe(printBuf)

        for pname, value in sorted(
            unionRssList.items(), key=lambda e: long(e[1]), reverse=True
        ):
            if pname == "FREE":
                printBuf = "%16s | " % "[FREE]"
            else:
                printBuf = "%16s | " % pname[-16:]

            for idx, fname in enumerate(flist):
                try:
                    prevRssProcList = statFileList[flist[idx - 1]][
                        "memProcUsage"
                    ]
                except:
                    prevRssProcList = None

                rssProcList = statFileList[fname]["memProcUsage"]

                # no target process in this file #
                if not pname in rssProcList:
                    if (
                        idx > 0
                        and prevRssProcList
                        and pname in prevRssProcList
                    ):
                        diff = "%6sM" % -(prevRssProcList[pname]["maxRss"])
                        diff = convColor(diff, "WARNING", 7)
                        printBuf = "%s %7s%s" % (
                            printBuf,
                            diff,
                            emptyRssStat[7:],
                        )
                    else:
                        printBuf = "%s %s" % (printBuf, emptyRssStat)
                    continue

                rssProcStat = rssProcList[pname]
                if not "diff" in rssProcStat:
                    diff = "-"
                elif rssProcStat["diff"] > 0:
                    diff = "{0:>6}M".format(
                        "+%s" % convNum(rssProcStat["diff"])
                    )
                    diff = convColor(diff, "RED", 6)
                elif rssProcStat["diff"] < 0:
                    diff = "{0:>6}M".format(
                        "-%s" % convNum(abs(rssProcStat["diff"]))
                    )
                    diff = convColor(diff, "GREEN", 6)
                else:
                    diff = "0"

                newStat = "%7s(%2s)(%6sM/%6sM/%6sM) |" % (
                    diff,
                    convNum(rssProcStat["cnt"]),
                    convNum(rssProcStat["minRss"]),
                    convNum(rssProcStat["avgRss"]),
                    convNum(rssProcStat["maxRss"]),
                )

                printBuf = "%s %s" % (printBuf, newStat)

            if pname == "FREE":
                totalBuf = printBuf
            else:
                SysMgr.addPrint(printBuf + "\n", force=True)

        if totalBuf:
            SysMgr.printPipe("%s\n%s" % (totalBuf, oneLine))

        SysMgr.doPrint(newline=False, clear=True)

        if len(unionRssList) < 2:
            SysMgr.printPipe("\tNone")

        SysMgr.printPipe(oneLine)

    def __init__(self, fpath=None, onlyInstance=False):

        # exec variable #
        if SysMgr.execEnable is None:
            self.execEnable = False
        else:
            self.execEnable = True

        # draw attributes #
        if "FONTSIZE" in SysMgr.environList:
            fontsize = UtilMgr.getEnvironNum("FONTSIZE")
            self.xfsize = self.lfsize = fontsize
        else:
            self.xfsize = UtilMgr.getEnvironNum("XFONTSIZE", False, 4, False)
            self.lfsize = UtilMgr.getEnvironNum("LFONTSIZE", False, 3, False)

        # thread mode #
        if fpath:
            self.initThreadData()

            self.init_threadData = {
                "comm": "",
                "usage": 0.0,
                "cpuRank": 0,
                "yield": 0,
                "cpuWait": 0.0,
                "pri": "?",
                "reqRdBlock": 0,
                "readBlock": 0,
                "ioRank": 0,
                "irq": 0.0,
                "reclaimWait": 0.0,
                "reclaimCnt": 0,
                "ptid": "-" * 5,
                "new": " ",
                "die": " ",
                "preempted": 0,
                "preemption": 0,
                "start": 0.0,
                "stop": 0.0,
                "ioRdWait": 0.0,
                "readQueueCnt": 0,
                "readStart": 0.0,
                "maxRuntime": 0.0,
                "coreSchedCnt": 0,
                "longRunCore": -1,
                "dReclaimWait": 0.0,
                "dReclaimStart": 0.0,
                "migrate": 0,
                "dReclaimCnt": 0,
                "ftxMax": 0.0,
                "ftxLockCnt": 0,
                "ftxEnter": 0.0,
                "ftxLock": 0.0,
                "ftxTotal": 0.0,
                "ftxWaitCnt": 0,
                "ftxProcess": 0.0,
                "ftxLockMax": 0.0,
                "ftxStat": "?",
                "ftxLSwitch": 0,
                "ftxBlockTotal": 0.0,
                "ftxLBlockTotal": 0.0,
                "ftxBlock": 0.0,
                "ftxLBlock": 0.0,
                "ftxBlockCnt": 0,
                "ftxEnt": None,
                "lastStatus": "N",
                "offCnt": 0,
                "offTime": 0.0,
                "waitStartAsParent": 0.0,
                "nrAllocPages": 0,
                "nrPages": 0,
                "reclaimedPages": 0,
                "waitPid": 0,
                "remainKmem": 0,
                "wasteKmem": 0,
                "childList": None,
                "kernelPages": 0,
                "readBlockCnt": 0,
                "writeBlock": 0,
                "writeBlockCnt": 0,
                "tgid": "-" * 5,
                "cachePages": 0,
                "userPages": 0,
                "lastOff": 0.0,
                "maxPreempted": 0.0,
                "anonReclaimedPages": 0,
                "lastIdleStatus": 0,
                "createdTime": 0.0,
                "waitChild": 0.0,
                "waitParent": 0.0,
                "customEvent": None,
                "userEvent": None,
                "kernelEvent": None,
                "blkCore": 0,
                "lockWait": 0.0,
                "lockTime": 0.0,
                "lockCnt": 0,
                "tryLockCnt": 0,
                "lastLockTime": 0.0,
                "lastLockWait": 0.0,
                "reqWrBlock": 0,
                "writeQueueCnt": 0,
                "writeBlockCnt": 0,
                "writeStart": 0.0,
                "ioWrWait": 0.0,
                "awriteBlock": 0,
                "awriteBlockCnt": 0,
                "schedLatency": 0.0,
                "schedReady": 0.0,
                "lastNrSyscall": -1,
                "schedBlock": 0.0,
                "nrSyscall": 0,
                "lastCore": 0,
            }

            self.init_irqData = {
                "name": None,
                "usage": 0.0,
                "start": 0.0,
                "max": 0.0,
                "min": 0.0,
                "maxPeriod": 0.0,
                "minPeriod": 0.0,
                "count": 0,
            }

            self.init_intData = {
                "time": 0.0,
                "firstLogTime": 0.0,
                "cpuPer": 0.0,
                "totalUsage": 0.0,
                "totalMemUsage": 0,
                "brUsage": 0,
                "totalBrUsage": 0,
                "irqUsage": 0.0,
                "kmemUsage": 0,
                "totalKmemUsage": 0,
                "coreSchedCnt": 0,
                "totalCoreSchedCnt": 0,
                "preempted": 0.0,
                "totalBwUsage": 0,
                "totalPreempted": 0.0,
                "new": " ",
                "die": " ",
                "bwUsage": 0,
                "cpuUsage": 0.0,
                "memUsage": 0,
            }

            self.init_eventData = {
                "count": 0,
                "start": 0.0,
                "usage": 0.0,
                "max": 0.0,
                "min": 0.0,
                "maxPeriod": 0.0,
                "minPeriod": 0.0,
            }

            self.init_kmallocData = {
                "tid": "0",
                "caller": "0",
                "ptr": "0",
                "req": 0,
                "alloc": 0,
                "time": "0",
                "waste": 0,
                "core": 0,
            }

            self.wakeupData = {
                "tid": "0",
                "nr": "0",
                "ret": "0",
                "time": "0",
                "args": "0",
                "valid": 0,
                "from": "0",
                "to": "0",
                "corrupt": "0",
            }

            self.allocPageData = {}

            self.init_syscallInfo = {
                "usage": 0.0,
                "last": 0.0,
                "count": 0,
                "max": 0.0,
                "min": 0.0,
                "err": 0,
            }

            self.init_binderInfo = {
                "usage": 0.0,
                "last": 0.0,
                "count": 0,
                "max": 0.0,
                "min": 0.0,
            }

            self.init_pageData = {
                "tid": "0",
                "page": "0",
                "flags": "0",
                "type": "0",
                "time": "0",
            }

            self.init_lastJob = {
                "job": "0",
                "time": "0",
                "tid": "0",
                "prevWakeupTid": "0",
            }

            self.init_preemptData = {"usage": 0.0, "count": 0, "max": 0.0}

            self.init_wqData = {
                "name": None,
                "usage": 0.0,
                "start": 0.0,
                "max": -1.0,
                "min": -1.0,
                "maxPeriod": -1.0,
                "minPeriod": -1.0,
                "avgPeriod": 0.0,
                "scount": 0,
                "rcount": 0,
                "avg": 0.0,
                "task": None,
            }

            self.finishTime = "0"
            self.lastCore = "0"
            self.lastTidPerCore = {}
            self.lastEvent = "0"
            self.backupData = {}
            self.nrSchedLoss = 0
            self.timelineIdx = {}
            self.timelineData = {"time_unit": "us", "segments": []}

        # top mode #
        else:
            self.init_procData = {
                "isMain": False,
                "tids": None,
                "stat": None,
                "io": None,
                "alive": False,
                "runtime": 0.0,
                "changed": True,
                "created": False,
                "new": False,
                "majflt": 0,
                "ttime": 0,
                "cttime": 0,
                "utime": 0,
                "stime": 0,
                "btime": 0,
                "rw": 0,
                "taskPath": None,
                "statm": None,
                "mainID": "",
                "maps": None,
                "status": None,
            }

            self.init_cpuData = {
                "user": 0,
                "system": 0,
                "nice": 0,
                "idle": 0,
                "wait": 0,
                "irq": 0,
                "softirq": 0,
                "iowait": 0,
            }

            self.nrThread = 0
            self.nrPrevThread = 0
            self.nrProcess = 0
            self.nrPrevProcess = 0
            self.nrFd = 0
            self.printTick = 0
            self.maxPid = SysMgr.pid
            self.procData = {}
            self.procFdData = {}
            self.prevProcData = {}
            self.cgroupData = {}
            self.prevCgroupData = {}
            self.nsData = {}
            self.fileData = {}
            self.cpuData = {}
            self.gpuData = {}
            self.prevCpuData = {}
            self.irqData = {}
            self.prevIrqData = {}
            self.zoneData = {}
            self.prevZoneData = {}
            self.slabData = {}
            self.vmallocData = {}
            self.memData = {}
            self.prevMemData = {}
            self.gpuMemData = {}
            self.vmData = {}
            self.prevVmData = {}
            self.stackTable = {}
            self.prevSwaps = None
            self.abnormalTasks = {}
            self.intervalData = {}

            # set index of attributes #
            self.majfltIdx = ConfigMgr.STAT_ATTR.index("MAJFLT")
            self.utimeIdx = ConfigMgr.STAT_ATTR.index("UTIME")
            self.stimeIdx = ConfigMgr.STAT_ATTR.index("STIME")
            self.cutimeIdx = ConfigMgr.STAT_ATTR.index("CUTIME")
            self.cstimeIdx = ConfigMgr.STAT_ATTR.index("CSTIME")
            self.btimeIdx = ConfigMgr.STAT_ATTR.index("DELAYBLKTICK")
            self.swapIdx = ConfigMgr.STAT_ATTR.index("NSWAP")
            self.commIdx = ConfigMgr.STAT_ATTR.index("COMM")
            self.ppidIdx = ConfigMgr.STAT_ATTR.index("PPID")
            self.nrthreadIdx = ConfigMgr.STAT_ATTR.index("NRTHREAD")
            self.prioIdx = ConfigMgr.STAT_ATTR.index("PRIORITY")
            self.policyIdx = ConfigMgr.STAT_ATTR.index("POLICY")
            self.vssIdx = ConfigMgr.STAT_ATTR.index("VSIZE")
            self.rssIdx = ConfigMgr.STAT_ATTR.index("RSS")
            self.scodeIdx = ConfigMgr.STAT_ATTR.index("STARTCODE")
            self.ecodeIdx = ConfigMgr.STAT_ATTR.index("ENDCODE")
            self.statIdx = ConfigMgr.STAT_ATTR.index("STATE")
            self.starttimeIdx = ConfigMgr.STAT_ATTR.index("STARTTIME")
            self.sidIdx = ConfigMgr.STAT_ATTR.index("SESSIONID")
            self.pgrpIdx = ConfigMgr.STAT_ATTR.index("PGRP")
            self.shrIdx = ConfigMgr.STATM_TYPE.index("SHR")
            self.statCnt = len(ConfigMgr.STAT_ATTR)

            # initialize netlink socket #
            try:
                SysMgr.initNetlink()
            except:
                SysMgr.printWarn("failed to initialize netlink", reason=True)

            # check task stream flag #
            if "TASKSTREAM" in SysMgr.environList:
                self.taskStreamEnable = True
                SysMgr.streamEnable = True
            else:
                self.taskStreamEnable = False

            # check to return just instance #
            if onlyInstance:
                return

            # set target type #
            if SysMgr.processEnable:
                targets = "processes"
            else:
                targets = "threads"

            if SysMgr.graphEnable:
                # draw images based on statistics #
                if SysMgr.inputParam:
                    # FLAME GRAPH MODE #
                    if SysMgr.checkMode("drawflame", True):
                        drawFunc = Debugger.drawFlame
                    elif SysMgr.checkMode("drawbitmap", True):
                        drawFunc = TaskAnalyzer.drawBitmap
                    # OTHER DRAW MODE #
                    else:
                        drawFunc = self.drawStats

                    if "NOMERGE" in SysMgr.environList:
                        for fpath in list(SysMgr.inputParam):
                            drawFunc(fpath)
                    else:
                        drawFunc(SysMgr.inputParam)

                    sys.exit(0)
                # no path for statistics #
                else:
                    SysMgr.printErr(
                        (
                            "wrong option used, "
                            "use also -I option to load statistics data"
                        )
                    )
                    sys.exit(-1)

            # set system maximum fd number #
            SysMgr.setMaxFd()

            # set default interval #
            if SysMgr.intervalEnable == 0:
                SysMgr.intervalEnable = 1

            # apply filter from 1st argument #
            if not SysMgr.filterGroup and SysMgr.hasMainArg():
                value = SysMgr.getMainArg()
                value = UtilMgr.splitString(value)
                SysMgr.filterGroup = UtilMgr.cleanItem(value)

            # remove wrong filter #
            if SysMgr.filterGroup:
                for idx, val in enumerate(SysMgr.filterGroup):
                    if not val:
                        SysMgr.filterGroup.pop(idx)

                taskList = ", ".join(SysMgr.filterGroup)

                if SysMgr.fileTopEnable:
                    pass
                elif SysMgr.groupProcEnable:
                    SysMgr.printInfo(
                        (
                            "only specific %s that are involved "
                            "in the process group [ %s ] are shown"
                        )
                        % (targets, taskList)
                    )
                else:
                    SysMgr.printInfo(
                        "only specific %s [ %s ] are shown"
                        % (targets, taskList)
                    )

            # set threshold config #
            if not "NOTHRESHOLD" in SysMgr.environList:
                SysMgr.applyThreshold()

            # set log buffer size #
            if SysMgr.bufferSize < 0:
                # default unlimited #
                SysMgr.bufferSize = 0

            if SysMgr.outPath:
                # print buffer size #
                if SysMgr.bufferSize == 0:
                    SysMgr.printWarn("buffer size is unlimited", True)
                else:
                    SysMgr.printInfo(
                        "limit buffer size to [%s]"
                        % UtilMgr.convSize2Unit(SysMgr.bufferSize)
                    )

                SysMgr.printStat(
                    r"start profiling... [ STOP(Ctrl+c), SAVE(Ctrl+\) ]"
                )

            # apply print condition via resource threshold #
            TaskAnalyzer.applyPrintCond()

            # file mode #
            if SysMgr.fileTopEnable:
                try:
                    self.runFileTop()
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr("failed to monitor files", reason=True)
            # DLT mode #
            elif SysMgr.dltTopEnable:
                DltAnalyzer.runDltReceiver(mode="top")
            # D-Bus mode #
            elif SysMgr.dbusTopEnable:
                DbusMgr.runDbusSnooper(mode="top")
            # slab mode #
            elif SysMgr.checkMode("slabtop"):
                try:
                    self.runSlabTop()
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr("failed to monitor slab", reason=True)
            # vmalloc mode #
            elif SysMgr.checkMode("vtop"):
                try:
                    self.runVmallocTop()
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr("failed to monitor vmalloc", reason=True)
            # cgroup mode #
            elif SysMgr.checkMode("cgtop"):
                try:
                    self.runCgTop()
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr("failed to monitor cgroup", reason=True)
            # others #
            else:
                # set network config #
                if not SysMgr.findOption("x"):
                    NetworkMgr.setServerNetwork(
                        None, None, reuse=False, weakPort=True
                    )

            # print system general info in advance #
            if SysMgr.outPath and SysMgr.pipeEnable and SysMgr.exitFlag:
                SysMgr.printLogo(big=True)
                SysMgr.saveSysStats()
                SysMgr.printInfoBuffer()
                SysMgr.printPipe("\n")

            # request service to remote server #
            self.requestService()

            # task top mode #
            try:
                if SysMgr.isLinux:
                    self.runTaskTop()
                else:
                    self.runTaskTopGen()
            except KeyboardInterrupt:
                SysMgr.stopHandler()
                sys.exit(0)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("failed to monitor tasks", reason=True)

            # terminate top mode #
            sys.exit(0)

        # -------------------- THREAD MODE --------------------#
        # change default CPU property #
        SysMgr.cpuEnable = False

        # initialize preempt thread list #
        if SysMgr.preemptGroup:
            if SysMgr.findOption("i"):
                SysMgr.printErr("-i option is already used")
                sys.exit(-1)
            elif SysMgr.findOption("g"):
                SysMgr.printErr("-g option is already used")
                sys.exit(-1)

            for index in SysMgr.preemptGroup:
                """
                preempted state
                [preemptBit, threadList, startTime, core, totalUsage] #
                """
                self.preemptData.append([False, {}, 0.0, 0, 0.0])

        # read trace data #
        lines = TaskAnalyzer.readTraceData(fpath)

        # save trace data and stop analysis #
        if SysMgr.outputFile:
            SysMgr.saveTraceData(lines)
            sys.exit(0)

        # get process tree #
        SysMgr.getProcTreeInfo()

        # start parsing logs #
        SysMgr.printStat("start analyzing... [ STOP(Ctrl+c) ]")
        SysMgr.totalLine = len(lines)

        for idx, log in enumerate(lines):
            if self.stopFlag:
                # accumulated data #
                if "EVENT_START" in log:
                    self.stopFlag = False
                else:
                    continue

            # skip blank line #
            if not log.strip():
                continue

            # parse a line #
            time = self.parse(log)
            UtilMgr.printProgress(idx, SysMgr.totalLine)

            # save last job per core #
            self.lastJob.setdefault(self.lastCore, dict(self.init_lastJob))

            self.lastJob[self.lastCore]["job"] = self.lastEvent
            self.lastJob[self.lastCore]["time"] = self.finishTime

        if lines:
            UtilMgr.deleteProgress()

        # print the number of missed sched data #
        if self.nrSchedLoss:
            SysMgr.printWarn(
                "a total of %s sched data is missing"
                % UtilMgr.convNum(self.nrSchedLoss),
                True,
            )

        # update finish time #
        if self.finishTime == "0":
            self.finishTime = time

        # update anonymous comm #
        for idx, val in self.threadData.items():
            if val["comm"] == "<...>":
                val["comm"] = "?"

        # add consumed time of jobs not finished yet to each threads #
        for idx, val in self.lastTidPerCore.items():
            # apply core off time #
            nrCore = long(idx)
            coreId = "0[%s]" % idx
            if (
                self.threadData[coreId]["coreSchedCnt"] == 0
                and self.threadData[coreId]["offTime"] == 0
            ):
                # define time delta #
                start_delta = 0
                stime = float(SysMgr.startTime)
                stop_delta = long((float(self.finishTime) - stime) * 1000000)

                # add timeline data #
                self.timelineData["segments"].append(
                    {
                        "group": nrCore,
                        "text": "OFF",
                        "id": nrCore,
                        "state": "OFF",
                        "time_start": start_delta,
                        "time_end": stop_delta,
                    }
                )

            elif self.threadData[coreId]["lastOff"] > 0:
                self.threadData[coreId]["usage"] += (
                    float(self.finishTime) - self.threadData[coreId]["start"]
                )

                # define time delta #
                startTime = self.threadData[coreId]["lastOff"]
                stime = float(SysMgr.startTime)
                start_delta = long((float(startTime) - stime) * 1000000)
                stop_delta = long((float(self.finishTime) - stime) * 1000000)

                # add timeline data #
                self.timelineData["segments"].append(
                    {
                        "group": nrCore,
                        "text": "OFF",
                        "id": nrCore,
                        "state": "OFF",
                        "time_start": start_delta,
                        "time_end": stop_delta,
                    }
                )

            if self.threadData[val]["lastStatus"] == "S":
                continue

            self.threadData[val]["usage"] += float(self.finishTime) - float(
                self.threadData[val]["start"]
            )

        # add lock time of jobs not finished yet to each threads #
        if SysMgr.lockEnable:
            for idx, item in self.threadData.items():
                if item["ftxEnter"] > 0:
                    # elapsed time #
                    wtime = float(self.finishTime) - item["ftxEnter"]
                    item["ftxTotal"] += wtime
                    if item["ftxMax"] < wtime:
                        item["ftxMax"] = wtime

                    # CPU time #
                    if item["start"] > item["ftxEnter"]:
                        ctime = float(self.finishTime) - item["start"]
                        item["ftxProcess"] += ctime
                    elif item["ftxBlock"] == 0 and item["ftxLBlock"] == 0:
                        ctime = float(self.finishTime) - item["ftxEnter"]
                        item["ftxProcess"] += ctime

                    # wait time #
                    if item["ftxBlock"] > 0:
                        wtime = float(self.finishTime) - item["ftxBlock"]
                        item["ftxBlockTotal"] += wtime
                    if item["ftxLBlock"] > 0:
                        wtime = float(self.finishTime) - item["ftxLBlock"]
                        item["ftxLBlockTotal"] += wtime

                if not "futexObj" in item:
                    continue

                # lock time #
                for obj, time in item["futexObj"].items():
                    ltime = float(self.finishTime) - time
                    item["ftxLock"] += ltime
                    if item["ftxLockMax"] < ltime:
                        item["ftxLockMax"] = ltime

        # add block waiting time of jobs not finished yet to each threads #
        if SysMgr.blockEnable:
            # waiting for read #
            for idx, item in sorted(
                self.threadData.items(),
                key=lambda e: e[1]["readStart"],
                reverse=True,
            ):

                if item["readStart"] > 0:
                    waitTime = float(self.finishTime) - item["readStart"]
                    item["ioRdWait"] += waitTime
                    self.threadData[item["blkCore"]]["ioRdWait"] += waitTime
                    item["readStart"] = 0
                else:
                    break

            # waiting for synchronous write #
            for idx, item in sorted(
                self.threadData.items(),
                key=lambda e: e[1]["writeStart"],
                reverse=True,
            ):

                # cancel to add blocking time for write because async write #
                break
                """
                if item['writeStart'] > 0:
                    waitTime = float(self.finishTime) - item['writeStart']
                    item['ioWrWait'] += waitTime
                    self.threadData[item['blkCore']]['ioWrWait'] += waitTime
                    item['writeStart'] = 0
                else:
                    break
                """

            # warn uncompleted block request #
            if self.ioData:
                SysMgr.printWarn(
                    "failed to handle %s block requests"
                    % UtilMgr.convNum(len(self.ioData))
                )

        # calculate usage of threads in last interval #
        self.handleIntData(self.finishTime)

        if not self.threadData:
            SysMgr.printErr("no recognized data in %s" % SysMgr.inputFile)
            sys.exit(-1)

        self.totalTime = round(
            float(self.finishTime) - float(SysMgr.startTime), 7
        )

        # apply filter #
        if SysMgr.filterGroup:
            # make parent list #
            plist = {}
            if SysMgr.groupProcEnable:
                for key, value in self.threadData.items():
                    tgid = value["tgid"]
                    if tgid == "0" or tgid.startswith("-"):
                        continue
                    if key in SysMgr.filterGroup or UtilMgr.isValidStr(
                        value["comm"]
                    ):
                        plist[tgid] = 0

            # filter segments #
            segments = self.timelineData["segments"]
            self.timelineData["segments"] = []
            for item in segments:
                # no tid #
                if not item["id"] in self.threadData:
                    continue
                # other progress group #
                elif SysMgr.isExceptTarget(
                    item["id"], self.threadData, plist=plist
                ):
                    continue

                # add segment #
                self.timelineData["segments"].append(item)

            # filter thread data #
            for key in list(self.threadData):
                # except for cores #
                if key.startswith("0["):
                    continue

                # except for process group #
                if not SysMgr.isExceptTarget(
                    key, self.threadData, plist=plist
                ):
                    continue

                # remove thread #
                try:
                    self.threadData.pop(key, None)
                except:
                    continue

        # add empty timeline data for drawing cores #
        for nrCore in SysMgr.perCoreDrawList:
            self.timelineData["segments"].append(
                {
                    "group": nrCore,
                    "text": "OFF",
                    "id": nrCore,
                    "state": "OFF",
                    "time_start": 0,
                    "time_end": 0,
                }
            )

    def __del__(self):
        pass

    def runVmallocTop(self):
        # run loop #
        while 1:
            # save timestamp #
            prevTime = time.time()

            # check repeat count #
            SysMgr.checkProgress()

            # print vmalloc info #
            SysMgr.doPrintVmalloc(True)

            # write user command #
            SysMgr.runProfCmd("AFTER")

            # get delayed time #
            delayTime = time.time() - prevTime
            if delayTime > SysMgr.intervalEnable:
                waitTime = 0.000001
            else:
                waitTime = SysMgr.intervalEnable - delayTime

            # wait for next tick #
            if not SysMgr.waitUserInput(waitTime):
                time.sleep(waitTime)

    def runSlabTop(self):
        # run loop #
        while 1:
            # save timestamp #
            prevTime = time.time()

            # check repeat count #
            SysMgr.checkProgress()

            # print slab info #
            SysMgr.doPrintSlab(True)

            # write user command #
            SysMgr.runProfCmd("AFTER")

            # get delayed time #
            delayTime = time.time() - prevTime
            if delayTime > SysMgr.intervalEnable:
                waitTime = 0.000001
            else:
                waitTime = SysMgr.intervalEnable - delayTime

            # wait for next tick #
            if not SysMgr.waitUserInput(waitTime):
                time.sleep(waitTime)

    def runCgTop(self):
        # check cgroup path #
        cgroupPath = SysMgr.sysInstance.getCgroupPath()
        if not cgroupPath or not os.path.isdir(cgroupPath):
            SysMgr.printErr("failed to access cgroup filesystem")
            sys.exit(-1)

        # run loop #
        while 1:
            # collect system stats as soon as possible #
            self.saveSystemStat(target="cgroup")

            # save timestamp #
            prevTime = time.time()

            if self.prevCpuData:
                # print system status #
                self.printSystemStat(idIndex=True, target="cgroup")

            # check repeat count #
            SysMgr.checkProgress()

            # reset system status #
            self.reinitStats()

            # write user command #
            SysMgr.runProfCmd("AFTER")

            # get delayed time #
            delayTime = time.time() - prevTime
            if delayTime > SysMgr.intervalEnable:
                waitTime = 0.000001
            else:
                waitTime = SysMgr.intervalEnable - delayTime

            # wait for next tick #
            if not SysMgr.waitUserInput(waitTime):
                time.sleep(waitTime)

    def runFileTop(self):
        def _getFilter(init=False):
            procFilter = []
            fileFilter = []

            if not SysMgr.filterGroup:
                return [procFilter, fileFilter]

            newFilter = ",".join(SysMgr.filterGroup)
            newFilter = newFilter.split(":", 1)

            # proc filter #
            for pval in newFilter[0].split(","):
                if pval != "":
                    procFilter.append(pval)

            # file filter #
            if len(newFilter) > 1:
                for fval in newFilter[1].split(","):
                    if fval != "":
                        fileFilter.append(fval)

            if init and len(procFilter) > 0:
                SysMgr.printInfo(
                    "only specific processes including [ %s ] are shown"
                    % ", ".join(procFilter)
                )

            if init and len(fileFilter) > 0:
                SysMgr.printInfo(
                    "only specific files including [ %s ] are shown"
                    % ", ".join(fileFilter)
                )

            return [procFilter, fileFilter]

        if SysMgr.isLinux:
            # check root permission #
            SysMgr.checkRootPerm()

            # check proc access #
            if not os.path.isdir(SysMgr.procPath):
                SysMgr.printErr("failed to access to proc filesystem")
                sys.exit(-1)

            # initialize task stat #
            TaskAnalyzer.dbgObj = Debugger(SysMgr.pid, attach=False)
            TaskAnalyzer.dbgObj.initValues()
            TaskAnalyzer.dbgObj.getCpuUsage(system=True)

            # execute commands #
            if SysMgr.inputParam:
                watchList = []
                for cmd in SysMgr.inputParam.split(","):
                    pid = SysMgr.createProcess(cmd.split(), mute=True)
                    if pid > 0:
                        watchList.append(str(pid))

                # apply new filter #
                SysMgr.filterGroup = watchList

        # import select package in the foreground #
        if not SysMgr.outPath:
            SysMgr.getPkg("select", False)

        prevFilter = []

        # set initial repeat value #
        SysMgr.progressCnt = 1

        # get prof flag #
        if "PRINTDELAY" in SysMgr.environList:
            printFlag = True
        else:
            printFlag = False

        while 1:
            # save timestamp #
            prevTime = time.time()

            # update proc and file filter #
            if prevFilter != SysMgr.filterGroup:
                nowFilter = _getFilter(True)
                prevFilter = SysMgr.filterGroup
            else:
                nowFilter = _getFilter()

            # collect file stats as soon as possible #
            if printFlag:
                UtilMgr.saveTime()
            self.saveFileStat(nowFilter)
            if printFlag:
                UtilMgr.printTime("saveFileStat")

            # print system status #
            if printFlag:
                UtilMgr.saveTime()
            self.printFileStat(nowFilter)
            if printFlag:
                UtilMgr.printTime("printFileStat")

            # flush socket caches #
            SysMgr.udpListCache = {}
            SysMgr.tcpListCache = {}
            SysMgr.udsListCache = {}

            # check repeat count #
            SysMgr.checkProgress()

            # reset and save proc instance #
            if printFlag:
                UtilMgr.saveTime()
            self.saveProcInstance()
            if printFlag:
                UtilMgr.printTime("saveProcInstance")

            # reset system status #
            self.reinitStats()

            # write user command #
            SysMgr.runProfCmd("AFTER")

            # get delayed time #
            delayTime = time.time() - prevTime
            if delayTime > SysMgr.intervalEnable:
                waitTime = 0.000001
            else:
                waitTime = SysMgr.intervalEnable - delayTime

            # wait for next tick #
            if not SysMgr.waitUserInput(waitTime, msg="DEFAULT"):
                time.sleep(waitTime)

    def runTaskTopGen(self):
        # import select package in the foreground #
        if not SysMgr.outPath:
            SysMgr.getPkg("select", False)

        # run loop #
        while 1:
            # collect system stats as soon as possible #
            self.saveSystemStatGen()

            # save timestamp #
            prevTime = time.time()

            # handle first tick for printing total resource #
            if SysMgr.totalEnable and not self.prevCpuData:
                SysMgr.progressCnt += 1
                self.reinitStats()
                self.saveSystemStatGen()

            # print stats #
            if self.prevCpuData:
                # print system status #
                self.printSystemStatGen(idIndex=True)

                # report system status for elastic stack
                if SysMgr.elasticEnable:
                    self.reportSystemStatElastic()
                # report system status #
                elif SysMgr.reportEnable:
                    self.reportSystemStat()

            # check repeat count #
            SysMgr.checkProgress()

            # reset system status #
            self.reinitStats()

            # get delayed time #
            delayTime = time.time() - prevTime
            if delayTime > SysMgr.intervalEnable:
                waitTime = 0.000001
            else:
                waitTime = SysMgr.intervalEnable - delayTime

            # wait for next tick #
            if not SysMgr.waitUserInput(waitTime):
                time.sleep(waitTime)

    def runTaskTop(self):
        if not os.path.isdir(SysMgr.procPath):
            SysMgr.printErr("failed to access proc filesystem")
            sys.exit(-1)

        # import select package in the foreground #
        if not SysMgr.outPath:
            SysMgr.getPkg("select", False)

        # initialize perf events #
        SysMgr.initSystemPerfEvents()

        # execute commands #
        if SysMgr.inputParam:
            watchList = []
            for cmd in SysMgr.inputParam.split(","):
                pid = SysMgr.createProcess(cmd.split(), mute=True)
                if pid > 0:
                    watchList.append(str(pid))

            # apply new filter #
            SysMgr.filterGroup = watchList
            if not SysMgr.processEnable:
                SysMgr.groupProcEnable = True

            # add termination condition #
            SysMgr.addEnvironVar("EXITCONDTERM", watchList)

        # get prof flag #
        if "PRINTDELAY" in SysMgr.environList:
            printFlag = True
        else:
            printFlag = False

        # run loop #
        while 1:
            if SysMgr.remoteServObj:
                # receive response from server #
                ret = SysMgr.localServObj.recvfrom()

                # handle response from server #
                self.handleServerResponse(ret)

                continue

            # collect system stats as soon as possible #
            if printFlag:
                UtilMgr.saveTime()
            self.saveSystemStat()
            if printFlag:
                UtilMgr.printTime("saveSystemStat")

            # save timestamp #
            prevTime = time.time()

            # handle first tick for printing total resource #
            if SysMgr.totalEnable and not self.prevCpuData:
                SysMgr.progressCnt += 1
                self.reinitStats()
                self.saveSystemStat()

            # print stats #
            if self.prevCpuData:
                # save timestamp #
                if printFlag:
                    UtilMgr.saveTime()

                # print system status #
                self.printSystemStat(idIndex=True)

                # check termination condition #
                self.checkTermCond()

                # report system status for elastic stack
                if SysMgr.elasticEnable:
                    self.reportSystemStatElastic()
                # report system status #
                elif SysMgr.reportEnable:
                    self.reportSystemStat()

                # print elapsed time #
                if printFlag:
                    UtilMgr.printTime("printSystemStat")

            # check repeat count #
            SysMgr.checkProgress()

            # reset system status #
            self.reinitStats()

            # write user command #
            SysMgr.runProfCmd("AFTER")

            # get delayed time #
            delayTime = time.time() - prevTime
            if delayTime > SysMgr.intervalEnable:
                waitTime = 0.000001
            else:
                waitTime = SysMgr.intervalEnable - delayTime

            # get stack of threads #
            if SysMgr.stackEnable and self.stackTable:
                self.sampleStack(waitTime)
                SysMgr.waitUserInput(0.000001)
            # wait for next tick #
            elif not SysMgr.waitUserInput(waitTime):
                time.sleep(waitTime)

            # check request from client #
            self.checkServer()

    def saveCgroupInstance(self):
        del self.prevCgroupData
        self.prevCgroupData = self.cgroupData
        self.cgroupData = {}
        SysMgr.topInstance = self
        SysMgr.procInstance = self.procData

    def saveProcInstance(self):
        # close fds for terminated tasks #
        for pid in set(self.prevProcData) - set(self.procData):
            try:
                os.close(self.procFdData.pop(pid, None))
            except SystemExit:
                sys.exit(0)
            except:
                pass

        self.prevProcData = self.procData
        self.procData = {}
        SysMgr.topInstance = self
        SysMgr.procInstance = self.procData

    def reinitStats(self):
        self.prevCpuData = self.cpuData
        self.nsData = {}
        self.cpuData = {}
        self.fileData = {}
        self.abnormalTasks = {}
        self.nrPrevThread = self.nrThread
        self.nrPrevProcess = self.nrProcess
        self.nrThread = 0
        self.nrProcess = 0
        self.nrFd = 0
        SysMgr.jsonData = {}

    @staticmethod
    def applyPrintCond():
        for env in list(SysMgr.printCond):
            if not env in SysMgr.environList:
                continue

            # apply condition number #
            SysMgr.printCond[env] = UtilMgr.getEnvironNum(env)
            if SysMgr.printCond[env]:
                SysMgr.reportEnable = True

    @staticmethod
    def getStatsFile(
        logFile, handle=None, applyOpt=True, onlyStart=False, verb=False
    ):
        logBuf = None
        infoBuf = None

        chartStats = {}

        timeline = []
        eventList = []

        cpuUsage = []
        nrCore = []
        nrTask = []
        memFree = []
        memAnon = []
        memCache = []
        swapUsage = []
        reclaimBg = []
        reclaimDr = []
        blkWait = []
        blkRead = []
        blkWrite = []
        netRead = []
        netWrite = []
        gpuUsage = {}
        cpuProcUsage = {}
        cpuProcDelay = {}
        memProcUsage = {}
        blkProcUsage = {}
        storageUsage = {}
        networkUsage = {}

        # get file handle #
        try:
            if handle:
                fd = handle
            else:
                fd = UtilMgr.getTextLines(logFile, verb=verb, retfd=True)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to read '%s'\n" % logFile)
            sys.exit(-1)

        # summarize details in advance #
        if "TOPSUM" in SysMgr.environList:
            # load whole file #
            SysMgr.reloadFileBuffer(fd.name)

            # backup print fd #
            origFd = SysMgr.printFd

            # create a on-memory file #
            SysMgr.printFd = MemoryFile(name="buf")

            # summarize file data #
            TaskAnalyzer.printIntervalUsage(onlyTotal=True)

            # convert data to list #
            fd = SysMgr.printFd
            fd.seek(0)
            fd = fd.read(fd.getsize()).decode().split("\n")

            # restore print fd #
            SysMgr.printFd = origFd

        # get file size #
        totalSize = 0
        if not handle:
            fsize = UtilMgr.getFileSizeStr(logFile)
            SysMgr.printStat(r"start processing '%s'%s..." % (logFile, fsize))

        # context variable #
        finalLine = 0
        context = None
        totalRam = None
        startTime = 0

        convSize = UtilMgr.convUnit2Size

        curSize = 0
        for idx, line in enumerate(fd):
            curSize += len(line)
            UtilMgr.printProgress(curSize, totalSize)

            # get system info #
            if not SysMgr.systemInfoBuffer and line.startswith(
                "[System General Info]"
            ):
                infoBuf = ""
            elif infoBuf is not None:
                if line.startswith("["):
                    # apply launch option #
                    SysMgr.systemInfoBuffer = infoBuf
                    if applyOpt:
                        SysMgr.applyLaunchOption()
                    infoBuf = None
                    continue
                elif line.startswith("=") or line.startswith(" "):
                    continue
                else:
                    infoBuf += line
                    continue

            # split line #
            sline = line.split("|")
            slen = len(sline)

            # get context #
            if line.startswith("[Top "):
                pid = 0
                average = 0
                maxVss = 0
                maxRss = 0
                maxUsage = 0
                pname = None
                gname = None
                intervalList = None

                contextList = line.split()

                # termination #
                if len(contextList) > 10:
                    strPos = line.find("[RAM")
                    sline = line[strPos:].split()

                    try:
                        totalRam = convSize(sline[1][:-1])
                    except:
                        pass

                    try:
                        totalSwap = convSize(sline[3][:-1])
                    except:
                        totalSwap = None

                    break

                # change context #
                context = contextList[1]

            # Summary #
            if context == "Summary":
                nrStatistics = 15

                if slen < nrStatistics:
                    continue

                try:
                    idx = long(sline[0])
                except:
                    continue

                try:
                    tick = long(float(sline[1].split("-")[1]))
                    timeline.append(tick)
                    if not startTime and tick:
                        startTime = tick
                        if onlyStart:
                            return {"start": tick}, {}
                except:
                    timeline.append(0)

                eventList.append(list())

                try:
                    cpuUsage.append(long(sline[2]))
                except:
                    cpuUsage.append(0)

                try:
                    memStat = sline[3].split("/")

                    assert len(memStat) == 3, "wrong format"

                    memFree.append(long(memStat[0]))
                    memAnon.append(long(memStat[1]))
                    memCache.append(long(memStat[2]))
                except:
                    # for backward compatibility #
                    try:
                        memFree.append(long(sline[3]))
                        memAnon.append(0)
                        memCache.append(0)
                    except:
                        memFree.append(0)
                        memAnon.append(0)
                        memCache.append(0)

                try:
                    blkWait.append(long(sline[5]))
                except:
                    blkWait.append(0)

                try:
                    swapUsage.append(long(sline[6]))
                except:
                    swapUsage.append(0)

                try:
                    reclaim = sline[7].strip().split("/")
                    reclaimBg.append(long(reclaim[0]) << 2)
                    reclaimDr.append(long(reclaim[1]) << 2)
                except:
                    reclaimBg.append(0)
                    reclaimDr.append(0)

                try:
                    blkUsage = sline[4].split("/")
                    blkRead.append(long(blkUsage[0]) << 10)
                    blkWrite.append(long(blkUsage[1]) << 10)
                except:
                    blkRead.append(0)
                    blkWrite.append(0)

                try:
                    nrTask.append(sline[11])
                except:
                    nrTask.append("")

                try:
                    nrCore.append(long(sline[12]))
                except:
                    nrCore.append(0)

                try:
                    netstat = sline[13].strip().split("/")

                    assert netstat[0] != "-", "wrong format"

                    if netstat[0][-1] == "T":
                        netRead.append(long(netstat[0][:-1]) << 30)
                    elif netstat[0][-1] == "G":
                        netRead.append(long(netstat[0][:-1]) << 20)
                    elif netstat[0][-1] == "M":
                        netRead.append(long(netstat[0][:-1]) << 10)
                    elif netstat[0][-1] == "K":
                        netRead.append(long(netstat[0][:-1]))
                    else:
                        netRead.append(0)

                    if netstat[0][-1] == "T":
                        netWrite.append(long(netstat[1][:-1]) << 30)
                    elif netstat[0][-1] == "G":
                        netWrite.append(long(netstat[1][:-1]) << 20)
                    elif netstat[1][-1] == "M":
                        netWrite.append(long(netstat[1][:-1]) << 10)
                    elif netstat[1][-1] == "K":
                        netWrite.append(long(netstat[1][:-1]))
                    else:
                        netWrite.append(0)
                except:
                    netRead.append(0)
                    netWrite.append(0)

            # Event #
            elif context == "Event":
                if slen != 4:
                    continue

                try:
                    time = long(float(sline[0]))
                    rtime = float(sline[1])
                    dtime = float(sline[2])
                    event = sline[3].strip()

                    idx = timeline.index(time)
                    eventList[idx].append("%s [%.2fs]" % (event, dtime))
                except:
                    pass

            # Life #
            elif context == "Life":
                if slen != 7:
                    continue

                if not "DRAWLIFE" in SysMgr.environList:
                    continue

                try:
                    task = sline[0].strip()
                    start = sline[1].strip()
                    end = sline[2].strip()
                    parent = sline[4].strip()

                    try:
                        startSec = UtilMgr.convTime2Sec(start)
                        if not startSec:
                            raise Exception("no start")

                        startIdx = UtilMgr.bisect_left(timeline, startSec)
                        eventList[startIdx].append(
                            "[+] %s [%s]" % (task, start)
                        )
                    except:
                        pass

                    try:
                        endSec = UtilMgr.convTime2Sec(end)
                        if not endSec:
                            raise Exception("no end")

                        endIdx = UtilMgr.bisect_left(timeline, endSec)
                        eventList[endIdx].append("[-] %s [%s]" % (task, end))
                    except:
                        pass
                except:
                    pass

            # CPU #
            elif context == "CPU":
                if slen == 3:
                    m = re.match(r"\s*(?P<comm>.+)\(\s*(?P<pid>[0-9]+)", line)
                    if not m:
                        continue

                    d = m.groupdict()
                    comm = d["comm"].strip()

                    if SysMgr.filterGroup:
                        if not TaskAnalyzer.checkFilter(comm, d["pid"]):
                            intervalList = None
                        else:
                            pid = d["pid"]
                            pname = "%s(%s)" % (comm, pid)

                            intervalList = sline[2]
                    else:
                        pid = d["pid"]
                        pname = "%s(%s)" % (comm, pid)

                        intervalList = sline[2]
                elif slen == 2:
                    if intervalList:
                        intervalList += sline[1]
                elif intervalList:
                    # save previous info #
                    cpuProcUsage[pname] = {}
                    cpuProcUsage[pname]["pid"] = pid

                    # get lifecycle info #
                    start = -1
                    finish = -1
                    zombie = -1
                    intervalList = intervalList.split()
                    for idx, item in enumerate(list(intervalList)):
                        if item.startswith("+"):
                            start = idx
                            intervalList[idx] = item[1:]
                        if item.startswith("-"):
                            finish = idx
                            intervalList[idx] = item[1:]
                        if item.startswith("z"):
                            zombie = idx
                            intervalList[idx] = item[1:]
                    cpuList = list(map(long, intervalList))
                    intervalList = " ".join(intervalList)

                    cpuProcUsage[pname]["usage"] = intervalList
                    intervalList = None

                    # calculate total usage of tasks filtered #
                    if TaskAnalyzer.checkFilter(comm, pid):
                        if not "[ TOTAL ]" in cpuProcUsage:
                            cpuProcUsage["[ TOTAL ]"] = {}

                            filterTotal = list(
                                map(long, cpuProcUsage[pname]["usage"].split())
                            )

                            cpuProcUsage["[ TOTAL ]"]["usage"] = " ".join(
                                list(map(str, filterTotal))
                            )

                            cpuProcUsage["[ TOTAL ]"]["count"] = 1
                        else:
                            filterTotal = list(
                                map(
                                    long,
                                    cpuProcUsage["[ TOTAL ]"]["usage"].split(),
                                )
                            )

                            for idx in xrange(len(filterTotal)):
                                filterTotal[idx] += cpuList[idx]

                            cpuProcUsage["[ TOTAL ]"]["usage"] = " ".join(
                                list(map(str, filterTotal))
                            )

                            cpuProcUsage["[ TOTAL ]"]["count"] += 1

                        cpuProcUsage["[ TOTAL ]"]["minimum"] = min(filterTotal)
                        cpuProcUsage["[ TOTAL ]"]["average"] = sum(
                            filterTotal
                        ) / len(filterTotal)
                        cpuProcUsage["[ TOTAL ]"]["maximum"] = max(filterTotal)

                    # update statistics #
                    if not cpuList:
                        cpuProcUsage[pname]["minimum"] = 0
                        cpuProcUsage[pname]["average"] = 0
                        cpuProcUsage[pname]["maximum"] = 0
                    else:
                        cpuProcUsage[pname]["minimum"] = min(cpuList)
                        cpuProcUsage[pname]["average"] = sum(cpuList) / len(
                            cpuList
                        )
                        cpuProcUsage[pname]["maximum"] = max(cpuList)

                    # update lifecycle #
                    if start > -1:
                        cpuProcUsage[pname]["start"] = start
                    if finish > -1:
                        cpuProcUsage[pname]["finish"] = finish
                    if zombie > -1:
                        cpuProcUsage[pname]["zombie"] = zombie

            # DELAY #
            elif context == "Delay":
                if slen == 3:
                    m = re.match(r"\s*(?P<comm>.+)\(\s*(?P<pid>[0-9]+)", line)
                    if not m:
                        continue

                    d = m.groupdict()
                    comm = d["comm"].strip()

                    if SysMgr.filterGroup:
                        if not TaskAnalyzer.checkFilter(comm, d["pid"]):
                            intervalList = None
                        else:
                            pid = d["pid"]
                            pname = "%s(%s)" % (comm, pid)

                            intervalList = sline[2]
                    else:
                        pid = d["pid"]
                        pname = "%s(%s)" % (comm, pid)

                        intervalList = sline[2]
                elif slen == 2:
                    if intervalList:
                        intervalList += sline[1]
                elif intervalList:
                    # save previous info #
                    cpuProcDelay[pname] = {}
                    cpuProcDelay[pname]["pid"] = pid

                    # get lifecycle info #
                    start = -1
                    finish = -1
                    zombie = -1
                    intervalList = intervalList.split()
                    for idx, item in enumerate(list(intervalList)):
                        if item.startswith("+"):
                            start = idx
                            intervalList[idx] = item[1:]
                        if item.startswith("-"):
                            finish = idx
                            intervalList[idx] = item[1:]
                        if item.startswith("z"):
                            zombie = idx
                            intervalList[idx] = item[1:]
                    cpuList = list(map(long, intervalList))
                    intervalList = " ".join(intervalList)

                    cpuProcDelay[pname]["usage"] = intervalList
                    intervalList = None

                    # calculate total usage of tasks filtered #
                    if TaskAnalyzer.checkFilter(comm, pid):
                        if not "[ TOTAL ]" in cpuProcDelay:
                            cpuProcDelay["[ TOTAL ]"] = {}

                            filterTotal = list(
                                map(long, cpuProcDelay[pname]["usage"].split())
                            )

                            cpuProcDelay["[ TOTAL ]"]["usage"] = " ".join(
                                list(map(str, filterTotal))
                            )

                            cpuProcDelay["[ TOTAL ]"]["count"] = 1
                        else:
                            filterTotal = list(
                                map(
                                    long,
                                    cpuProcDelay["[ TOTAL ]"]["usage"].split(),
                                )
                            )

                            for idx in xrange(len(filterTotal)):
                                filterTotal[idx] += cpuList[idx]

                            cpuProcDelay["[ TOTAL ]"]["usage"] = " ".join(
                                list(map(str, filterTotal))
                            )

                            cpuProcDelay["[ TOTAL ]"]["count"] += 1

                        cpuProcDelay["[ TOTAL ]"]["minimum"] = min(filterTotal)
                        cpuProcDelay["[ TOTAL ]"]["average"] = sum(
                            filterTotal
                        ) / len(filterTotal)
                        cpuProcDelay["[ TOTAL ]"]["maximum"] = max(filterTotal)

                    # update statistics #
                    if not cpuList:
                        cpuProcDelay[pname]["minimum"] = 0
                        cpuProcDelay[pname]["average"] = 0
                        cpuProcDelay[pname]["maximum"] = 0
                    else:
                        cpuProcDelay[pname]["minimum"] = min(cpuList)
                        cpuProcDelay[pname]["average"] = sum(cpuList) / len(
                            cpuList
                        )
                        cpuProcDelay[pname]["maximum"] = max(cpuList)

                    # update lifecycle #
                    if start > -1:
                        cpuProcDelay[pname]["start"] = start
                    if finish > -1:
                        cpuProcDelay[pname]["finish"] = finish
                    if zombie > -1:
                        cpuProcDelay[pname]["zombie"] = zombie

            # GPU #
            elif context == "GPU":
                if slen == 3:
                    gname = sline[0].strip()
                    intervalList = sline[2]
                elif slen == 2:
                    if intervalList:
                        intervalList += sline[1]
                elif intervalList and gname != "GPU":
                    # save previous info #
                    gpuUsage[gname] = intervalList
                    intervalList = None

                    """
                    gpuUsage[gname] = {}

                    gpuUsage[gname]['usage'] = intervalList
                    gpuList = list(map(long, intervalList.split()))

                    if not gpuList:
                        gpuUsage[gname]['minimum'] = 0
                        gpuUsage[gname]['average'] = 0
                        gpuUsage[gname]['maximum'] = 0
                    else:
                        gpuUsage[pname]['minimum'] = min(gpuList)
                        gpuUsage[pname]['average'] = \
                            sum(gpuList) / len(gpuList)
                        gpuUsage[pname]['maximum'] = max(gpuList)
                    """

            # VSS #
            elif context == "VSS":
                if slen == 3:
                    m = re.match(r"\s*(?P<comm>.+)\(\s*(?P<pid>[0-9]+)", line)
                    if not m:
                        continue

                    d = m.groupdict()
                    comm = d["comm"].strip().replace("^", "")

                    if not SysMgr.filterGroup:
                        pid = d["pid"]
                        pname = "%s(%s)" % (comm, pid)
                        maxVss = long(sline[1])
                        intervalList = sline[2]
                        continue

                    if not TaskAnalyzer.checkFilter(comm, d["pid"]):
                        intervalList = None
                    else:
                        pid = d["pid"]
                        pname = "%s(%s)" % (comm, pid)
                        maxVss = long(sline[1])
                        intervalList = sline[2]
                elif slen == 2:
                    if intervalList:
                        intervalList += sline[1]
                elif intervalList:
                    # save previous info #
                    try:
                        memProcUsage[pname]
                    except:
                        memProcUsage[pname] = {}
                        memProcUsage[pname]["pid"] = pid

                    memProcUsage[pname]["maxVss"] = maxVss
                    memProcUsage[pname]["vssUsage"] = intervalList
                    intervalList = None

            # RSS / PSS / USS #
            elif (
                SysMgr.rssEnable or SysMgr.pssEnable or SysMgr.ussEnable
            ) and (context == "RSS" or context == "PSS" or context == "USS"):
                if slen == 3:
                    m = re.match(r"\s*(?P<comm>.+)\(\s*(?P<pid>[0-9]+)", line)
                    if not m:
                        continue

                    d = m.groupdict()
                    comm = d["comm"].strip().replace("^", "")

                    if not SysMgr.filterGroup:
                        pid = d["pid"]
                        pname = "%s(%s)" % (comm, pid)
                        maxRss = long(sline[1])
                        intervalList = sline[2]
                        continue

                    if not TaskAnalyzer.checkFilter(comm, d["pid"]):
                        intervalList = None
                    else:
                        pid = d["pid"]
                        pname = "%s(%s)" % (comm, pid)
                        maxRss = long(sline[1])
                        intervalList = sline[2]
                elif slen == 2:
                    if intervalList:
                        intervalList += sline[1]
                elif intervalList:
                    # save previous info #
                    try:
                        memProcUsage[pname]
                    except:
                        memProcUsage[pname] = {}
                        memProcUsage[pname]["pid"] = pid

                    memProcUsage[pname]["maxRss"] = maxRss
                    memProcUsage[pname]["rssUsage"] = intervalList
                    intervalList = None

            # Block #
            elif context == "Block":
                if slen == 3:
                    m = re.match(r"\s*(?P<comm>.+)\(\s*(?P<pid>[0-9]+)", line)
                    if not m:
                        continue

                    d = m.groupdict()
                    comm = d["comm"].strip()

                    if not SysMgr.filterGroup:
                        pid = d["pid"]
                        pname = "%s(%s)" % (comm, pid)

                        try:
                            total = long(sline[1])
                        except:
                            total = sline[1]

                        intervalList = sline[2]
                        continue

                    if not TaskAnalyzer.checkFilter(comm, d["pid"]):
                        intervalList = None
                    else:
                        pid = d["pid"]
                        pname = "%s(%s)" % (comm, pid)

                        try:
                            total = long(sline[1])
                        except:
                            total = sline[1]

                        intervalList = sline[2]
                elif slen == 2:
                    if intervalList:
                        intervalList += sline[1]
                elif intervalList:
                    # save previous info #
                    blkProcUsage[pname] = {}
                    blkProcUsage[pname]["pid"] = pid
                    blkProcUsage[pname]["total"] = total
                    blkProcUsage[pname]["usage"] = intervalList
                    intervalList = None

            # Storage #
            elif context == "Storage":
                if slen == 3:
                    sname = sline[0].strip()
                    intervalList = sline[2]
                elif slen == 2:
                    if intervalList:
                        intervalList += sline[1]
                elif intervalList and (
                    sname != "Device" and sname != "Storage"
                ):
                    # define arrays #
                    storageUsage.setdefault(sname, {})
                    busyList = []
                    readList = []
                    writeList = []
                    freeList = []

                    # convert previous stats #
                    for item in intervalList.split():
                        if item == "0":
                            busy = read = write = free = 0
                        else:
                            busy, read, write, free = item.split("/")
                        busyList.append(long(busy))
                        readList.append(convSize(read) >> 10)
                        writeList.append(convSize(write) >> 10)
                        freeList.append(convSize(free) >> 10)

                    # save previous info #
                    storageUsage[sname]["busy"] = busyList
                    storageUsage[sname]["read"] = readList
                    storageUsage[sname]["write"] = writeList
                    storageUsage[sname]["free"] = freeList
                    intervalList = None

            # Network #
            elif context == "Network":
                if slen == 3:
                    sname = sline[0].strip()
                    intervalList = sline[2]
                elif slen == 2:
                    if intervalList:
                        intervalList += sline[1]
                elif intervalList and (
                    sname != "Device" and sname != "Network"
                ):
                    # define arrays #
                    networkUsage.setdefault(sname, {})
                    recvList = []
                    tranList = []

                    # convert previous stats e
                    for item in intervalList.split():
                        if item == "0":
                            recv = tran = 0
                        else:
                            recv, tran = item.split("/")
                        recvList.append(convSize(recv) >> 10)
                        tranList.append(convSize(tran) >> 10)

                    # save previous info #
                    networkUsage[sname]["recv"] = recvList
                    networkUsage[sname]["tran"] = tranList
                    intervalList = None

            # Meory Details #
            elif context == "Memory":
                if slen != 13:
                    continue

                m = re.match(r"\s*(?P<comm>.+)\(\s*(?P<pid>[0-9]+)", sline[0])
                if m:
                    d = m.groupdict()
                    pid = d["pid"]
                    comm = d["comm"].strip()
                    pname = "%s(%s)" % (comm, pid)
                    chartStats[pname] = {}

                    try:
                        chartStats[pname][sline[1].strip()] = list(
                            map(long, sline[2:-1])
                        )
                    except:
                        pass
                elif long(pid) > 0:
                    try:
                        chartStats[pname][sline[1].strip()] = list(
                            map(long, sline[2:-1])
                        )
                    except:
                        pass

            # Cgroup.cpu Details #
            elif context == "Cgroup.CPU":
                pid = 0

                if slen == 3 and sline[0].startswith("Cgroup"):
                    pass
                elif slen == 3:
                    comm = sline[0].strip()

                    if SysMgr.filterGroup:
                        if not TaskAnalyzer.checkFilter(comm, pid):
                            intervalList = None
                        else:
                            pname = "%s" % comm

                            intervalList = sline[2]
                    else:
                        pname = "%s" % comm

                        intervalList = sline[2]
                elif slen == 2:
                    if intervalList:
                        intervalList += sline[1]
                elif intervalList:
                    # save previous info #
                    cpuProcUsage[pname] = {}
                    cpuProcUsage[pname]["pid"] = pid

                    # get lifecycle info #
                    intervalList = intervalList.split()
                    cpuList = list(map(float, intervalList))
                    cpuList = list(map(long, cpuList))
                    intervalList = list(map(str, cpuList))
                    intervalList = " ".join(intervalList)

                    cpuProcUsage[pname]["usage"] = intervalList
                    intervalList = None

                    # update statistics #
                    if not cpuList:
                        cpuProcUsage[pname]["minimum"] = 0
                        cpuProcUsage[pname]["average"] = 0
                        cpuProcUsage[pname]["maximum"] = 0
                    else:
                        cpuProcUsage[pname]["minimum"] = min(cpuList)
                        cpuProcUsage[pname]["average"] = sum(cpuList) / len(
                            cpuList
                        )
                        cpuProcUsage[pname]["maximum"] = max(cpuList)

        if curSize:
            UtilMgr.deleteProgress()

        # check output data #
        if not totalRam:
            SysMgr.printErr("failed to find statistics data in '%s'" % logFile)
            sys.exit(-1)
        elif not timeline:
            SysMgr.printErr("failed to find interval data in '%s'" % logFile)
            sys.exit(-1)

        # get indexes for trim #
        if "TRIM" in SysMgr.environList or "TRIMIDX" in SysMgr.environList:
            if "TRIM" in SysMgr.environList:
                trim = SysMgr.environList["TRIM"][0].split(":")
            elif "TRIMIDX" in SysMgr.environList:
                trim = SysMgr.environList["TRIMIDX"][0].split(":")

            try:
                if len(trim) == 1:
                    condMin = long(trim[0])
                    condMax = SysMgr.maxSize
                elif len(trim) >= 2:
                    # first tick #
                    if trim[0].strip():
                        condMin = long(trim[0])
                    else:
                        condMin = 0

                    # last tick #
                    if trim[1].strip():
                        condMax = long(trim[1])
                    else:
                        condMax = long(SysMgr.maxSize)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "failed to recognize '%s' as the START:END time"
                    % ":".join(trim)
                )
                sys.exit(-1)

            if "TRIM" in SysMgr.environList:
                # define default values #
                imin = timeline[0]
                imax = timeline[-1]

                # get min index #
                for itime in timeline:
                    if itime >= condMin:
                        imin = itime
                        break

                # get max index #
                for itime in timeline:
                    if itime >= condMax:
                        imax = itime
                        break

                # convert index range #
                imin = timeline.index(imin)
                imax = timeline.index(imax)
            elif "TRIMIDX" in SysMgr.environList:
                imin = condMin
                imax = condMax

            # trim intervals #
            for name, value in cpuProcUsage.items():
                value["usage"] = value["usage"].split()[imin:imax]
                value["usage"] = " ".join(value["usage"])

            for name, value in blkProcUsage.items():
                value["usage"] = value["usage"].split()[imin:imax]
                value["usage"] = " ".join(value["usage"])

            for name, value in memProcUsage.items():
                if "vssUsage" in value:
                    value["vssUsage"] = value["vssUsage"].split()[imin:imax]
                    value["vssUsage"] = " ".join(value["vssUsage"])
                if "rssUsage" in value:
                    value["rssUsage"] = value["rssUsage"].split()[imin:imax]
                    value["rssUsage"] = " ".join(value["rssUsage"])

            for name, value in gpuUsage.items():
                value = value.split()[imin:imax]
                gpuUsage[name] = " ".join(value)

            for name, dev in storageUsage.items():
                for item, value in dev.items():
                    storageUsage[name][item] = value[imin:imax]

            for name, dev in networkUsage.items():
                for item, value in dev.items():
                    networkUsage[name][item] = value[imin:imax]
        else:
            # set range index #
            imin = 0
            imax = len(timeline)

        # set graph argument list #
        graphStats = {
            "timeline": timeline[imin:imax],
            "eventList": eventList[imin:imax],
            "cpuUsage": cpuUsage[imin:imax],
            "cpuProcUsage": cpuProcUsage,
            "cpuProcDelay": cpuProcDelay,
            "blkWait": blkWait[imin:imax],
            "blkProcUsage": blkProcUsage,
            "blkRead": blkRead[imin:imax],
            "blkWrite": blkWrite[imin:imax],
            "netRead": netRead[imin:imax],
            "netWrite": netWrite[imin:imax],
            "memFree": memFree[imin:imax],
            "memAnon": memAnon[imin:imax],
            "memCache": memCache[imin:imax],
            "memProcUsage": memProcUsage,
            "gpuUsage": gpuUsage,
            "totalRam": totalRam,
            "swapUsage": swapUsage[imin:imax],
            "totalSwap": totalSwap,
            "reclaimBg": reclaimBg[imin:imax],
            "reclaimDr": reclaimDr[imin:imax],
            "storageUsage": storageUsage,
            "networkUsage": networkUsage,
            "nrCore": nrCore[imin:imax],
            "nrTask": nrTask[imin:imax],
            "graphTitle": "Guider Perf Graph",
            "start": startTime,
        }

        return graphStats, chartStats

    def getAvgStats(self, flist, stats):
        # pylint: disable=undefined-variable

        # make file index table #
        fileIdxList = {}
        for idx, fname in enumerate(flist):
            fileIdxList[fname] = idx

        avgList = {}

        for name, value in stats.items():
            # set graph title #
            if name == "graphTitle":
                avgList.setdefault(name, "Guider Average Graph")
                continue

            try:
                fname, sname = name.split(":", 1)
            except:
                SysMgr.printErr(
                    "failed to get file name from '%s" % name, True
                )
                sys.exit(-1)

            if sname.endswith("List"):
                continue
            elif sname.endswith("ProcUsage"):
                avgList.setdefault(sname, {})

                for proc, pvalue in value.items():
                    pname = proc.split("(", 1)[0].lstrip("*")
                    avgList[sname].setdefault(pname, [0] * len(flist))
                    if sname == "cpuProcUsage":
                        usage = pvalue["average"]
                    elif sname == "memProcUsage":
                        if "rssUsage" in pvalue:
                            mname = "rssUsage"
                        else:
                            mname = "vssUsage"
                        mlist = list(map(long, pvalue[mname].split()))
                        usage = max(mlist)
                    else:
                        continue

                    # add average usage #
                    avgList[sname][pname][fileIdxList[fname]] += usage
            elif type(value) is list:
                if not value:
                    usage = 0
                elif isinstance(value[0], (int, long)):
                    usage = round(sum(value) / len(value), 1)
                else:
                    continue

                avgList.setdefault(sname, [0] * len(flist))
                avgList[sname][fileIdxList[fname]] = usage
            elif type(value) is dict:
                avgList.setdefault(sname, {})

                for item, val in value.items():
                    if UtilMgr.isString(val):
                        val = list(map(long, val.split()))
                        usage = round(sum(val) / len(val), 1)
                    else:
                        continue

                    avgList[sname].setdefault(item, [0] * len(flist))
                    avgList[sname][item][fileIdxList[fname]] = usage
            else:
                avgList.setdefault(sname, value)

        return avgList

    @staticmethod
    def drawBitmap(inputFile, unit=4096):
        # pylint: disable=undefined-variable

        # check file #
        if type(inputFile) is list:
            if len(inputFile) > 1:
                SysMgr.printErr("no support multiple files")
                sys.exit(0)
            inputFile = inputFile[0]

        # load bitmap from file #
        try:
            table = list(open(inputFile, "rb").read())
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to read bitmap from '%s'" % inputFile, True
            )
            sys.exit(0)

        # initialize environment for drawing #
        TaskAnalyzer.initDrawEnv()

        # set frame #
        _, ax = subplots()

        # set title #
        suptitle("Guider Bitmap", fontsize=8)

        # set size of table #
        num = long(len(table) ** (1 / 2))

        # convert 0 values #
        table = [3 if not val else val for val in table]

        # get stats and build info string #
        nrTotal = len(table)
        nrExist = table.count(1)
        nrEmpty = table.count(3)
        convNum = UtilMgr.convNum
        info = (
            "- Unit: %s\n" "- Total: %s\n" "- Used: %s\n" "- Unused: %s\n"
        ) % (
            convNum(unit),
            convNum(nrTotal * unit),
            convNum(nrExist * unit),
            convNum(nrEmpty * unit),
        )

        # create a new bitmap #
        bitmap = []
        prevPos = 0
        for pos in xrange(num, len(table), num):
            bitmap.append(table[prevPos:pos])
            prevPos = pos

        # attach remaining bits #
        if prevPos < len(table) - 1:
            last = table[prevPos : len(table)]
            last += [2] * (num - len(last))
            bitmap.append(last)

        # draw base #
        figObj = TaskAnalyzer.drawFigure()

        # draw bitmap #
        ax.imshow(
            bitmap,
            cmap="RdGy",
            aspect="auto",
            interpolation="nearest",
            extent=[0, num, num, 0],
        )

        # set font size #
        if "FONTSIZE" in SysMgr.environList:
            fontsize = UtilMgr.getEnvironNum("FONTSIZE", isInt=True)
        else:
            fontsize = 3

        # set ticks #
        ax.set_xticks(xrange(0, num, 1))
        ax.set_yticks(xrange(0, num, 1))
        ax.grid(color="w", linewidth=0.1)

        # set font size #
        xticks(fontsize=fontsize)
        yticks(fontsize=fontsize)

        # draw bitmap info #
        figObj.text(0, 1, info, va="top", ha="left", size=3)

        # save map to file #
        TaskAnalyzer.saveImage(inputFile, "bitmap")

    @staticmethod
    def drawFigure():
        # pylint: disable=undefined-variable
        # ticklabel_format(useOffset=False)
        locator_params(axis="x", nbins=30)
        obj = figure(num=1, figsize=(10, 10), facecolor="b", edgecolor="k")
        obj.subplots_adjust(left=0.06, top=0.95, bottom=0.04, hspace=0.3)
        return obj

    @staticmethod
    def drawName(ax, name, fontsize=20):
        # pylint: disable=undefined-variable
        xticks = ax.get_xticks().tolist()
        yticks = ax.get_yticks().tolist()

        x = xticks[long(len(xticks) * 1 / 2)] - fontsize / len(name)
        y = yticks[long(len(yticks) * 1 / 2)]

        annotate(
            name,
            xy=(x, y),
            xytext=(x, y),
            fontsize=fontsize,
            fontweight="bold",
            color="gray",
            alpha=0.1,
        )

    @staticmethod
    def drawYticks(ax, ymax, fontsize=5, adjust=True):
        # pylint: disable=undefined-variable
        if "YRANGE" in SysMgr.environList:
            yminval, ymaxval = SysMgr.environList["YRANGE"][0].split(":")

            # set ymin #
            try:
                yminval = long(yminval)
            except:
                yminval = 0
            finally:
                if yminval:
                    ax.set_ylim(bottom=long(yminval))
                    ymin = long(yminval)
                else:
                    ymin = long(min(ax.get_yticks().tolist()))
                    if ymin < 0:
                        ymin = 0
                        ax.set_ylim(bottom=0)

            # set ymax #
            try:
                ymaxval = long(ymaxval)
            except:
                ymaxval = 0
            finally:
                if ymaxval:
                    ax.set_ylim(top=long(ymaxval))
                    ymax = long(ymaxval)
                else:
                    ymax = long(min(ax.get_yticks().tolist()))

            # adjust ticks #
            if adjust:
                inc = long(ymax / 10)
                if inc == 0:
                    inc = 1
                yticks(xrange(ymin, long(ymax + inc), inc), fontsize=fontsize)
            else:
                yticks(fontsize=fontsize)
        else:
            if ymax is None:
                ylist = ax.get_yticks().tolist()
                ymax = long(max(ylist))

            ymaxval = ymax + int(ymax / 10)
            if ymaxval > 0:
                ylim([0, ymaxval])

            # get final yticks #
            ylist = ax.get_yticks().tolist()
            ymin = long(min(ylist))
            if ymin < 0:
                ymin = 0
                ax.set_ylim(bottom=0)

            # adjust yticks #
            if adjust:
                inc = long(ymax / 10)
                if inc == 0:
                    inc = 1
                yticks(xrange(ymin, long(ymax + inc), inc), fontsize=fontsize)
            else:
                yticks(fontsize=fontsize)

        # apply formatter #
        try:
            ytickLabel = ax.get_yticks().tolist()
            ytickLabel = list(map(long, ytickLabel))

            # convert label units #
            convNum = UtilMgr.convNum
            ytickLabel = [convNum(val) for val in ytickLabel]

            # apply formatter #
            ax.set_yticks(ax.get_yticks().tolist())
            ax.set_yticklabels(ytickLabel)
        except:
            pass

    @staticmethod
    def drawLabel(
        labelList,
        draw=True,
        anchor=(1.12, 0.75),
        loc="upper right",
        fontsize=3.5,
        markerfirst=False,
    ):
        # pylint: disable=undefined-variable

        # check labels #
        if not labelList:
            return

        # set legend position #
        if SysMgr.matplotlibVersion >= 1.2:
            if labelList:
                res = legend(
                    labelList,
                    bbox_to_anchor=anchor,
                    fontsize=fontsize,
                    loc=loc,
                    markerfirst=markerfirst,
                )
            elif draw:
                res = legend(
                    bbox_to_anchor=anchor,
                    fontsize=fontsize,
                    loc=loc,
                    markerfirst=markerfirst,
                )
            else:
                res = None
        else:
            if labelList:
                res = legend(
                    labelList,
                    bbox_to_anchor=anchor,
                    loc=loc,
                    markerfirst=markerfirst,
                )
            elif draw:
                res = legend(
                    bbox_to_anchor=anchor, loc=loc, markerfirst=markerfirst
                )
            else:
                res = None

        # set zorder #
        if res:
            res.set_zorder(1)

    @staticmethod
    def initDrawEnv():
        # pylint: disable=import-error

        # get matplotlib object #
        matplotlib = SysMgr.getPkg("matplotlib", False)
        if not matplotlib:
            SysMgr.printPipWarn("matplotlib", "matplotlib")
            sys.exit(-1)

        from matplotlib.ticker import MaxNLocator

        SysMgr.matplotlibVersion = float(
            ".".join(matplotlib.__version__.split(".")[:2])
        )

        matplotlib.use("Agg")

        # get pylab object #
        SysMgr.importPkgItems("pylab")

        # set dpi #
        matplotlib.rcParams["figure.dpi"] = SysMgr.matplotlibDpi

        return matplotlib

    def drawStats(self, flist, outFile=None, onlyGraph=False, onlyChart=False):
        def _printMemUsage(signum=None, frame=None):
            pid = SysMgr.pid
            comm = SysMgr.getComm(pid)

            try:
                mlist = SysMgr.getMemStat(pid)
                mstat = SysMgr.convMemStat(mlist)
                vss = UtilMgr.convSize2Unit(mstat["vss"], isInt=True, unit="M")
                rss = UtilMgr.convSize2Unit(mstat["rss"], isInt=True, unit="M")
                avl = SysMgr.getAvailMemInfo(unit="M")
                SysMgr.printWarn(
                    "System's AvailableMemory(%s), %s(%s)'s VSS(%s) & RSS(%s)"
                    % (avl, comm, pid, vss, rss),
                    True,
                )
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "failed to get memory usage for %s(%s)" % (pid, comm), True
                )

            signal.alarm(SysMgr.intervalEnable)

        # convert str to list #
        if type(flist) is str:
            flist = [flist]

        # get stats from a single file #
        if len(flist) == 1:
            logFile = flist[0]

            # parse stats #
            graphStats, chartStats = TaskAnalyzer.getStatsFile(logFile)
        # get stats from multiple files for comparison #
        else:
            logFile = SysMgr.outFilePath

            # define integrated stats #
            graphStats = {}
            chartStats = {}
            timeList = {}

            # get only start flag #
            if "CONCATENATE" in SysMgr.environList:
                concatenated = True
            else:
                concatenated = False

            # parse stats from multiple files #
            for lfile in flist:
                try:
                    gstats, cstats = TaskAnalyzer.getStatsFile(
                        lfile, onlyStart=concatenated
                    )
                except SystemExit:
                    sys.exit(0)
                except:
                    continue

                # merge stats for concatenation temporally #
                if concatenated:
                    try:
                        timeList[gstats["start"]] = lfile
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass
                    continue

                # merge stats #
                for key, val in gstats.items():
                    fname = os.path.basename(lfile)
                    if key == "graphTitle":
                        graphStats[key] = val
                    else:
                        graphStats["%s:%s" % (fname, key)] = val

            # concatenate stats in order #
            if concatenated:
                # set alarm for printing meory usage #
                if not SysMgr.intervalEnable:
                    SysMgr.intervalEnable = 1
                signal.signal(signal.SIGALRM, _printMemUsage)
                signal.alarm(SysMgr.intervalEnable)

                mergedData = []
                for stime, path in sorted(
                    timeList.items(),
                    key=lambda e: e[0],
                    reverse=True,
                ):
                    mergedData += TaskAnalyzer.getSummaryData(path)

                # save merged data #
                SysMgr.procBuffer = mergedData

                # set temporary output path for merged data #
                SysMgr.printFd = None
                SysMgr.pipeForPager = None
                origOutput = SysMgr.outPath
                if SysMgr.outPath:
                    SysMgr.outPath = os.path.dirname(origOutput)
                    if not SysMgr.outPath:
                        SysMgr.outPath = "."
                else:
                    SysMgr.outPath = "."
                SysMgr.outPath = os.path.join(
                    SysMgr.outPath, "merged_%s.out" % SysMgr.pid
                )

                # print summary #
                try:
                    SysMgr.printStat("start summarizing...")

                    # get only total flag #
                    if "ONLYTOTAL" in SysMgr.environList:
                        onlyTotal = True
                    else:
                        onlyTotal = False

                    # set ignore flags #
                    checkMode = SysMgr.checkMode
                    addEnv = SysMgr.addEnvironVar

                    # check processor #
                    if not any(
                        [checkMode("draw", True), checkMode("drawcpu", True)]
                    ):
                        addEnv("NOCPUSUMMARY")
                        addEnv("NOGPUSUMMARY")

                    # check delay #
                    if not checkMode("drawdelay", True):
                        addEnv("NODELAYSUMMARY")

                    # check vss #
                    if not any(
                        [
                            checkMode("drawvss", True),
                            checkMode("drawleak", True),
                        ]
                    ):
                        addEnv("NOVSSSUMMARY")

                    # check rss #
                    if not checkMode("drawrss", True):
                        addEnv("NORSSSUMMARY")

                    # check io #
                    if not any(
                        [checkMode("draw", True), checkMode("drawio", True)]
                    ):
                        addEnv("NOBLOCKSUMMARY")
                        addEnv("NOSTORAGESUMMARY")
                        addEnv("NONETSUMMARY")

                    # ignore life info #
                    addEnv("NOLIFESUMMARY")

                    # print interval info for drawing #
                    TaskAnalyzer.printIntervalUsage(
                        onlyTotal=onlyTotal, onlySummary=True
                    )
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(
                        "failed to print interval summary", reason=True
                    )

                # clean up #
                targetFile = SysMgr.printFd.name
                del SysMgr.procBuffer
                SysMgr.procBuffer = []
                SysMgr.printFd = None
                SysMgr.outPath = origOutput

                try:
                    gstats, cstats = TaskAnalyzer.getStatsFile(targetFile)
                except SystemExit:
                    sys.exit(0)
                except:
                    sys.exit(-1)

                # merge stats #
                graphStats = gstats

        # initialize environment for drawing #
        TaskAnalyzer.initDrawEnv()

        # draw avreage graphs #
        if SysMgr.avgEnable:
            try:
                # convert pull path to file name #
                fnameList = [os.path.basename(fname) for fname in flist]
                if len(fnameList) < 2:
                    raise Exception("of input for multiple files")
                graphStats = self.getAvgStats(fnameList, graphStats)
                graphStats["fileList"] = fnameList
                self.drawAvgGraph(graphStats, logFile, outFile=outFile)
            except SystemExit:
                return
            except:
                SysMgr.printErr("failed to draw history graph", True)
            finally:
                return

        # draw graphs #
        try:
            if not onlyChart:
                self.drawGraph(graphStats, logFile, outFile=outFile)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to draw graph", True)
            return

        # draw charts #
        try:
            if not onlyGraph:
                self.drawChart(chartStats, logFile, outFile=outFile)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to draw chart", True)
            return

    def drawChart(self, data, logFile, outFile=None):
        # pylint: disable=undefined-variable

        if not data:
            return

        def _make_autopct(values):
            def _autopct(pct):
                total = sum(values)
                val = long(round(pct * total / 100.0)) << 20
                val = UtilMgr.convSize2Unit(val, True)
                usage = "{v:s} ({p:.0f}%)".format(p=pct, v=val)
                line = "=" * 7
                string = "{s:1}\n{l:1}{d:1}".format(
                    s=usage, d=self.details[self.tmpCnt], l=line
                )
                self.tmpCnt += 1
                return string

            return _autopct

        SysMgr.printStat(r"start drawing charts...")

        # init variables #
        seq = 0

        height = (
            long(len(data) / 2)
            if len(data) & 1 != 0
            else long(len(data) / 2 + 1)
        )

        colors = [
            "pink",
            "lightgreen",
            "skyblue",
            "lightcoral",
            "gold",
            "yellowgreen",
        ]

        propList = [
            "count",
            "vmem",
            "rss",
            "pss",
            "swap",
            "huge",
            "locked",
            "pdirty",
            "sdirty",
        ]

        convSize = UtilMgr.convSize2Unit

        # set title #
        suptitle("Guider Memory Chart", fontsize=8)

        for idx, item in sorted(
            data.items(),
            key=lambda e: e[1]["[TOTAL]"][propList.index("rss")]
            + e[1]["[TOTAL]"][propList.index("swap")],
            reverse=True,
        ):
            labels = []
            sizes = []
            explode = []
            self.details = []
            self.tmpCnt = 0

            if item["[TOTAL]"][propList.index("count")] == 0:
                continue

            for prop, value in item.items():
                if prop == "[TOTAL]" or (
                    value[propList.index("rss")] == 0
                    and value[propList.index("swap")] == 0
                ):
                    continue

                # add label of property and its property count #
                labels.append(
                    "%s(%s)" % (prop, value[propList.index("count")])
                )

                sizes.append(
                    value[propList.index("rss")]
                    + value[propList.index("swap")]
                )

                # set private dirty size #
                pdrt = convSize(value[propList.index("pdirty")] << 10, True)

                # set shared dirty size #
                sdrt = convSize(value[propList.index("sdirty")] << 10, True)

                # set rss size #
                rss = convSize(value[propList.index("rss")] << 20, True)

                # set swap size #
                swap = convSize(value[propList.index("swap")] << 20, True)

                # set locked size #
                locked = convSize(value[propList.index("locked")] << 10, True)

                self.details.append(
                    (
                        "\n- RSS  : %5s \n- SWAP : %5s \n%s\n"
                        "- LOCK : %5s \n- PDRT : %5s \n- SDRT : %5s"
                    )
                    % (rss, swap, "=" * 7, locked, pdrt, sdrt)
                )

            # convert labels to tuple #
            labels = tuple(labels)

            # find and mark index of max value #
            explode = [0] * len(sizes)
            explode[sizes.index(max(sizes))] = 0.03

            # set size and position of this chart #
            try:
                ypos = seq >> 1
                xpos = seq - (ypos << 1)
                ax = subplot2grid(
                    (height, 2), (ypos, xpos), rowspan=1, colspan=1
                )
                ax.xaxis.set_major_locator(MaxNLocator(integer=True))
            except SystemExit:
                sys.exit(0)
            except:
                continue

            # get property of process #
            line = "_" * len(idx) * 1

            rss = item["[TOTAL]"][propList.index("rss")]
            swap = item["[TOTAL]"][propList.index("swap")]
            total = convSize((rss + swap) << 20)

            rss = convSize(rss << 20)
            swap = convSize(swap << 20)
            vmem = convSize(item["[TOTAL]"][propList.index("vmem")] << 20)
            pss = convSize(item["[TOTAL]"][propList.index("pss")] << 20)
            lock = convSize(item["[TOTAL]"][propList.index("locked")] << 10)
            dirty = (
                item["[TOTAL]"][propList.index("pdirty")]
                + item["[TOTAL]"][propList.index("sdirty")]
            )
            dirty = convSize(dirty << 10)

            totalList = [
                (
                    "\n%s\n%s\n\n- %-5s: %7s\n- %-5s: %7s\n- %-5s: %7s\n%s\n\n"
                    "- %-5s: %7s\n- %-5s: %7s\n- %-5s: %7s\n- %-5s: %7s"
                )
                % (
                    "[%s] %s" % (str(seq + 1), idx),
                    line,
                    "TOTAL",
                    total,
                    "RSS",
                    rss,
                    "SWAP",
                    swap,
                    line,
                    "VSS",
                    vmem,
                    "PSS",
                    pss,
                    "LOCK",
                    lock,
                    "DIRTY",
                    dirty,
                )
            ]

            # draw chart #
            if SysMgr.matplotlibVersion >= 1.2:
                patches, texts, autotexts = pie(
                    sizes,
                    explode=explode,
                    labels=labels,
                    colors=colors,
                    autopct=_make_autopct(sizes),
                    shadow=True,
                    startangle=50,
                    pctdistance=0.5,
                )
            else:
                patches, texts, autotexts = pie(
                    sizes,
                    explode=explode,
                    labels=labels,
                    colors=colors,
                    autopct=_make_autopct(sizes),
                    shadow=True,
                    pctdistance=0.5,
                )

            # set font size #
            for idx, val in enumerate(texts):
                val.set_fontsize(self.xfsize + 1)
                autotexts[idx].set_fontsize(self.lfsize)
            axis("equal")

            # print total size in legend #
            if SysMgr.matplotlibVersion >= 1.2:
                legend(
                    patches,
                    totalList,
                    loc="lower right",
                    shadow=True,
                    fontsize=self.xfsize,
                    handlelength=0,
                    bbox_to_anchor=(1.2, 0.01),
                )
            else:
                legend(
                    patches,
                    totalList,
                    loc="lower right",
                    shadow=True,
                    handlelength=0,
                    bbox_to_anchor=(1.2, 0.01),
                )

            seq += 1

        # draw image #
        figure(
            num=1, figsize=(10, 10), facecolor="b", edgecolor="k"
        ).subplots_adjust(left=0, top=0.9, bottom=0.02, hspace=0.1, wspace=0.1)

        # save to file #
        TaskAnalyzer.saveImage(logFile, "chart", outFile=outFile)

    def drawLayout(self, graphStats, _drawCpu, _drawMem, _drawIo, _drawEvent):
        pos = 0
        total = 0
        layoutDict = {}
        layoutList = []
        layout = SysMgr.layout.split(",")

        # sum size of graph boxes #
        for idx, graph in enumerate(layout):
            try:
                if len(graph.split(":")) == 1:
                    target = graph
                    size = 1
                else:
                    (target, size) = graph.split(":")

                # check duplicated graph #
                try:
                    layoutDict[target]
                    SysMgr.printErr(
                        "failed to draw graph "
                        "because %s graph is duplicated" % target
                    )
                    sys.exit(-1)
                except SystemExit:
                    sys.exit(0)
                except:
                    layoutDict[target] = True

                size = long(size)
                assert size > 0, "wrong size"

                total += size
                layoutList.append([target, long(size)])
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "failed to draw graph "
                    "because graph format [TYPE:SIZE] is wrong"
                )
                sys.exit(-1)

        for idx, item in enumerate(layoutList):
            target = item[0].strip()
            size = item[1]

            # convert size to proportion #
            size = long((size / float(total)) * 6)

            try:
                xtype = len(layoutList) - idx

                targetc = target.upper()

                if targetc == "CPU" or targetc.startswith("C"):
                    _drawCpu(graphStats, xtype, pos, size)
                elif targetc == "DELAY" or targetc.startswith("D"):
                    _drawCpu(graphStats, xtype, pos, size, delay=True)
                elif targetc == "MEM" or targetc.startswith("M"):
                    _drawMem(graphStats, xtype, pos, size)
                elif targetc == "VSS" or targetc.startswith("V"):
                    SysMgr.vssEnable = True
                    _drawMem(graphStats, xtype, pos, size)
                elif targetc == "RSS" or targetc.startswith("R"):
                    SysMgr.rssEnable = True
                    _drawMem(graphStats, xtype, pos, size)
                elif targetc == "IO" or targetc.startswith("I"):
                    if _drawIo:
                        _drawIo(graphStats, xtype, pos, size)
                else:
                    SysMgr.printErr(
                        "failed to draw graph "
                        "because '%s' is not recognized" % target
                    )
                    sys.exit(-1)

                if _drawEvent and idx == 0:
                    # draw events on graphs #
                    _drawEvent(graphStats)

                pos += size
            except SystemExit:
                sys.exit(0)
            except:
                err = SysMgr.getErrMsg()
                raise Exception(err)

    def drawBottom(self, xtype, ax, timeline, nrTask, effectProcList):
        # pylint: disable=undefined-variable
        if xtype == 1:
            # convert tick type to integer #
            try:
                xtickLabel = ax.get_xticks().tolist()
                xtickLabel = list(map(long, xtickLabel))

                # apply relative time #
                if "RELTIME" in SysMgr.environList:
                    try:
                        start = xtickLabel[0]
                        xtickLabel = [val - start for val in xtickLabel]
                    except:
                        pass

                # apply time format #
                if not "NOTIMEFORMAT" in SysMgr.environList:
                    try:
                        xtickLabel = list(map(UtilMgr.convTime, xtickLabel))
                    except:
                        pass

                for idx, item in enumerate(list(xtickLabel)):
                    if idx & 1:
                        xtickLabel[idx] = "\n%s" % item
                ax.set_xticklabels(xtickLabel)

                lastIdx = len(ax.get_xticks().tolist())
                xtickLabel[lastIdx - 1] += "\nTIME(Sec)".expandtabs()
                xtickLabel[lastIdx - 1] = xtickLabel[lastIdx - 1].lstrip("\n")
                ax.set_xticklabels(xtickLabel)
            except SystemExit:
                sys.exit(0)
            except:
                pass
        elif xtype == 3:
            # draw the number of running tasks #
            try:
                xtickLabel = ax.get_xticks().tolist()
                xlim([xtickLabel[0], xtickLabel[-1]])
                if sum(effectProcList) == 0:
                    for seq, cnt in enumerate(xtickLabel):
                        xtickLabel[seq] = "?"
                else:
                    for seq, cnt in enumerate(xtickLabel):
                        try:
                            xtickLabel[seq] = UtilMgr.convNum(
                                effectProcList[timeline.index(long(cnt))]
                            )
                        except SystemExit:
                            sys.exit(0)
                        except:
                            xtickLabel[seq] = " "

                ax.set_xticklabels(xtickLabel)
                lastIdx = len(ax.get_xticks().tolist())
                xtickLabel[lastIdx - 1] += "\nRUN(NR)".expandtabs()
                xtickLabel[lastIdx - 1] = xtickLabel[lastIdx - 1].lstrip("\n")
                ax.set_xticklabels(xtickLabel)
            except SystemExit:
                sys.exit(0)
            except:
                pass
        elif xtype == 2:
            # draw the number of total tasks (proc/thread) #
            try:
                xtickLabel = ax.get_xticks().tolist()
                xlim([xtickLabel[0], xtickLabel[-1]])
                for seq, cnt in enumerate(xtickLabel):
                    try:
                        val = nrTask[timeline.index(long(cnt))]
                        if seq & 1:
                            xtickLabel[seq] = "\n%s" % val
                        else:
                            xtickLabel[seq] = val
                    except SystemExit:
                        sys.exit(0)
                    except:
                        xtickLabel[seq] = " "

                ax.set_xticklabels(xtickLabel)
                lastIdx = len(ax.get_xticks().tolist())
                xtickLabel[lastIdx - 1] += "\nTASK(NR)".expandtabs()
                xtickLabel[lastIdx - 1] = xtickLabel[lastIdx - 1].lstrip("\n")
                ax.set_xticklabels(xtickLabel)
            except SystemExit:
                sys.exit(0)
            except:
                pass

    def drawUserEvent(self, mode=None):
        # pylint: disable=undefined-variable

        if not "EVENT" in SysMgr.environList:
            return

        for item in SysMgr.environList["EVENT"]:
            try:
                values = item.split(":")
                if not (3 <= len(values) <= 5):
                    SysMgr.printErr(
                        (
                            "failed to recognize %s in "
                            "X:Y:NAME:[CPU|MEM|IO]:[BOX|CIRCLE|LARROW|RARROW]"
                            "format"
                        )
                        % item
                    )
                    sys.exit(-1)

                # get values #
                if len(values) == 5:
                    x, y, name, resource, feature = values
                elif len(values) == 4:
                    x, y, name, resource = values
                    feature = "none"
                elif len(values) == 3:
                    x, y, name = values
                    feature = "none"
                    resource = "none"

                # check type #
                if mode and mode.upper() != resource.upper():
                    continue

                # get feature #
                if feature.upper() == "CIRCLE":
                    feature = "Circle,pad=1"
                elif feature.upper() == "LARROW":
                    feature = "LArrow,pad=1"
                elif feature.upper() == "RARROW":
                    feature = "RArrow,pad=1"
                else:
                    feature = "Roundtooth,pad=1"

                # draw text #
                text(
                    long(x),
                    long(y),
                    name,
                    style="italic",
                    fontsize=self.lfsize * 2,
                    color="green",
                    fontweight="bold",
                    bbox=dict(boxstyle=feature, facecolor="gold", alpha=0.7),
                )
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("failed to draw events", reason=True)
                sys.exit(-1)

    def drawBoundary(self, gtype, labelList):
        # pylint: disable=undefined-variable

        if not SysMgr.boundaryLine:
            return

        try:
            boundaryList = list(
                map(UtilMgr.convUnit2Size, SysMgr.boundaryLine)
            )
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to set boundary line", True)
            sys.exit(-1)

        # draw boundary graph #
        for boundary in boundaryList:
            if gtype == "io":
                bl = boundary >> 10
            elif gtype == "mem":
                bl = boundary >> 20
            else:
                bl = boundary

            try:
                axhline(y=bl, linewidth=1, linestyle="--", color="black")

                labelList.append(
                    "[ Boundary %s ]" % UtilMgr.convSize2Unit(boundary)
                )
            except SystemExit:
                sys.exit(0)
            except:
                continue

    def drawGraph(self, graphStats, logFile, outFile=None):
        # pylint: disable=undefined-variable

        # ==================== DEFINE PART ====================#
        def _getTextAlign(idx, timeline):
            if idx < len(timeline) / 4:
                return "left"
            elif idx > len(timeline) / 4 * 3:
                return "right"
            else:
                return "center"

        def _drawEvent(graphStats):
            # get minimum timeline #
            timeline = None
            for key, val in graphStats.items():
                if not key.endswith("timeline"):
                    continue
                elif not timeline:
                    timeline = val
                elif len(timeline) > len(val):
                    timeline = val
            lent = len(timeline)

            # get exclude event list #
            if "EXEVENT" in SysMgr.environList:
                exEventList = SysMgr.environList["EXEVENT"]
            else:
                exEventList = None

            # get include event list #
            if "INEVENT" in SysMgr.environList:
                inEventList = SysMgr.environList["INEVENT"]
            else:
                inEventList = None

            # start loop #
            for key, val in graphStats.items():
                if not key.endswith("timeline"):
                    continue

                res = key.split(":")
                if len(res) > 1:
                    fname = "%s:" % res[0]
                    prefix = "[%s] " % res[0]
                else:
                    fname = ""
                    prefix = ""

                # get event table #
                eventList = graphStats["%seventList" % fname]

                for tm, evts in enumerate(eventList):
                    if not evts:
                        continue

                    # filter inclusive events #
                    if inEventList:
                        newEvts = []
                        for evt in evts:
                            if not UtilMgr.isValidStr(evt, inEventList):
                                continue
                            newEvts.append(evt)
                        evts = newEvts

                    # filter exclusive events #
                    if exEventList:
                        newEvts = []
                        for evt in evts:
                            if UtilMgr.isValidStr(evt, exEventList):
                                continue
                            newEvts.append(evt)
                        evts = newEvts

                    evtbox = prefix + "\n".join(evts)

                    try:
                        text(
                            timeline[tm],
                            ylim()[-1],
                            evtbox,
                            fontsize=self.lfsize,
                            verticalalignment="top",
                            style="italic",
                            bbox={
                                "facecolor": "green",
                                "alpha": 0.5,
                                "pad": 1,
                            },
                            ha="left",
                        )

                        axvline(
                            x=timeline[tm],
                            linewidth=1,
                            linestyle="--",
                            color="green",
                        )
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass

        def _getPathEffect(lw=2):
            try:
                pe = SysMgr.getPkg("matplotlib.patheffects", False)
                return [
                    pe.Stroke(linewidth=lw, foreground="black"),
                    pe.Normal(),
                ]
            except SystemExit:
                sys.exit(0)
            except:
                return []

        def _getPlotAttr(idx):
            try:
                lw = 0.7
                pe = []

                if not "STROKE" in SysMgr.environList:
                    pass
                elif UtilMgr.isValidStr(idx, SysMgr.environList["STROKE"]):
                    lw = 1
                    pe = _getPathEffect()
            except:
                pass

            return lw, pe

        def _drawCpu(graphStats, xtype, pos, size, delay=False):
            # draw title #
            ax = subplot2grid((6, 1), (pos, 0), rowspan=size, colspan=1)
            ax.xaxis.set_major_locator(MaxNLocator(integer=True))
            suptitle(graphStats["graphTitle"], fontsize=8)

            # define common label list #
            ymax = 0
            labelList = []

            # get minimum timeline #
            timeline = None
            for key, val in graphStats.items():
                if not key.endswith("timeline"):
                    continue
                elif not timeline:
                    timeline = val
                elif len(timeline) > len(val):
                    timeline = val
            lent = len(timeline)

            conv = UtilMgr.convNum

            # start loop #
            cnt = 0
            for key, val in graphStats.items():
                if not key.endswith("timeline"):
                    continue

                res = key.split(":")
                if len(res) > 1:
                    fname = "%s:" % res[0]
                    prefix = "[%s] " % res[0]
                else:
                    fname = ""
                    prefix = ""

                cpuUsage = graphStats["%scpuUsage" % fname][:lent]
                cpuProcUsage = graphStats["%scpuProcUsage" % fname]
                cpuProcDelay = graphStats["%scpuProcDelay" % fname]
                blkWait = graphStats["%sblkWait" % fname][:lent]
                blkProcUsage = graphStats["%sblkProcUsage" % fname]
                gpuUsage = graphStats["%sgpuUsage" % fname]
                nrCore = graphStats["%snrCore" % fname]
                maxCore = max(nrCore)

                # convert total CPU usage by core number #
                if not SysMgr.cpuAvgEnable:
                    cpuUsage = [maxCore * i for i in cpuUsage]

                # set visible total usage flag #
                if SysMgr.showAll or not SysMgr.filterGroup:
                    isVisibleTotal = True
                else:
                    isVisibleTotal = False

                # add boundary line #
                self.drawBoundary("cpu", labelList)

                # draw user event #
                self.drawUserEvent("cpu")

                # System Processor usage #
                if not delay and isVisibleTotal:
                    # ------------------ Total GPU usage ------------------#
                    for gpu, stat in gpuUsage.items():
                        stat = list(map(long, stat.split()))[:lent]
                        try:
                            if min(stat) == max(stat):
                                continue
                        except:
                            pass

                        # set color #
                        if prefix:
                            gcolor = None
                        else:
                            gcolor = "olive"

                        # draw total GPU graph #
                        plot(
                            timeline,
                            stat,
                            "-",
                            c=gcolor,
                            linestyle="--",
                            linewidth=1,
                            marker="d",
                            markersize=1,
                            path_effects=_getPathEffect(),
                            solid_capstyle="round",
                        )

                        totalUsage = sum(stat)

                        try:
                            avgUsage = round(totalUsage / len(stat), 1)
                        except:
                            avgUsage = 0

                        maxUsage = max(stat)
                        maxIdx = stat.index(maxUsage)

                        labelList.append(
                            "%s[ %s ] - %s%%" % (prefix, gpu, avgUsage)
                        )

                        for idx in [
                            idx
                            for idx, usage in enumerate(stat)
                            if usage == maxUsage
                        ]:
                            if idx != 0 and stat[idx] == stat[idx - 1]:
                                continue
                            text(
                                timeline[idx],
                                stat[maxIdx],
                                "%s Max_%d%% | Avg_%d%% | Total_%s%%"
                                % (
                                    prefix,
                                    maxUsage,
                                    avgUsage,
                                    conv(totalUsage),
                                ),
                                fontsize=self.lfsize + 1,
                                color="olive",
                                fontweight="bold",
                                bbox=dict(
                                    boxstyle="round",
                                    facecolor="wheat",
                                    alpha=0.3,
                                ),
                                ha=_getTextAlign(idx, timeline),
                            )
                            break

                    # ------------------ Total CPU usage ------------------#
                    if (
                        not "NOLOADPLOT" in SysMgr.environList
                        and sum(blkWait) > 0
                    ):
                        for idx, item in enumerate(blkWait):
                            blkWait[idx] += cpuUsage[idx]

                            # update the maximum ytick #
                            if ymax < blkWait[idx]:
                                ymax = blkWait[idx]

                        # set color #
                        if prefix:
                            icolor = None
                        else:
                            icolor = "pink"

                        # draw total CPU + IOWAIT graph #
                        plot(
                            timeline,
                            blkWait,
                            "-",
                            c=icolor,
                            linestyle="--",
                            linewidth=1,
                            marker="d",
                            markersize=1,
                            path_effects=_getPathEffect(),
                            solid_capstyle="round",
                        )

                        totalUsage = sum(blkWait)

                        try:
                            avgUsage = round(totalUsage / len(blkWait), 1)
                        except:
                            avgUsage = 0

                        labelList.append(
                            "%s[ CPU+IO Average ] - %.1f%%"
                            % (prefix, avgUsage)
                        )

                        maxUsage = max(blkWait)
                        maxIdx = blkWait.index(maxUsage)

                        for idx in [
                            idx
                            for idx, usage in enumerate(blkWait)
                            if usage == maxUsage
                        ]:
                            if idx != 0 and blkWait[idx] == blkWait[idx - 1]:
                                continue
                            text(
                                timeline[idx],
                                blkWait[maxIdx],
                                "%s Max_%d%% | Avg_%.1f%% | Total_%s%%"
                                % (
                                    prefix,
                                    maxUsage,
                                    avgUsage,
                                    conv(totalUsage),
                                ),
                                fontsize=self.lfsize + 1,
                                color="pink",
                                fontweight="bold",
                                bbox=dict(
                                    boxstyle="round",
                                    facecolor="wheat",
                                    alpha=0.3,
                                ),
                                ha=_getTextAlign(idx, timeline),
                            )
                            break

                    # set color #
                    if prefix:
                        ccolor = None
                    else:
                        ccolor = "red"

                    # draw total CPU graph #
                    plot(
                        timeline,
                        cpuUsage,
                        "-",
                        c=ccolor,
                        linestyle="--",
                        linewidth=1,
                        marker="d",
                        markersize=1,
                        path_effects=_getPathEffect(),
                        solid_capstyle="round",
                    )

                    totalUsage = sum(cpuUsage)

                    try:
                        avgUsage = round(totalUsage / len(cpuUsage), 1)
                    except:
                        avgUsage = 0

                    maxUsage = max(cpuUsage)
                    maxIdx = cpuUsage.index(maxUsage)

                    labelList.append(
                        "%s[ CPU Average ] - %s%%" % (prefix, avgUsage)
                    )

                    # update the maximum ytick #
                    if ymax < maxUsage:
                        ymax = maxUsage

                    for idx in [
                        idx
                        for idx, usage in enumerate(cpuUsage)
                        if usage == maxUsage
                    ]:
                        if idx != 0 and cpuUsage[idx] == cpuUsage[idx - 1]:
                            continue
                        text(
                            timeline[idx],
                            cpuUsage[maxIdx],
                            "%sMax_%d%% | Avg_%.1f%% | Total_%s%%"
                            % (prefix, maxUsage, avgUsage, conv(totalUsage)),
                            fontsize=self.lfsize + 1,
                            color="red",
                            fontweight="bold",
                            bbox=dict(
                                boxstyle="round", facecolor="wheat", alpha=0.3
                            ),
                            ha=_getTextAlign(idx, timeline),
                        )
                        break

                # ------------------- Process CPU usage -------------------#
                # total Process CPU usage filtered #
                if (
                    not delay
                    and SysMgr.filterGroup
                    and "[ TOTAL ]" in cpuProcUsage
                    and cpuProcUsage["[ TOTAL ]"]["count"] > 1
                    and not "NOTOTAL" in SysMgr.environList
                ):
                    totalUsage = cpuProcUsage["[ TOTAL ]"]["usage"].split()
                    totalUsage = list(map(long, totalUsage))[:lent]

                    # draw total graph #
                    plot(
                        timeline,
                        totalUsage,
                        "-",
                        c="green",
                        linestyle="-.",
                        linewidth=1,
                        marker="d",
                        markersize=1,
                        path_effects=_getPathEffect(),
                        solid_capstyle="round",
                    )

                    totalSumUsage = sum(totalUsage)

                    try:
                        avgUsage = round(totalSumUsage / len(totalUsage), 1)
                    except:
                        avgUsage = 0

                    maxUsage = max(totalUsage)
                    maxIdx = totalUsage.index(maxUsage)

                    labelList.append(
                        "%s[ TOTAL ] - %.1f%%" % (prefix, avgUsage)
                    )

                    # update the maximum ytick #
                    if ymax < maxUsage:
                        ymax = maxUsage

                    for idx in [
                        idx
                        for idx, usage in enumerate(totalUsage)
                        if usage == maxUsage
                    ]:
                        if idx != 0 and totalUsage[idx] == totalUsage[idx - 1]:
                            continue

                        if "NOLABEL" in SysMgr.environList:
                            break

                        text(
                            timeline[idx],
                            totalUsage[maxIdx],
                            "%s Max_%d%%|Avg_%.1f%%|Total_%s%%"
                            % (
                                prefix,
                                maxUsage,
                                avgUsage,
                                conv(totalSumUsage),
                            ),
                            fontsize=self.lfsize + 1,
                            color="green",
                            fontweight="bold",
                            bbox=dict(
                                boxstyle="round", facecolor="wheat", alpha=0.3
                            ),
                            ha=_getTextAlign(idx, timeline),
                        )
                        break

                cpuProcUsage.pop("[ TOTAL ]", None)

                # define top variable #
                tcnt = 0

                # check delay option #
                if delay:
                    targetList = cpuProcDelay
                else:
                    targetList = cpuProcUsage

                # get max cpu condition #
                maxCpuCond = UtilMgr.getEnvironNum(
                    "MAXCPUCOND", False, 0, False, True
                )

                # get avg cpu condition #
                avgCpuCond = UtilMgr.getEnvironNum(
                    "AVGCPUCOND", False, 0, False, True
                )

                # get min cpu condition #
                if "MINCPUCOND" in SysMgr.environList:
                    minCpuCond = UtilMgr.getEnvironNum(
                        "MINCPUCOND", False, 0, False, True
                    )
                else:
                    minCpuCond = 0

                # Process CPU usage #
                for idx, item in sorted(
                    targetList.items(),
                    key=lambda e: e[1]["average"],
                    reverse=True,
                ):
                    # check option #
                    if not SysMgr.cpuEnable:
                        break

                    # check top number #
                    if SysMgr.nrTop:
                        if tcnt >= SysMgr.nrTop:
                            break
                        else:
                            tcnt += 1
                    elif (
                        not SysMgr.showAll
                        and not SysMgr.filterGroup
                        and item["maximum"] == 0
                    ):
                        continue

                    # check max cpu condition #
                    if item["maximum"] < maxCpuCond:
                        continue

                    # check min cpu condition #
                    if item["minimum"] < minCpuCond:
                        continue

                    usage = item["usage"].split()
                    usage = list(map(long, usage))[:lent]
                    cpuUsage = list(usage)

                    totalUsage = sum(cpuUsage)

                    try:
                        avgUsage = round(totalUsage / len(cpuUsage), 1)
                    except:
                        avgUsage = 0

                    # check avg cpu condition #
                    if avgUsage < avgCpuCond:
                        continue

                    if not SysMgr.blockEnable:
                        # merge CPU usage and wait time for processes #
                        try:
                            blkUsage = blkProcUsage[idx]["usage"].split()
                            blkUsage = list(map(long, blkUsage))
                            for interval, value in enumerate(blkUsage):
                                usage[interval] += value
                        except SystemExit:
                            sys.exit(0)
                        except:
                            pass

                    # increase effectProcList count #
                    for seq, cnt in enumerate(usage):
                        if cnt > 0:
                            effectProcList[seq] += 1

                    # update the maximum ytick #
                    maxusage = max(usage)
                    if ymax < maxusage:
                        ymax = maxusage

                    # get plot attr #
                    lw, pe = _getPlotAttr(idx)

                    # draw plot and get color #
                    color = plot(
                        timeline, usage, "-", linewidth=lw, path_effects=pe
                    )[0].get_color()

                    margin = self.getMargin()

                    maxIdx = usage.index(maxusage)
                    maxCpuPer = str(cpuUsage[maxIdx])
                    if idx in blkProcUsage and not SysMgr.blockEnable:
                        maxBlkPer = blkUsage[maxIdx]
                    else:
                        maxBlkPer = 0

                    # get blocking time #
                    try:
                        if maxBlkPer > 0:
                            maxBlkPerStr = "+%s%%" % maxBlkPer
                        else:
                            maxBlkPerStr = ""
                    except:
                        maxBlkPerStr = ""

                    # check lifecycle event #
                    life = ""
                    if (
                        "start" in item
                        and "finish" in item
                        and item["start"] < len(timeline)
                        and item["finish"] < len(timeline)
                    ):
                        life += "|Run_%s~%s" % (
                            timeline[item["start"]],
                            timeline[item["finish"]],
                        )
                    elif "start" in item and item["start"] < len(timeline):
                        life += "|Run_%s~" % timeline[item["start"]]
                    elif "finish" in item and item["finish"] < len(timeline):
                        life += "|Run_~%s" % timeline[item["finish"]]

                    # make text #
                    maxPer = "[Max_%s%%%s|Avg_%s%%|Total_%s%%%s]" % (
                        maxCpuPer,
                        maxBlkPerStr,
                        avgUsage,
                        conv(totalUsage),
                        life,
                    )

                    # mark text at peek #
                    ilabel = "%s%s%s" % (prefix, idx, maxPer)

                    if not "NOLABEL" in SysMgr.environList:
                        text(
                            timeline[maxIdx],
                            usage[maxIdx] + margin,
                            ilabel,
                            fontsize=self.lfsize - 1,
                            color=color,
                            fontweight="normal",
                            rotation=35,
                            ha=_getTextAlign(maxIdx, timeline),
                        )

                    labelList.append("%s%s - %s%%" % (prefix, idx, avgUsage))

            """
            ylabel('CPU + I/O', fontsize=5)
            ax.yaxis.set_label_coords(-0.05,0.5)
            """

            # draw label #
            TaskAnalyzer.drawLabel(labelList, draw=True, anchor=(1.12, 1.05))

            grid(which="both", linestyle=":", linewidth=0.2)
            tick_params(axis="x", direction="in")
            tick_params(axis="y", direction="in")

            # update xticks #
            xticks(fontsize=self.xfsize)
            if len(timeline) > 1:
                xlim([timeline[0], timeline[-1]])

            # update yticks #
            TaskAnalyzer.drawYticks(ax, ymax)

            # add % unit to each value #
            try:
                ytickLabel = ax.get_yticks().tolist()
                ytickLabel = list(map(long, ytickLabel))

                # convert label units #
                ytickLabel = ["%s%%" % val for val in ytickLabel]

                ax.set_yticklabels(ytickLabel)
            except SystemExit:
                sys.exit(0)
            except:
                pass

            # set name #
            if delay:
                name = "Delay"
            else:
                name = "CPU"

            # draw name #
            TaskAnalyzer.drawName(ax, name)

            # draw base #
            self.figure = TaskAnalyzer.drawFigure()

            self.drawBottom(xtype, ax, timeline, nrTask, effectProcList)

        def _drawIo(graphStats, xtype, pos, size):
            def __drawSystemIo(statList, color, ymax, name):
                if not statList:
                    return

                usage = list(map(long, statList))[:lent]

                # update the maximum ytick #
                maxUsage = max(usage)
                if ymax < maxUsage:
                    ymax = maxUsage

                minIdx = usage.index(min(usage))
                maxIdx = usage.index(max(usage))

                minval = "%s%s%s" % (
                    prefix,
                    name,
                    convSize(usage[minIdx] << 10),
                )
                maxsize = convSize(usage[maxIdx] << 10)
                totalsize = convSize(long(sum(usage)) << 10)
                maxval = "%s%s%s" % (prefix, name, maxsize)
                lastval = "%s%s%s" % (prefix, name, convSize(usage[-1] << 10))

                # set color #
                if prefix:
                    rcolor = None
                else:
                    rcolor = color

                if usage[minIdx] == usage[maxIdx] == 0:
                    line = plot(
                        timeline,
                        statList,
                        "-",
                        c=rcolor,
                        linewidth=0.1,
                        alpha=0.1,
                    )
                else:
                    pe = _getPathEffect(lw=1)
                    line = plot(
                        timeline,
                        statList,
                        linestyle="--",
                        c=rcolor,
                        linewidth=0.7,
                        marker="d",
                        markersize=1,
                        path_effects=pe,
                    )

                color = line[0].get_color()

                if usage[minIdx] > 0:
                    text(
                        timeline[minIdx],
                        usage[minIdx],
                        minval,
                        fontsize=self.lfsize,
                        color=color,
                        fontweight="bold",
                        ha=_getTextAlign(minIdx, timeline),
                        rotation=35,
                    )
                if usage[minIdx] != usage[maxIdx] and usage[maxIdx] > 0:
                    text(
                        timeline[maxIdx],
                        usage[maxIdx],
                        maxval,
                        fontsize=self.lfsize,
                        color=color,
                        fontweight="bold",
                        ha=_getTextAlign(maxIdx, timeline),
                        rotation=35,
                    )
                if usage[-1] > 0:
                    text(
                        timeline[-1],
                        usage[-1],
                        lastval,
                        rotation=35,
                        fontsize=self.lfsize,
                        color=color,
                        fontweight="bold",
                        ha="right",
                    )

                return totalsize, ymax

            # define common label list #
            ymax = 0
            labelList = []

            # set convert size #
            convSize = UtilMgr.convSize2Unit

            # draw title #
            ax = subplot2grid((6, 1), (pos, 0), rowspan=size, colspan=1)
            ax.xaxis.set_major_locator(MaxNLocator(integer=True))
            suptitle(graphStats["graphTitle"], fontsize=8)

            # get minimum timeline #
            timeline = None
            for key, val in graphStats.items():
                if not key.endswith("timeline"):
                    continue
                elif not timeline:
                    timeline = val
                elif len(timeline) > len(val):
                    timeline = val
            lent = len(timeline)

            # set visible total usage flag #
            if SysMgr.showAll or not SysMgr.filterGroup:
                isVisibleTotal = True
            else:
                isVisibleTotal = False

            # set label variable #
            if "NOLABEL" in SysMgr.environList:
                hasLabel = False
            else:
                hasLabel = True

            # add boundary line #
            self.drawBoundary("io", labelList)

            # draw user event #
            self.drawUserEvent("io")

            # start loop #
            for key, val in graphStats.items():
                if not key.endswith("timeline"):
                    continue

                res = key.split(":")
                if len(res) > 1:
                    fname = "%s:" % res[0]
                    prefix = "[%s] " % res[0]
                else:
                    fname = ""
                    prefix = ""

                blkRead = graphStats["%sblkRead" % fname][:lent]
                blkWrite = graphStats["%sblkWrite" % fname][:lent]
                blkProcUsage = graphStats["%sblkProcUsage" % fname]
                netRead = graphStats["%snetRead" % fname][:lent]
                netWrite = graphStats["%snetWrite" % fname][:lent]
                reclaimBg = graphStats["%sreclaimBg" % fname][:lent]
                reclaimDr = graphStats["%sreclaimDr" % fname][:lent]
                storageUsage = graphStats["%sstorageUsage" % fname]
                networkUsage = graphStats["%snetworkUsage" % fname]

                if isVisibleTotal:
                    # System Block Read #
                    color = None if fname else "purple"
                    totalsize, ymax = __drawSystemIo(
                        blkRead, color, ymax, "[BR]"
                    )
                    labelList.append("%sBlock Read - %s" % (prefix, totalsize))

                    # System Block Write #
                    color = None if fname else "darkgreen"
                    totalsize, ymax = __drawSystemIo(
                        blkWrite, color, ymax, "[BW]"
                    )
                    labelList.append(
                        "%sBlock Write - %s" % (prefix, totalsize)
                    )

                    # System Background Reclaim #
                    color = None if fname else "pink"
                    totalsize, ymax = __drawSystemIo(
                        reclaimBg, color, ymax, "[RB]"
                    )
                    labelList.append("%sReclaim BG - %s" % (prefix, totalsize))

                    # System Direct Reclaim #
                    color = None if fname else "red"
                    totalsize, ymax = __drawSystemIo(
                        reclaimDr, color, ymax, "[RF]"
                    )
                    labelList.append("%sReclaim FG - %s" % (prefix, totalsize))

                    # System Network Inbound #
                    color = None if fname else "orange"
                    totalsize, ymax = __drawSystemIo(
                        netRead, color, ymax, "[NI]"
                    )
                    labelList.append("%sNetwork In - %s" % (prefix, totalsize))

                    # System Network Outbound #
                    color = None if fname else "cyan"
                    totalsize, ymax = __drawSystemIo(
                        netWrite, color, ymax, "[NO]"
                    )
                    labelList.append(
                        "%sNetwork Out - %s" % (prefix, totalsize)
                    )

                # check device enable flag #
                diskEnable = False
                networkEnable = False
                enableList = SysMgr.getOption("e")
                if enableList:
                    if "d" in enableList:
                        diskEnable = True
                    if "n" in enableList:
                        networkEnable = True

                # System Network Usage #
                for idx, item in networkUsage.items():
                    if not isVisibleTotal or not networkEnable:
                        break

                    rdUsage = item["recv"][:lent]
                    wrUsage = item["tran"][:lent]

                    # no network usage #
                    if not rdUsage and not wrUsage:
                        continue

                    margin = self.getMargin()

                    # Network Transfer #
                    minIdx = wrUsage.index(min(wrUsage))
                    maxIdx = wrUsage.index(max(wrUsage))

                    # update the maximum ytick #
                    maxUsage = max(wrUsage)
                    if ymax < maxUsage:
                        ymax = maxUsage

                    maxsize = convSize(wrUsage[maxIdx] << 10)
                    totalsize = convSize(long(sum(wrUsage)) << 10)
                    ptype = "[NO]"
                    maxval = "%s%s%s" % (prefix, ptype, maxsize)
                    lastval = "%s%s%s" % (
                        prefix,
                        ptype,
                        convSize(wrUsage[-1] << 10),
                    )

                    if wrUsage[minIdx] == wrUsage[maxIdx] == 0:
                        pass
                    else:
                        color = plot(timeline, wrUsage, "-", linewidth=0.7)[
                            0
                        ].get_color()
                        if wrUsage[maxIdx] > 0:
                            text(
                                timeline[maxIdx],
                                wrUsage[maxIdx] + margin,
                                maxval,
                                rotation=35,
                                fontsize=self.lfsize,
                                color=color,
                                fontweight="bold",
                                ha=_getTextAlign(maxIdx, timeline),
                            )
                        if wrUsage[-1] > 0:
                            text(
                                timeline[-1],
                                wrUsage[-1] + margin,
                                lastval,
                                rotation=35,
                                fontsize=self.lfsize,
                                color=color,
                                fontweight="bold",
                                ha="right",
                            )

                        labelList.append(
                            "%s%s Transfer - %s" % (prefix, idx, totalsize)
                        )

                    # Network Receive #
                    minIdx = rdUsage.index(min(rdUsage))
                    maxIdx = rdUsage.index(max(rdUsage))

                    # update the maximum ytick #
                    maxUsage = max(rdUsage)
                    if ymax < maxUsage:
                        ymax = maxUsage

                    maxsize = convSize(rdUsage[maxIdx] << 10)
                    totalsize = convSize(long(sum(rdUsage)) << 10)
                    ptype = "[NI]"
                    maxval = "%s%s%s" % (prefix, ptype, maxsize)
                    lastval = "%s%s%s" % (
                        prefix,
                        ptype,
                        convSize(rdUsage[-1] << 10),
                    )

                    if rdUsage[minIdx] == rdUsage[maxIdx] == 0:
                        pass
                    else:
                        color = plot(timeline, rdUsage, "-", linewidth=0.7)[
                            0
                        ].get_color()

                        if rdUsage[maxIdx] > 0:
                            text(
                                timeline[maxIdx],
                                rdUsage[maxIdx] + margin,
                                maxval,
                                rotation=35,
                                fontsize=self.lfsize,
                                color=color,
                                fontweight="bold",
                                ha=_getTextAlign(maxIdx, timeline),
                            )
                        if rdUsage[-1] > 0:
                            text(
                                timeline[-1],
                                rdUsage[-1] + margin,
                                lastval,
                                rotation=35,
                                fontsize=self.lfsize,
                                color=color,
                                fontweight="bold",
                                ha="right",
                            )

                        labelList.append(
                            "%s%s Receive - %s" % (prefix, idx, totalsize)
                        )

                # System Storage Usage #
                for idx, item in storageUsage.items():
                    if not isVisibleTotal or not diskEnable:
                        break

                    busyUsage = item["busy"][:lent]
                    rdUsage = item["read"][:lent]
                    wrUsage = item["write"][:lent]
                    freeUsage = item["free"][:lent]

                    # no storage usage #
                    if len(rdUsage) == len(wrUsage) == len(freeUsage) == 0:
                        continue

                    margin = self.getMargin()

                    # Storage Write #
                    minIdx = wrUsage.index(min(wrUsage))
                    maxIdx = wrUsage.index(max(wrUsage))

                    # update the maximum ytick #
                    maxUsage = max(wrUsage)
                    if ymax < maxUsage:
                        ymax = maxUsage

                    maxsize = convSize(wrUsage[maxIdx] << 10)
                    totalsize = convSize(long(sum(wrUsage)) << 10)
                    busyval = busyUsage[maxIdx]
                    ptype = "[BW]"
                    maxval = "%s%s%s[%s%%]" % (prefix, ptype, maxsize, busyval)
                    lastval = "%s%s%s" % (
                        prefix,
                        ptype,
                        convSize(wrUsage[-1] << 10),
                    )

                    if wrUsage[minIdx] == wrUsage[maxIdx] == 0:
                        pass
                    else:
                        color = plot(timeline, wrUsage, "-", linewidth=0.7)[
                            0
                        ].get_color()

                        if wrUsage[maxIdx] > 0:
                            text(
                                timeline[maxIdx],
                                wrUsage[maxIdx] + margin,
                                maxval,
                                rotation=35,
                                fontsize=self.lfsize,
                                color=color,
                                fontweight="bold",
                                ha=_getTextAlign(maxIdx, timeline),
                            )

                        if wrUsage[-1] > 0:
                            text(
                                timeline[-1],
                                wrUsage[-1] + margin,
                                lastval,
                                fontsize=self.lfsize,
                                color=color,
                                fontweight="bold",
                                ha="right",
                                rotation=35,
                            )

                        labelList.append(
                            "%s%s Write - %s" % (prefix, idx, totalsize)
                        )

                    # Storage Read #
                    minIdx = rdUsage.index(min(rdUsage))
                    maxIdx = rdUsage.index(max(rdUsage))

                    # update the maximum ytick #
                    maxUsage = max(rdUsage)
                    if ymax < maxUsage:
                        ymax = maxUsage

                    maxsize = convSize(rdUsage[maxIdx] << 10)
                    totalsize = convSize(long(sum(rdUsage)) << 10)
                    busyval = busyUsage[maxIdx]
                    ptype = "[BR]"
                    maxval = "%s%s%s[%s%%]" % (prefix, ptype, maxsize, busyval)
                    lastval = "%s%s%s" % (
                        prefix,
                        ptype,
                        convSize(rdUsage[-1] << 10),
                    )

                    if rdUsage[minIdx] == rdUsage[maxIdx] == 0:
                        pass
                    else:
                        color = plot(timeline, rdUsage, "-", linewidth=0.7)[
                            0
                        ].get_color()

                        if rdUsage[maxIdx] > 0:
                            text(
                                timeline[maxIdx],
                                rdUsage[maxIdx] + margin,
                                maxval,
                                rotation=35,
                                fontsize=self.lfsize,
                                color=color,
                                fontweight="bold",
                                ha=_getTextAlign(maxIdx, timeline),
                            )
                        if rdUsage[-1] > 0:
                            text(
                                timeline[-1],
                                rdUsage[-1] + margin,
                                lastval,
                                fontsize=self.lfsize,
                                color=color,
                                fontweight="bold",
                                ha="right",
                                rotation=35,
                            )

                        labelList.append(
                            "%s%s Read - %s" % (prefix, idx, totalsize)
                        )

                # Process I/O usage #
                for idx, item in blkProcUsage.items():
                    if not SysMgr.showAll:
                        break

                    rdUsage = []
                    wrUsage = []
                    usage = item["usage"].split()[:lent]

                    # divide I/O graph #
                    for item in usage:
                        io = item.split("/")
                        if len(io) == 2:
                            rdUsage.append(long(io[0]) << 10)
                            wrUsage.append(long(io[1]) << 10)
                        else:
                            rdUsage.append(0)
                            wrUsage.append(0)

                    # no I/O usage #
                    if len(rdUsage) == len(wrUsage) == 0:
                        continue

                    margin = self.getMargin()

                    # Block Write of process #
                    minIdx = wrUsage.index(min(wrUsage))
                    maxIdx = wrUsage.index(max(wrUsage))

                    # update the maximum ytick #
                    maxUsage = max(wrUsage)
                    if ymax < maxUsage:
                        ymax = maxUsage

                    maxsize = convSize(wrUsage[maxIdx] << 10)
                    totalsize = convSize(long(sum(wrUsage)) << 10)
                    ptype = "[BW]"
                    maxval = "%s%s%s[%s]" % (prefix, ptype, idx, maxsize)
                    lastval = "%s%s%s[%s]" % (
                        prefix,
                        ptype,
                        convSize(wrUsage[-1] << 10),
                        idx,
                    )

                    # get plot attr #
                    lw, pe = _getPlotAttr(idx)

                    if wrUsage[minIdx] == wrUsage[maxIdx] == 0:
                        pass
                    else:
                        color = plot(
                            timeline,
                            wrUsage,
                            "-",
                            linewidth=lw,
                            path_effects=pe,
                        )[0].get_color()

                        if wrUsage[maxIdx] > 0 and hasLabel:
                            text(
                                timeline[maxIdx],
                                wrUsage[maxIdx] + margin,
                                maxval,
                                fontsize=self.lfsize,
                                color=color,
                                fontweight="normal",
                                rotation=35,
                                ha=_getTextAlign(maxIdx, timeline),
                            )
                        if wrUsage[-1] > 0 and hasLabel:
                            text(
                                timeline[-1],
                                wrUsage[-1] + margin,
                                lastval,
                                fontsize=self.lfsize,
                                color=color,
                                fontweight="normal",
                                rotation=35,
                                ha="right",
                            )

                        labelList.append(
                            "%s%s[BWR] - %s" % (prefix, idx, totalsize)
                        )

                    # Block Read of process #
                    minIdx = rdUsage.index(min(rdUsage))
                    maxIdx = rdUsage.index(max(rdUsage))

                    # update the maximum ytick #
                    maxUsage = max(rdUsage)
                    if ymax < maxUsage:
                        ymax = maxUsage

                    maxsize = convSize(rdUsage[maxIdx] << 10)
                    totalsize = convSize(long(sum(rdUsage)) << 10)
                    ptype = "[BR]"
                    maxval = "%s%s%s[%s]" % (prefix, ptype, idx, maxsize)
                    lastval = "%s%s%s[%s]" % (
                        prefix,
                        ptype,
                        convSize(rdUsage[-1] << 10),
                        idx,
                    )

                    if rdUsage[minIdx] == rdUsage[maxIdx] == 0:
                        pass
                    else:
                        color = plot(
                            timeline,
                            rdUsage,
                            "-",
                            linewidth=lw,
                            path_effects=pe,
                        )[0].get_color()

                        if rdUsage[maxIdx] > 0 and hasLabel:
                            text(
                                timeline[maxIdx],
                                rdUsage[maxIdx] + margin,
                                maxval,
                                fontsize=self.lfsize,
                                color=color,
                                fontweight="normal",
                                rotation=35,
                                ha=_getTextAlign(maxIdx, timeline),
                            )
                        if rdUsage[-1] > 0 and hasLabel:
                            text(
                                timeline[-1],
                                rdUsage[-1] + margin,
                                lastval,
                                fontsize=self.lfsize,
                                color=color,
                                fontweight="normal",
                                rotation=35,
                                ha="right",
                            )

                        labelList.append(
                            "%s%s[BRD] - %s" % (prefix, idx, totalsize)
                        )

            """
            ylabel('I/O', fontsize=5)
            ax.yaxis.set_label_coords(-0.05,0.5)
            """

            # draw label #
            TaskAnalyzer.drawLabel(labelList, draw=False, anchor=(1.12, 1.05))

            grid(which="both", linestyle=":", linewidth=0.2)
            tick_params(axis="x", direction="in")
            tick_params(axis="y", direction="in")

            # update yticks #
            TaskAnalyzer.drawYticks(ax, ymax)

            # update xticks #
            xticks(fontsize=self.xfsize)
            if len(timeline) > 1:
                xlim([timeline[0], timeline[-1]])

            try:
                ticklabel_format(useOffset=False)
            except:
                pass

            # draw name #
            TaskAnalyzer.drawName(ax, "I/O")

            # draw base #
            self.figure = TaskAnalyzer.drawFigure()

            # convert tick type to integer #
            try:
                # ax.get_xaxis().set_visible(False)
                ytickLabel = ax.get_yticks().tolist()
                ytickLabel = list(map(long, ytickLabel))

                # convert label units #
                ytickLabel = [convSize(val << 10) for val in ytickLabel]

                # remove redundant ticks #
                lastTick = ""
                tempLabelList = list(ytickLabel)
                for idx, ytick in enumerate(tempLabelList):
                    if lastTick == ytick:
                        ytickLabel[idx] = ""
                    else:
                        lastTick = ytick
                ax.set_yticklabels(ytickLabel)

                # hide yticks #
                if ytickLabel[-1] == "0":
                    ax.set_ylim(top=1)
                    ax.get_yaxis().set_visible(False)
            except SystemExit:
                sys.exit(0)
            except:
                pass

            self.drawBottom(xtype, ax, timeline, nrTask, effectProcList)

        def _drawMem(graphStats, xtype, pos, size):
            def __drawSystemMem(statList, color, ymax, name):
                usage = list(map(long, statList))
                minIdx = usage.index(min(usage))
                maxIdx = usage.index(max(usage))

                if usage[minIdx] == usage[maxIdx] == 0:
                    return None, ymax

                # update the maximum ytick #
                maxusage = max(usage)
                if ymax < maxusage:
                    ymax = maxusage

                minval = "%s%s%s" % (
                    prefix,
                    name,
                    convSize(usage[minIdx] << 20),
                )
                maxsize = convSize(usage[maxIdx] << 20)
                maxval = "%s%s%s" % (prefix, name, maxsize)
                lastsize = convSize(usage[-1] << 20)
                lastval = "%s%s%s" % (prefix, name, lastsize)

                # set color #
                if prefix:
                    fcolor = None
                else:
                    fcolor = color

                pe = _getPathEffect()

                line = plot(
                    timeline,
                    usage,
                    "-",
                    c=fcolor,
                    linewidth=0.7,
                    path_effects=pe,
                    solid_capstyle="round",
                )

                color = line[0].get_color()

                if usage[minIdx] > 0:
                    text(
                        timeline[minIdx],
                        usage[minIdx],
                        minval,
                        fontsize=self.lfsize,
                        color=color,
                        fontweight="bold",
                        ha=_getTextAlign(minIdx, timeline),
                    )
                if usage[minIdx] != usage[maxIdx] and usage[maxIdx] > 0:
                    text(
                        timeline[maxIdx],
                        usage[maxIdx],
                        maxval,
                        fontsize=self.lfsize,
                        color=color,
                        fontweight="bold",
                        ha=_getTextAlign(maxIdx, timeline),
                    )
                if usage[-1] > 0:
                    text(
                        timeline[-1],
                        usage[-1],
                        lastval,
                        fontsize=self.lfsize,
                        color=color,
                        fontweight="bold",
                        ha="right",
                    )

                return lastsize, ymax

            # define common label list #
            ymax = 0
            labelList = []

            # set convert size #
            convSize = UtilMgr.convSize2Unit

            # set label variable #
            if "NOLABEL" in SysMgr.environList:
                hasLabel = False
            else:
                hasLabel = True

            # draw title #
            ax = subplot2grid((6, 1), (pos, 0), rowspan=size, colspan=1)
            ax.xaxis.set_major_locator(MaxNLocator(integer=True))
            suptitle(graphStats["graphTitle"], fontsize=8)

            # get minimum timeline #
            timeline = None
            for key, val in graphStats.items():
                if not key.endswith("timeline"):
                    continue
                elif not timeline:
                    timeline = val
                elif len(timeline) > len(val):
                    timeline = val
            lent = len(timeline)

            # add boundary line #
            self.drawBoundary("mem", labelList)

            # draw user event #
            self.drawUserEvent("mem")

            # define top variable #
            tcnt = 0

            # start loop #
            for key, val in graphStats.items():
                if not key.endswith("timeline"):
                    continue

                # get prefix #
                res = key.split(":")
                if len(res) > 1:
                    fname = "%s:" % res[0]
                    prefix = "[%s] " % res[0]
                else:
                    fname = ""
                    prefix = ""

                totalRam = graphStats["%stotalRam" % fname]
                totalSwap = graphStats["%stotalSwap" % fname]

                if "NOMEMFREEPLOT" in SysMgr.environList:
                    memFree = [0]
                else:
                    memFree = graphStats["%smemFree" % fname][:lent]

                if "NOMEMANONPLOT" in SysMgr.environList:
                    memAnon = [0]
                else:
                    memAnon = graphStats["%smemAnon" % fname][:lent]

                if "NOMEMCACHEPLOT" in SysMgr.environList:
                    memCache = [0]
                else:
                    memCache = graphStats["%smemCache" % fname][:lent]

                if "NOMEMPROCPLOT" in SysMgr.environList:
                    memProc = {}
                else:
                    memProc = graphStats["%smemProcUsage" % fname]

                if "NOMEMSWAPPLOT" in SysMgr.environList:
                    swapUsage = [0]
                else:
                    swapUsage = graphStats["%sswapUsage" % fname][:lent]

                # get margin #
                margin = self.getMargin()

                def __drawMemPlots(ymax):
                    # System Free Memory #
                    lastsize, ymax = __drawSystemMem(
                        memFree, "blue", ymax, "[RF]"
                    )
                    if lastsize is not None:
                        if totalRam:
                            label = (
                                "%s[ RAM Total ] - %s\nRAM Available - %s"
                                % (prefix, convSize(totalRam), lastsize)
                            )
                            labelList.append(label)
                        else:
                            labelList.append(
                                "%sRAM Available - %s" % (prefix, lastsize)
                            )

                    # System Anon Memory #
                    lastsize, ymax = __drawSystemMem(
                        memAnon, "skyblue", ymax, "[RA]"
                    )
                    if lastsize is not None:
                        labelList.append(
                            "%sRAM User - %s" % (prefix, lastsize)
                        )

                    # System Cache Memory #
                    lastsize, ymax = __drawSystemMem(
                        memCache, "darkgray", ymax, "[RC]"
                    )
                    if lastsize is not None:
                        labelList.append(
                            "%sRAM Cache - %s" % (prefix, lastsize)
                        )

                    # System Swap Memory #
                    lastsize, ymax = __drawSystemMem(
                        swapUsage, "orange", ymax, "[RS]"
                    )
                    if lastsize is not None:
                        if totalSwap:
                            label = (
                                "%s[ Swap Total ] - %s\nSwap Usage - %s"
                                % (prefix, convSize(totalSwap), lastsize)
                            )
                            labelList.append(label)
                        else:
                            labelList.append(
                                "%sSwap Usage - %s" % (prefix, lastsize)
                            )

                    return ymax

                # draw system memory #
                if "MEMSYSPLOT" in SysMgr.environList:
                    ymax = __drawMemPlots(ymax)

                # Process VSS #
                if SysMgr.vssEnable:
                    # get max vss condition #
                    maxVssCond = UtilMgr.getEnvironNum(
                        "MAXVSSCOND", False, 0, False, True
                    )

                    for key, item in sorted(
                        memProc.items(),
                        key=lambda e: 0
                        if not "maxVss" in e[1]
                        else e[1]["maxVss"],
                        reverse=True,
                    ):

                        # check top number #
                        if SysMgr.nrTop:
                            if tcnt >= SysMgr.nrTop:
                                break
                            else:
                                tcnt += 1

                        usage = list(map(long, item["vssUsage"].split()))[
                            :lent
                        ]

                        # update the maximum ytick #
                        maxusage = max(usage)
                        if ymax < maxusage:
                            ymax = maxusage

                        # check max vss conditino #
                        if maxusage < maxVssCond:
                            continue

                        try:
                            minIdx = usage.index(min(usage))
                        except:
                            minIdx = 0
                        try:
                            maxIdx = usage.index(item["maxVss"])
                        except:
                            maxIdx = 0

                        key = prefix + key
                        minval = "%s [%s]" % (
                            key,
                            convSize(usage[minIdx] << 20),
                        )
                        maxsize = convSize(usage[maxIdx] << 20)
                        maxval = "%s [%s]" % (key, maxsize)
                        lastval = "%s [%s]" % (key, convSize(usage[-1] << 20))

                        if usage[minIdx] == usage[maxIdx] == 0:
                            continue

                        # ignore 0 #
                        usage = list(
                            map(lambda x: x if x != 0 else None, usage)
                        )

                        # get plot attr #
                        lw, pe = _getPlotAttr(key)

                        # get color #
                        color = plot(
                            timeline, usage, "-", linewidth=lw, path_effects=pe
                        )[0].get_color()

                        if usage[minIdx] and hasLabel:
                            text(
                                timeline[minIdx],
                                usage[minIdx] + margin,
                                minval,
                                color=color,
                                fontsize=self.lfsize,
                                rotation=35,
                                ha=_getTextAlign(minIdx, timeline),
                            )
                        if (
                            usage[minIdx] != usage[maxIdx]
                            and usage[maxIdx]
                            and hasLabel
                        ):
                            text(
                                timeline[maxIdx],
                                usage[maxIdx] + margin,
                                maxval,
                                color=color,
                                fontsize=self.lfsize,
                                rotation=35,
                                ha=_getTextAlign(maxIdx, timeline),
                            )
                        if usage[-1] and hasLabel:
                            text(
                                timeline[-1],
                                usage[-1] + margin,
                                lastval,
                                color=color,
                                fontsize=self.lfsize,
                                rotation=35,
                                ha="right",
                            )

                        labelList.append("%s [VSS] - %s" % (key, maxsize))

                # Process Leak #
                elif SysMgr.leakEnable:
                    # get VSS diffs #
                    for key, item in sorted(
                        memProc.items(),
                        key=lambda e: 0
                        if not "maxVss" in e[1]
                        else e[1]["maxVss"],
                        reverse=True,
                    ):
                        usage = list(map(long, item["vssUsage"].split()))[
                            :lent
                        ]

                        # get maximum value #
                        try:
                            maxVss = max(usage)
                        except:
                            maxVss = 0

                        if maxVss == 0:
                            item["vssDiff"] = 0
                            continue

                        # get index for maximum/minimum values greater than 0 #
                        try:
                            first = next(val for val in usage if val > 0)
                            last = next(
                                val for val in reversed(usage) if val > 0
                            )

                            if long(first) >= long(last):
                                item["vssDiff"] = 0
                                continue
                        except:
                            pass

                        # get minimum value #
                        try:
                            minVss = min(x for x in usage if x != 0)
                        except:
                            minVss = 0

                        diff = maxVss - minVss
                        item["vssDiff"] = diff

                    # draw leakage plots #
                    for key, item in sorted(
                        memProc.items(),
                        key=lambda e: e[1]["vssDiff"],
                        reverse=True,
                    ):

                        # check top number #
                        if SysMgr.nrTop:
                            if tcnt >= SysMgr.nrTop:
                                break
                            else:
                                tcnt += 1

                        if item["vssDiff"] == 0:
                            break

                        usage = list(map(long, item["vssUsage"].split()))[
                            :lent
                        ]

                        # update the maximum ytick #
                        maxusage = max(usage)
                        if ymax < maxusage:
                            ymax = maxusage

                        # get minimum value #
                        try:
                            minIdx = usage.index(min(usage))
                        except:
                            minIdx = 0

                        # get maximum value #
                        try:
                            maxIdx = usage.index(item["maxVss"])
                        except:
                            maxIdx = 0

                        key = prefix + key
                        minval = "%s [%s]" % (
                            key,
                            convSize(usage[minIdx] << 20),
                        )
                        diffsize = convSize(item["vssDiff"] << 20)
                        lastval = "%s [%s/+%s]" % (
                            key,
                            convSize(usage[maxIdx] << 20),
                            diffsize,
                        )

                        if usage[minIdx] == usage[maxIdx] == 0:
                            continue

                        # ignore 0 #
                        usage = list(
                            map(lambda x: x if x != 0 else None, usage)
                        )

                        # get plot attr #
                        lw, pe = _getPlotAttr(key)

                        # get color #
                        color = plot(
                            timeline, usage, "-", linewidth=lw, path_effects=pe
                        )[0].get_color()

                        if usage[minIdx] and hasLabel:
                            text(
                                timeline[minIdx],
                                usage[minIdx] - margin,
                                minval,
                                color=color,
                                fontsize=self.lfsize,
                                rotation=35,
                                ha=_getTextAlign(minIdx, timeline),
                            )
                        if (
                            usage[minIdx] != usage[maxIdx]
                            and usage[maxIdx]
                            and hasLabel
                        ):
                            text(
                                timeline[maxIdx],
                                usage[maxIdx] + margin,
                                lastval,
                                color=color,
                                fontsize=self.lfsize,
                                rotation=35,
                                ha=_getTextAlign(maxIdx, timeline),
                            )

                        labelList.append("%s [LEAK] - %s" % (key, diffsize))

                # Process RSS #
                elif SysMgr.rssEnable or SysMgr.pssEnable or SysMgr.ussEnable:
                    # get max rss condition #
                    maxRssCond = UtilMgr.getEnvironNum(
                        "MAXRSSCOND", False, 0, False, True
                    )

                    for key, item in sorted(
                        memProc.items(),
                        key=lambda e: 0
                        if not "maxRss" in e[1]
                        else e[1]["maxRss"],
                        reverse=True,
                    ):

                        # check top number #
                        if SysMgr.nrTop:
                            if tcnt >= SysMgr.nrTop:
                                break
                            else:
                                tcnt += 1

                        try:
                            rssList = item["rssUsage"].split()
                            usage = list(map(long, rssList))[:lent]
                        except SystemExit:
                            sys.exit(0)
                        except:
                            continue

                        # update the maximum ytick #
                        maxusage = max(usage)
                        if ymax < maxusage:
                            ymax = maxusage

                        # check max rss conditino #
                        if maxusage < maxRssCond:
                            continue

                        try:
                            minIdx = usage.index(min(usage))
                        except SystemExit:
                            sys.exit(0)
                        except:
                            minIdx = 0

                        try:
                            maxIdx = usage.index(item["maxRss"])
                        except SystemExit:
                            sys.exit(0)
                        except:
                            maxIdx = 0

                        key = prefix + key
                        minval = "%s [%s]" % (
                            key,
                            convSize(usage[minIdx] << 20),
                        )
                        maxsize = convSize(usage[maxIdx] << 20)
                        maxval = "%s [%s]" % (key, maxsize)
                        lastsize = convSize(usage[-1] << 20)
                        lastval = "%s [%s]" % (key, lastsize)

                        if usage[minIdx] == usage[maxIdx] == 0:
                            continue

                        # ignore 0 #
                        usage = list(
                            map(lambda x: x if x != 0 else None, usage)
                        )

                        # get plot attr #
                        lw, pe = _getPlotAttr(key)

                        # get color #
                        color = plot(
                            timeline, usage, "-", linewidth=lw, path_effects=pe
                        )[0].get_color()

                        if usage[minIdx] and hasLabel:
                            text(
                                timeline[minIdx],
                                usage[minIdx] + margin,
                                minval,
                                color=color,
                                fontsize=self.lfsize,
                                rotation=35,
                                ha=_getTextAlign(minIdx, timeline),
                            )
                        if (
                            usage[minIdx] != usage[maxIdx]
                            and usage[maxIdx]
                            and hasLabel
                        ):
                            text(
                                timeline[maxIdx],
                                usage[maxIdx] + margin,
                                maxval,
                                color=color,
                                fontsize=self.lfsize,
                                rotation=35,
                                ha=_getTextAlign(maxIdx, timeline),
                            )
                        if usage[-1] and hasLabel:
                            text(
                                timeline[-1],
                                usage[-1] + margin,
                                lastval,
                                color=color,
                                fontsize=self.lfsize,
                                rotation=35,
                                ha="right",
                            )

                        # set memory type #
                        if SysMgr.pssEnable:
                            mem = "PSS"
                        elif SysMgr.ussEnable:
                            mem = "USS"
                        else:
                            mem = "RSS"

                        labelList.append("%s [%s] - %s" % (key, mem, maxsize))

                # System #
                else:
                    if not "MEMSYSPLOT" in SysMgr.environList:
                        __drawMemPlots(ymax)

            """
            ylabel('MEMORY', fontsize=5)
            ax.yaxis.set_label_coords(-0.05,0.5)
            """

            # draw label #
            TaskAnalyzer.drawLabel(labelList, draw=True, anchor=(1.12, 0.75))

            grid(which="both", linestyle=":", linewidth=0.2)
            tick_params(axis="x", direction="in")
            tick_params(axis="y", direction="in")

            # adjust yticks #
            ylist = ax.get_yticks().tolist()

            # set ymin #
            ymin = long(min(ylist))
            if ymin < 0:
                ymin = 0
            elif ymin == 0:
                try:
                    ax.set_ylim(bottom=0)
                except:
                    pass

            # update yticks #
            TaskAnalyzer.drawYticks(ax, ymax)

            try:
                # ax.get_xaxis().set_visible(False)
                ytickLabel = ax.get_yticks().tolist()
                ytickLabel = list(map(long, ytickLabel))

                # convert label units #
                ytickLabel = [convSize(val << 20) for val in ytickLabel]

                # remove redundant ticks #
                lastTick = ""
                tempLabelList = list(ytickLabel)
                for idx, ytick in enumerate(tempLabelList):
                    if lastTick == ytick:
                        ytickLabel[idx] = ""
                    else:
                        lastTick = ytick

                ax.set_yticklabels(ytickLabel)
            except SystemExit:
                sys.exit(0)
            except:
                pass

            xticks(fontsize=self.xfsize)
            if len(timeline) > 1:
                xlim([timeline[0], timeline[-1]])

            # draw name #
            TaskAnalyzer.drawName(ax, "MEM")

            # draw base #
            self.figure = TaskAnalyzer.drawFigure()

            self.drawBottom(xtype, ax, timeline, nrTask, effectProcList)

        # ==================== BODY PART ====================#

        SysMgr.printStat(r"start drawing graphs...")

        """
        initialize list that count the number of process
        using resource more than 1% #
        """

        # get timeline #
        if "timeline" in graphStats:
            timeline = graphStats["timeline"]
        else:
            timeline = []
            for key, val in graphStats.items():
                if key.endswith("timeline") and len(val) > len(timeline):
                    timeline = val

        # get nrCore #
        if "nrCore" in graphStats:
            nrCore = graphStats["nrCore"]
        else:
            nrCore = []
            for key, val in graphStats.items():
                if key.endswith("nrCore") and len(val) > len(nrCore):
                    nrCore = val

        # get nrTask #
        if "nrTask" in graphStats:
            nrTask = graphStats["nrTask"]
        else:
            nrTask = []
            for key, val in graphStats.items():
                if key.endswith("nrTask") and len(val) > len(nrTask):
                    nrTask = val

        # get effectProcList #
        effectProcList = [0] * len(timeline)

        # draw plots #
        if not SysMgr.layout:
            _drawCpu(graphStats, 3, 0, 4)
            _drawEvent(graphStats)
            _drawIo(graphStats, 2, 4, 1)
            _drawMem(graphStats, 1, 5, 1)
        else:
            self.drawLayout(
                graphStats, _drawCpu, _drawMem, _drawIo, _drawEvent
            )

        # draw system info #
        try:
            if SysMgr.systemInfoBuffer and len(SysMgr.systemInfoBuffer) > 0:
                if not SysMgr.origArgs:
                    SysMgr.origArgs = ["None"]

                # add draw command #
                drawCmdStr = "{0:20} # {1:<100}".format(
                    "DrawCmd", " ".join(SysMgr.origArgs)
                )
                SysMgr.systemInfoBuffer = (
                    SysMgr.systemInfoBuffer[:-1] + drawCmdStr
                )

                self.figure.text(
                    0, 1, SysMgr.systemInfoBuffer, va="top", ha="left", size=2
                )
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("failed to write system info", True, reason=True)

        # remove stats to free memory #
        graphStats.clear()

        # save to file #
        TaskAnalyzer.saveImage(logFile, "graph", outFile=outFile)

    def getMargin(self):
        # pylint: disable=undefined-variable

        ytick = yticks()[0]
        if len(ytick) > 1:
            margin = (ytick[1] - ytick[0]) / 10
        else:
            margin = 0

        return margin

    def drawAvgGraph(self, graphStats, logFile, outFile=None):
        def _getTextAlign(idx, timeline):
            if idx < len(timeline) / 4:
                return "left"
            elif idx > len(timeline) / 4 * 3:
                return "right"
            else:
                return "center"

        def _getPathEffect(lw=2):
            try:
                pe = SysMgr.getPkg("matplotlib.patheffects", False)
                return [
                    pe.Stroke(linewidth=lw, foreground="black"),
                    pe.Normal(),
                ]
            except SystemExit:
                sys.exit(0)
            except:
                return []

        def _getPlotAttr(idx):
            try:
                lw = 0.7
                pe = []

                if not "STROKE" in SysMgr.environList:
                    pass
                elif UtilMgr.isValidStr(idx, SysMgr.environList["STROKE"]):
                    lw = 1
                    pe = _getPathEffect()
            except:
                pass

            return lw, pe

        def _convNameLabel(fileList):
            newList = []
            for idx, name in enumerate(fileList):
                if idx & 1:
                    name = "\n%s" % name
                newList.append(name)
            return newList

        def _drawAvgCpu(graphStats, xtype, pos, size):
            # pylint: disable=undefined-variable

            # draw title #
            ax = subplot2grid((6, 1), (pos, 0), rowspan=size, colspan=1)
            ax.xaxis.set_major_locator(MaxNLocator(integer=True))
            suptitle("Guider Average Graph", fontsize=8)

            # define common label list #
            ymax = 0
            labelList = []

            # create new timeline #
            timeline = xrange(len(graphStats["timeline"]))
            lent = len(timeline)

            cpuUsage = graphStats["cpuUsage"]
            cpuProcUsage = graphStats["cpuProcUsage"]
            blkWait = graphStats["blkWait"]
            blkProcUsage = graphStats["blkProcUsage"]
            try:
                gpuUsage = graphStats["gpuUsage"]
            except:
                gpuUsage = {}
            nrCore = graphStats["nrCore"]
            maxCore = max(nrCore)

            # convert total CPU usage by core number #
            if not SysMgr.cpuAvgEnable:
                cpuUsage = [maxCore * i for i in cpuUsage]

            # set visible total usage flag #
            if SysMgr.showAll or not SysMgr.filterGroup:
                isVisibleTotal = True
            else:
                isVisibleTotal = False

            # add boundary line #
            self.drawBoundary("cpu", labelList)

            # draw user event #
            self.drawUserEvent("cpu")

            # get plot path effect #
            pe = _getPathEffect()

            # -------------------- Total GPU usage --------------------#
            if isVisibleTotal:
                for gpu, stat in gpuUsage.items():
                    if UtilMgr.isString(stat):
                        stat = list(map(long, stat.split()))[:lent]
                    else:
                        stat = stat[:lent]

                    try:
                        if min(stat) == max(stat):
                            continue
                    except:
                        pass

                    # draw total GPU graph #
                    plot(
                        timeline,
                        stat,
                        "-",
                        c="olive",
                        linestyle="-",
                        linewidth=2,
                        marker="d",
                        markersize=1,
                        path_effects=pe,
                        solid_capstyle="round",
                    )

                    maxUsage = max(stat)
                    labelList.append("[ %s ] - %s%%" % (gpu, maxUsage))

                    margin = self.getMargin()

                    for idx, usage in enumerate(stat):
                        if usage == 0:
                            continue
                        text(
                            timeline[idx],
                            usage + margin,
                            "%d%%" % usage,
                            fontsize=self.lfsize + 1,
                            color="olive",
                            fontweight="bold",
                            bbox=dict(
                                boxstyle="round", facecolor="wheat", alpha=0.3
                            ),
                            ha=_getTextAlign(idx, timeline),
                        )

            # -------------------- Total CPU usage --------------------#
            if isVisibleTotal:
                if sum(blkWait) > 0:
                    for idx, item in enumerate(blkWait):
                        blkWait[idx] += cpuUsage[idx]

                        # update the maximum ytick #
                        if ymax < blkWait[idx]:
                            ymax = blkWait[idx]

                    # draw total CPU + iowait graph #
                    plot(
                        timeline,
                        blkWait,
                        "-",
                        c="pink",
                        linestyle="-",
                        linewidth=2,
                        marker="d",
                        markersize=1,
                        path_effects=pe,
                        solid_capstyle="round",
                    )

                    maxUsage = max(blkWait)
                    labelList.append(
                        "[ CPU+IO Average ] - %.1f%%" % (maxUsage)
                    )

                    margin = self.getMargin()

                    for idx, usage in enumerate(blkWait):
                        if usage == 0:
                            continue
                        text(
                            timeline[idx],
                            usage + margin,
                            "%d%%" % usage,
                            fontsize=self.lfsize + 1,
                            color="pink",
                            fontweight="bold",
                            bbox=dict(
                                boxstyle="round", facecolor="wheat", alpha=0.3
                            ),
                            ha=_getTextAlign(idx, timeline),
                        )

                # draw total CPU graph #
                plot(
                    timeline,
                    cpuUsage,
                    "-",
                    c="red",
                    linestyle="-",
                    linewidth=2,
                    marker="d",
                    markersize=1,
                    path_effects=pe,
                    solid_capstyle="round",
                )

                maxUsage = max(cpuUsage)
                labelList.append("[ CPU Average ] - %s%%" % maxUsage)

                # update the maximum ytick #
                if ymax < maxUsage:
                    ymax = maxUsage

                # set margin #
                margin = self.getMargin()

                for idx, usage in enumerate(cpuUsage):
                    if usage == 0:
                        continue
                    text(
                        timeline[idx],
                        usage + margin,
                        "%d%%" % usage,
                        fontsize=self.lfsize + 1,
                        color="red",
                        fontweight="bold",
                        bbox=dict(
                            boxstyle="round", facecolor="wheat", alpha=0.3
                        ),
                        ha=_getTextAlign(idx, timeline),
                    )

            # -------------------- Process CPU usage --------------------#
            # Total Process CPU usage filtered #
            if "[ TOTAL ]" in cpuProcUsage and len(cpuProcUsage) > 2:
                totalUsage = cpuProcUsage["[ TOTAL ]"]
                totalUsage = list(map(long, totalUsage))[:lent]

                # draw total graph #
                plot(
                    timeline,
                    totalUsage,
                    "-",
                    c="green",
                    linestyle="-",
                    linewidth=2,
                    marker="d",
                    markersize=1,
                    path_effects=pe,
                    solid_capstyle="round",
                )

                maxUsage = max(totalUsage)
                labelList.append("[ TOTAL ] - %d%%" % maxUsage)

                margin = self.getMargin()

                # update the maximum ytick #
                if ymax < maxUsage:
                    ymax = maxUsage

                for idx, usage in enumerate(totalUsage):
                    if usage == 0:
                        continue
                    text(
                        timeline[idx],
                        usage + margin,
                        "%d%%" % usage,
                        fontsize=self.lfsize + 1,
                        color="green",
                        fontweight="bold",
                        bbox=dict(
                            boxstyle="round", facecolor="wheat", alpha=0.3
                        ),
                        ha=_getTextAlign(idx, timeline),
                    )

            # define top variable #
            tcnt = 0

            # Process CPU usage #
            for idx, item in sorted(
                cpuProcUsage.items(),
                key=lambda e: sum(list(map(long, e[1]))),
                reverse=True,
            ):

                if not SysMgr.cpuEnable:
                    break

                if idx == "[ TOTAL ]":
                    continue

                # check top number #
                if SysMgr.nrTop:
                    if tcnt >= SysMgr.nrTop:
                        break
                    else:
                        tcnt += 1

                usage = list(map(long, item))[:lent]
                cpuUsage = list(usage)

                if not SysMgr.blockEnable:
                    # merge CPU usage and wait time for processes #
                    try:
                        blkUsage = blkProcUsage[idx]
                        blkUsage = list(map(long, blkUsage))
                        for interval, value in enumerate(blkUsage):
                            usage[interval] += value
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass

                # update the maximum ytick #
                maxusage = max(usage)
                if ymax < maxusage:
                    ymax = maxusage

                # get plot attr #
                lw, pe = _getPlotAttr(idx)

                maxIdx = usage.index(maxusage)
                color = plot(timeline, usage, "-", path_effects=pe)[
                    0
                ].get_color()

                margin = self.getMargin()

                maxCpuPer = str(cpuUsage[maxIdx])
                if idx in blkProcUsage and not SysMgr.blockEnable:
                    maxBlkPer = str(blkUsage[maxIdx])
                else:
                    maxBlkPer = "0"
                maxPer = "(%s%%+%s%%)" % (maxCpuPer, maxBlkPer)

                for pidx, usage in enumerate(cpuUsage):
                    if usage == 0:
                        continue

                    if (
                        "[ TOTAL ]" in cpuProcUsage
                        and len(cpuProcUsage) > 2
                        and cpuProcUsage["[ TOTAL ]"][pidx] == usage
                    ):
                        continue

                    text(
                        timeline[pidx],
                        usage + margin,
                        "%d%%" % usage,
                        fontsize=self.lfsize + 1,
                        color=color,
                        fontweight="bold",
                        ha=_getTextAlign(maxIdx, timeline),
                    )

                labelList.append("%s - %s%%" % (idx, maxCpuPer))

            cpuProcUsage.pop("[ TOTAL ]", None)

            # draw label #
            TaskAnalyzer.drawLabel(labelList, draw=True, anchor=(1.12, 1.05))

            grid(which="both", linestyle=":", linewidth=0.2)
            tick_params(axis="x", direction="in")
            tick_params(axis="y", direction="in")

            # update ymax #
            if SysMgr.funcDepth > 0:
                ymax = SysMgr.funcDepth

            # set xticks attributes #
            ax.set_xticklabels(_convNameLabel(graphStats["fileList"]))
            xticks(fontsize=self.xfsize)
            if len(timeline) > 1:
                xlim([timeline[0], timeline[-1]])

            # update yticks #
            TaskAnalyzer.drawYticks(ax, ymax)

            # add % unit to each value #
            try:
                # convert label units #
                ytickLabel = ax.get_yticks().tolist()
                ytickLabel = list(map(long, ytickLabel))
                ytickLabel = ["%s%%" % val for val in ytickLabel]
                ytickLabel[0] = ""
                ax.set_yticklabels(ytickLabel)

                # remove space between axis and label #
                tick_params(pad=1)
            except SystemExit:
                sys.exit(0)
            except:
                pass

            # draw name #
            TaskAnalyzer.drawName(ax, "CPU")

            # draw base #
            self.figure = TaskAnalyzer.drawFigure()

        def _drawAvgMem(graphStats, xtype, pos, size):
            # pylint: disable=undefined-variable
            def __drawSystemMem(statList, color, ymax):
                usage = list(map(long, statList))
                minIdx = usage.index(min(usage))
                maxIdx = usage.index(max(usage))

                if usage[minIdx] == usage[maxIdx] == 0:
                    return None, ymax

                # update the maximum ytick #
                maxUsage = max(usage)
                if ymax < maxUsage:
                    ymax = maxUsage

                # get plot path effect #
                pe = _getPathEffect()

                plot(
                    timeline,
                    usage,
                    "-",
                    c=color,
                    linewidth=2,
                    path_effects=pe,
                    solid_capstyle="round",
                )

                for pidx, value in enumerate(usage):
                    if value == 0:
                        continue
                    size = convSize2Unit(value << 20)
                    text(
                        timeline[pidx],
                        value,
                        size,
                        color=color,
                        fontsize=self.lfsize + 1,
                        ha=_getTextAlign(maxIdx, timeline),
                    )

                return usage[-1], ymax

            # define common label list #
            ymax = 0
            labelList = []

            # set convert size #
            convSize2Unit = UtilMgr.convSize2Unit

            # draw title #
            ax = subplot2grid((6, 1), (pos, 0), rowspan=size, colspan=1)
            ax.xaxis.set_major_locator(MaxNLocator(integer=True))
            suptitle(graphStats["graphTitle"], fontsize=8)

            # add boundary line #
            self.drawBoundary("mem", labelList)

            # draw user event #
            self.drawUserEvent("mem")

            # define top variable #
            tcnt = 0

            # create new timeline #
            timeline = xrange(len(graphStats["timeline"]))
            lent = len(timeline)

            totalRam = graphStats["totalRam"]
            memFree = graphStats["memFree"]
            memAnon = graphStats["memAnon"]
            memCache = graphStats["memCache"]
            memProc = graphStats["memProcUsage"]
            totalSwap = graphStats["totalSwap"]
            swapUsage = graphStats["swapUsage"]

            # get margin #
            margin = self.getMargin()

            # Process VSS #
            if SysMgr.vssEnable:
                for key, item in sorted(
                    memProc.items(),
                    key=lambda e: sum(list(map(long, e[1]))),
                    reverse=True,
                ):

                    # check top number #
                    if SysMgr.nrTop:
                        if tcnt >= SysMgr.nrTop:
                            break
                        else:
                            tcnt += 1

                    usage = list(map(long, item))[:lent]

                    # update the maximum ytick #
                    maxUsage = max(usage)
                    if ymax < maxUsage:
                        ymax = maxUsage
                    maxIdx = usage.index(maxUsage)

                    # get plot attr #
                    lw, pe = _getPlotAttr(key)

                    # get color #
                    color = plot(
                        timeline, usage, "-", linewidth=1, path_effects=pe
                    )[0].get_color()

                    lastUsage = "?"
                    for pidx, value in enumerate(usage):
                        if value == 0:
                            continue
                        lastUsage = size = convSize2Unit(value << 20)
                        text(
                            timeline[pidx],
                            value + margin,
                            size,
                            color=color,
                            fontsize=self.lfsize + 1,
                            ha=_getTextAlign(maxIdx, timeline),
                        )

                    labelList.append("%s [VSS] - %s" % (key, lastUsage))

            # Process RSS #
            elif SysMgr.rssEnable or SysMgr.pssEnable or SysMgr.ussEnable:
                for key, item in sorted(
                    memProc.items(),
                    key=lambda e: sum(list(map(long, e[1]))),
                    reverse=True,
                ):

                    # check top number #
                    if SysMgr.nrTop:
                        if tcnt >= SysMgr.nrTop:
                            break
                        else:
                            tcnt += 1

                    usage = list(map(long, item))[:lent]

                    # update the maximum ytick #
                    maxUsage = max(usage)
                    if ymax < maxUsage:
                        ymax = maxUsage
                    maxIdx = usage.index(maxUsage)

                    # get plot attr #
                    lw, pe = _getPlotAttr(key)

                    # get color #
                    color = plot(
                        timeline, usage, "-", linewidth=1, path_effects=pe
                    )[0].get_color()

                    lastUsage = "?"
                    for pidx, value in enumerate(usage):
                        if value == 0:
                            continue
                        lastUsage = size = convSize2Unit(value << 20)
                        text(
                            timeline[pidx],
                            value + margin,
                            size,
                            color=color,
                            fontsize=self.lfsize + 1,
                            ha=_getTextAlign(maxIdx, timeline),
                        )

                    # set memory type #
                    if SysMgr.pssEnable:
                        mem = "PSS"
                    elif SysMgr.ussEnable:
                        mem = "USS"
                    else:
                        mem = "RSS"

                    labelList.append("%s [%s] - %s" % (key, mem, lastUsage))

            # System #
            else:
                # System Free Memory #
                lastsize, ymax = __drawSystemMem(memFree, "blue", ymax)
                if lastsize is not None:
                    if totalRam:
                        label = "[ RAM Total ] - %s\nRAM Available - %s" % (
                            convSize2Unit(totalRam),
                            lastsize,
                        )
                        labelList.append(label)
                    else:
                        labelList.append("RAM Available - %s" % lastsize)

                # System Anon Memory #
                lastsize, ymax = __drawSystemMem(memAnon, "skyblue", ymax)
                if lastsize is not None:
                    labelList.append("RAM User - %s" % lastsize)

                # System Cache Memory #
                lastsize, ymax = __drawSystemMem(memCache, "darkgray", ymax)
                if lastsize is not None:
                    labelList.append("RAM Cache - %s" % lastsize)

                # System Swap Memory #
                lastsize, ymax = __drawSystemMem(swapUsage, "orange", ymax)
                if lastsize is not None:
                    if totalSwap:
                        label = "[ Swap Total ] - %s\nSwap Usage - %s" % (
                            convSize2Unit(totalSwap),
                            lastsize,
                        )
                        labelList.append(label)
                    else:
                        labelList.append("Swap Usage - %s" % lastsize)

            """
            ylabel('MEMORY', fontsize=5)
            ax.yaxis.set_label_coords(-0.05,0.5)
            """

            # draw label #
            TaskAnalyzer.drawLabel(labelList, draw=True, anchor=(1.12, 0.75))

            grid(which="both", linestyle=":", linewidth=0.2)
            tick_params(axis="x", direction="in")
            tick_params(axis="y", direction="in")

            # adjust yticks #
            ylist = ax.get_yticks().tolist()

            # update yticks #
            TaskAnalyzer.drawYticks(ax, ymax)

            try:
                # ax.get_xaxis().set_visible(False)
                ytickLabel = ax.get_yticks().tolist()
                ytickLabel = list(map(long, ytickLabel))

                # convert label units #
                ytickLabel = [convSize2Unit(val << 20) for val in ytickLabel]

                # remove redundant ticks #
                lastTick = ""
                tempLabelList = list(ytickLabel)
                for idx, ytick in enumerate(tempLabelList):
                    if lastTick == ytick:
                        ytickLabel[idx] = ""
                    else:
                        lastTick = ytick
                ytickLabel[0] = ""
                ax.set_yticklabels(ytickLabel)

                # remove space between axis and label #
                tick_params(pad=1)
            except SystemExit:
                sys.exit(0)
            except:
                pass

            # set xticks attributes #
            ax.set_xticklabels(_convNameLabel(graphStats["fileList"]))
            xticks(fontsize=self.xfsize)
            if len(timeline) > 1:
                xlim([timeline[0], timeline[-1]])

            # draw name #
            TaskAnalyzer.drawName(ax, "MEM")

            # draw base #
            self.figure = TaskAnalyzer.drawFigure()

        SysMgr.printStat(r"start drawing average graphs...")

        # draw All #
        if SysMgr.checkMode("drawavg", True):
            if not SysMgr.layout:
                _drawAvgCpu(graphStats, 3, 0, 4)
                _drawAvgMem(graphStats, 1, 4, 2)
            else:
                self.drawLayout(
                    graphStats, _drawAvgCpu, _drawAvgMem, None, None
                )

        # draw CPU #
        elif SysMgr.checkMode("drawcpuavg", True):
            _drawAvgCpu(graphStats, 3, 0, 6)
        # draw Memory #
        else:
            _drawAvgMem(graphStats, 3, 0, 6)

        # remove stats to free memory #
        graphStats.clear()

        # save to file #
        TaskAnalyzer.saveImage(logFile, "graph", outFile=outFile)

    @staticmethod
    def saveImage(logFile, itype="", outFile=None):
        # get pylab object #
        SysMgr.importPkgItems("pylab")

        # get output file name #
        outputFile = UtilMgr.prepareForImageFile(logFile, itype, outFile)

        try:
            # save graph #
            savefig(  # pylint: disable=undefined-variable
                outputFile, dpi=SysMgr.matplotlibDpi
            )
            clf()  # pylint: disable=undefined-variable

            # get output size #
            fsize = UtilMgr.getFileSizeStr(outputFile)

            SysMgr.printStat(
                "wrote resource %s into '%s'%s" % (itype, outputFile, fsize)
            )
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to draw image to '%s'" % outputFile, True)
            return

    def sampleStack(self, period):
        def _findNthStr(s, x, n, i=0):
            i = s.find(x, i)
            if n == 1 or i == -1:
                return i
            else:
                return _findNthStr(s, x, n - 1, i + len(x))

        start = time.time()

        while 1:
            for idx in list(self.stackTable):
                item = self.stackTable[idx]

                # read stack #
                try:
                    item["fd"].seek(0)
                    stack = item["fd"].read()
                except SystemExit:
                    sys.exit(0)
                except:
                    self.stackTable.pop(idx, None)
                    continue

                # cut stack length #
                try:
                    if SysMgr.funcDepth > 0:
                        nth = _findNthStr(stack, "\n", SysMgr.funcDepth)
                        stack = stack[:nth]
                except:
                    pass

                # count sampled stack #
                try:
                    item["total"] += 1
                    item["stack"][stack] += 1
                except SystemExit:
                    sys.exit(0)
                except:
                    item["stack"][stack] = 1

            if time.time() - start >= period:
                return

            # set 1ms as sampling rate #
            time.sleep(0.001)

    def getRunTaskNum(self):
        return len(self.threadData) - SysMgr.nrCore

    def printCreationTree(self, tid, loc):
        try:
            childList = self.threadData[tid]["childList"]
        except:
            return

        threadName = "%s(%s)" % (self.threadData[tid]["comm"], tid)

        if self.threadData[tid]["createdTime"] > 0:
            threadName += " /%2.3f/" % (
                self.threadData[tid]["createdTime"] - float(SysMgr.startTime)
            )

        if self.threadData[tid]["usage"] > 0:
            threadName += " <%2.3f>" % (self.threadData[tid]["usage"])

        if self.threadData[tid]["childList"]:
            threadName += " |%d|" % (len(self.threadData[tid]["childList"]))

        if self.threadData[tid]["waitChild"] > 0:
            threadName += " {%1.3f}" % (self.threadData[tid]["waitChild"])

        if self.threadData[tid]["waitParent"] > 0:
            threadName += " [%1.3f]" % (self.threadData[tid]["waitParent"])

        # set new position of line #
        newLoc = loc + 5

        if self.threadData[tid]["die"] == " ":
            life = "+ "
        else:
            life = "- "

        SysMgr.printPipe(" " * loc + life + threadName)

        if childList:
            for thread in childList:
                self.printCreationTree(thread, newLoc)

    @staticmethod
    def getCoreId(string):
        try:
            offset = string.rfind("/")
            if offset >= 0:
                return long(string[offset + 1 :])
            else:
                return -1
        except:
            return -1

    def printComInfo(self):
        convNum = UtilMgr.convNum

        # print thread tree by creation #
        if SysMgr.showAll and self.nrNewTask > 0:
            SysMgr.clearPrint()
            SysMgr.printPipe(
                (
                    "\n[Thread Creation Info] [Alive: +] [Die: -] "
                    "[CreatedTime: //] [ChildCount: ||] "
                    "[CpuUsage: <>] [WaitForChildren: {}] "
                    "[WaitOfParent: []]\n%s"
                )
                % twoLine
            )

            cnt = 0
            for key, value in sorted(
                self.threadData.items(),
                key=lambda e: e[1]["waitChild"],
                reverse=True,
            ):

                # print tree from root threads #
                if value["childList"] and value["new"] == " ":
                    cnt += 1
                    self.printCreationTree(key, 0)
            if cnt == 0:
                SysMgr.printPipe("\tNone")
            SysMgr.printPipe(oneLine)

        # print signal traffic #
        if SysMgr.showAll and len(self.sigData) > 0:
            SysMgr.clearPrint()
            SysMgr.printPipe("\n[Thread Signal Info]")
            SysMgr.printPipe(twoLine)
            SysMgr.printPipe(
                (
                    "{0:^6} {1:>10} {2:>40}({3:>7}) {4:^10} "
                    "{5:>40}({6:>7})\n{7:1}"
                ).format(
                    "TYPE",
                    "TIME",
                    "SENDER",
                    "TID",
                    "SIGNAL",
                    "RECEIVER",
                    "TID",
                    twoLine,
                )
            )

            cnt = 0
            for val in self.sigData:
                try:
                    signal = ConfigMgr.SIG_LIST[int(val[4])]
                except:
                    signal = "SIG_%s" % val[4]

                stype = val[0]
                stime = val[1]
                stid = val[2]
                rtid = val[3]

                # skip useless signal log #
                if (
                    (stid and stid[0] == "0") or stid not in self.threadData
                ) and (
                    (rtid and rtid[0] == "0") or rtid not in self.threadData
                ):
                    continue

                try:
                    scomm = self.threadData[stid]["comm"]
                except:
                    scomm = "?"

                try:
                    rcomm = self.threadData[rtid]["comm"]
                except:
                    rcomm = "?"

                if stype == "SEND":
                    if stid.startswith("0["):
                        stid = 0

                    SysMgr.printPipe(
                        (
                            "{0:^6} {1:>10.6f} {2:>40}({3:>7}) "
                            "{4:^10} {5:>40}({6:>7})"
                        ).format(
                            stype, stime, scomm, stid, signal, rcomm, rtid
                        )
                    )

                    cnt += 1
                elif val[0] == "RECV":
                    SysMgr.printPipe(
                        (
                            "{0:^6} {1:>10.6f} {2:>40} {3:>7}  "
                            "{4:^10} {5:>40}({6:>7})"
                        ).format(stype, stime, " ", " ", signal, rcomm, rtid)
                    )

                    cnt += 1
            if cnt == 0:
                SysMgr.printPipe("\tNone")
            SysMgr.printPipe(oneLine)

        # print workqueue information #
        if self.wqData:
            totalCnt = 0
            totalUsage = 0.0

            SysMgr.printPipe(
                (
                    "\n[Thread Workqueue Info] [Elapsed: %.3f] "
                    "(Unit: Sec/NR)\n%s"
                )
                % (float(self.totalTime), twoLine)
            )
            SysMgr.printPipe(
                (
                    "{0:^32} {1:>12} {2:>10} {3:>10} "
                    "{4:>10} {5:>10} {6:>10} {7:>10} {8:>6}\n{9:1}"
                ).format(
                    "Name",
                    "Count",
                    "Usage",
                    "ProcAvg",
                    "ProcMax",
                    "ProcMin",
                    "InterMax",
                    "InterMin",
                    "NrTask",
                    twoLine,
                )
            )

            SysMgr.clearPrint()

            # merge by name #
            wqData = {}
            for struct, item in self.wqData.items():
                name = item["name"]

                # change default stat value -1 to 0 #
                for key in list(item):
                    if item[key] == -1:
                        item[key] = 0

                if not name in wqData:
                    wqData[name] = UtilMgr.deepcopy(item)
                    continue

                target = wqData[name]

                # change default stat value -1 to 0 #
                for key in list(target):
                    if target[key] == -1:
                        target[key] = 0

                target["scount"] += item["scount"]
                target["rcount"] += item["rcount"]
                target["usage"] += item["usage"]
                target["task"].update(item["task"])

                if target["max"] < item["max"]:
                    target["max"] = item["max"]
                if target["min"] > item["min"]:
                    target["min"] = item["min"]
                if target["maxPeriod"] < item["maxPeriod"]:
                    target["maxPeriod"] = item["maxPeriod"]
                if target["minPeriod"] > item["minPeriod"]:
                    target["minPeriod"] = item["minPeriod"]

            # print summary #
            for struct, item in sorted(
                wqData.items(), key=lambda e: e[1]["usage"], reverse=True
            ):
                totalCnt += item["scount"]
                totalUsage += item["usage"]
                avg = item["usage"] / item["rcount"]
                tasks = convNum(len(item["task"]))
                SysMgr.addPrint(
                    (
                        "{0:<32} {1:>12} {2:>10.6f} {3:>10.6f} "
                        "{4:>10.6f} {5:>10.6f} {6:>10.6f} {7:>10.6f} {8:>6}\n"
                    ).format(
                        item["name"],
                        convNum(item["scount"]),
                        item["usage"],
                        avg,
                        item["max"],
                        item["min"],
                        item["maxPeriod"],
                        item["minPeriod"],
                        tasks,
                    )
                )

            SysMgr.printPipe(
                "%s# WORKQUEUE(%s) / Total(%6.3f) / Cnt(%s)\n\n"
                % ("", convNum(len(wqData)), totalUsage, convNum(totalCnt))
            )
            SysMgr.doPrint(clear=True)
            SysMgr.printPipe(oneLine)

        # print interrupt information #
        if self.irqData:
            totalCnt = 0
            totalUsage = 0.0

            SysMgr.printPipe(
                ("\n[Thread IRQ Info] [Elapsed: %.3f] (Unit: Sec/NR)\n%s")
                % (float(self.totalTime), twoLine)
            )
            SysMgr.printPipe(
                (
                    "{0:^16} {1:<62} {2:>12} {3:>10} {4:>10} "
                    "{5:>10} {6:>10} {7:>10}\n{8:1}"
                ).format(
                    "IRQ",
                    "Name",
                    "Count",
                    "Usage",
                    "ProcMax",
                    "ProcMin",
                    "InterMax",
                    "InterMin",
                    twoLine,
                )
            )

            SysMgr.clearPrint()

            # print irq list #
            irqList = [
                irq for irq in list(self.irqData) if irq.startswith("irq")
            ]
            for key in sorted(irqList, key=lambda e: int(e.split("/")[1])):
                totalCnt += self.irqData[key]["count"]
                totalUsage += self.irqData[key]["usage"]
                SysMgr.addPrint(
                    (
                        "{0:>16} {1:<62} {2:>12} {3:>10.6f} {4:>10.6f} "
                        "{5:>10.6f} {6:>10.6f} {7:>10.6f}\n"
                    ).format(
                        key,
                        " | ".join(list(self.irqData[key]["name"])),
                        convNum(self.irqData[key]["count"]),
                        self.irqData[key]["usage"],
                        self.irqData[key]["max"],
                        self.irqData[key]["min"],
                        self.irqData[key]["maxPeriod"],
                        self.irqData[key]["minPeriod"],
                    )
                )

            # print softirq list #
            sirqList = [
                irq for irq in list(self.irqData) if irq.startswith("softirq")
            ]
            for key in sorted(sirqList, key=lambda e: int(e.split("/")[1])):
                totalCnt += self.irqData[key]["count"]
                totalUsage += self.irqData[key]["usage"]
                SysMgr.addPrint(
                    (
                        "{0:>16} {1:<62} {2:>12} {3:>10.6f} {4:>10.6f} "
                        "{5:>10.6f} {6:>10.6f} {7:>10.6f}\n"
                    ).format(
                        key,
                        " | ".join(list(self.irqData[key]["name"])),
                        convNum(self.irqData[key]["count"]),
                        self.irqData[key]["usage"],
                        self.irqData[key]["max"],
                        self.irqData[key]["min"],
                        self.irqData[key]["maxPeriod"],
                        self.irqData[key]["minPeriod"],
                    )
                )

            SysMgr.printPipe(
                "%s# IRQ(%s) / Total(%6.3f) / Cnt(%s)\n\n"
                % (
                    "",
                    convNum(len(self.irqData)),
                    totalUsage,
                    convNum(totalCnt),
                )
            )
            SysMgr.doPrint(clear=True)
            SysMgr.printPipe(oneLine)

    def printEventInfo(self):
        # pick up event info from thread info #
        for key, value in sorted(self.threadData.items()):
            if value["customEvent"]:
                self.customInfo[key] = value["customEvent"]
            if value["userEvent"]:
                self.userInfo[key] = value["userEvent"]
            if value["kernelEvent"]:
                self.kernelInfo[key] = value["kernelEvent"]

        # print custom event info #
        if self.customEventInfo:
            SysMgr.clearPrint()
            SysMgr.printPipe("\n[Thread CUSTOM Event Info]\n%s" % twoLine)
            SysMgr.printPipe(
                (
                    "{0:^32} {1:>32}({2:>7}) {3:>10} " "{4:>10} {5:>10}\n{6:1}"
                ).format(
                    "Event",
                    "COMM",
                    "TID",
                    "Count",
                    "MaxPeriod",
                    "MinPeriod",
                    twoLine,
                )
            )

            newLine = False
            for idx, val in sorted(
                self.customEventInfo.items(),
                key=lambda e: e[1]["count"],
                reverse=True,
            ):
                if newLine:
                    SysMgr.printPipe()
                else:
                    newLine = True

                SysMgr.printPipe(
                    (
                        "{0:<32} {1:>32}({2:>7}) {3:>10} "
                        "{4:>10.6f} {5:>10.6f}"
                    ).format(
                        idx,
                        "TOTAL",
                        "-",
                        val["count"],
                        val["maxPeriod"],
                        val["minPeriod"],
                    )
                )

                for key, value in sorted(
                    self.customInfo.items(),
                    key=lambda e: 0 if not idx in e[1] else e[1][idx]["count"],
                    reverse=True,
                ):

                    try:
                        value[idx]
                        self.threadData[key]["comm"]
                    except:
                        continue

                    SysMgr.printPipe(
                        (
                            "{0:<32} {1:>32}({2:>7}) {3:>10} {4:>10.6f} "
                            "{5:>10.6f}"
                        ).format(
                            " ",
                            self.threadData[key]["comm"],
                            key,
                            value[idx]["count"],
                            value[idx]["maxPeriod"],
                            value[idx]["minPeriod"],
                        )
                    )
                SysMgr.printPipe(oneLine)

        # print custom event history #
        if SysMgr.showAll and len(self.customEventData) > 0:
            SysMgr.clearPrint()
            SysMgr.printPipe("\n[Thread CUSTOM Event History]\n%s" % twoLine)
            SysMgr.printPipe(
                "{0:^32} {1:^10} {2:>16}({3:>7}) {4:<1}\n{5:1}".format(
                    "EVENT", "TIME", "COMM", "TID", "ARG", twoLine
                )
            )

            cnt = 0
            for val in self.customEventData:
                skipFlag = False
                for fval in SysMgr.filterGroup:
                    if SysMgr.isValidTid(val[2], fval) or fval in val[1]:
                        skipFlag = False
                        break
                    skipFlag = True

                if skipFlag:
                    continue

                cnt += 1
                SysMgr.printPipe(
                    "{0:<32} {1:>10.6f} {2:>16}({3:>7}) {4:<1}".format(
                        val[0], val[3], val[1][:16], val[2], val[4]
                    )
                )
            if cnt == 0:
                SysMgr.printPipe("\tNone")
            SysMgr.printPipe(oneLine)

        # print user event info #
        if self.userEventInfo:
            SysMgr.clearPrint()
            SysMgr.printPipe("\n[Thread User Event Info]\n%s" % twoLine)
            SysMgr.printPipe(
                (
                    "{0:^32} {1:>16}({2:>7}) {3:>10} {4:>10} "
                    "{5:>10} {6:>10} {7:>10} {8:>10}\n{9:1}"
                ).format(
                    "Event",
                    "COMM",
                    "TID",
                    "Usage",
                    "Count",
                    "ProcMax",
                    "ProcMin",
                    "InterMax",
                    "InterMin",
                    twoLine,
                )
            )

            newLine = False
            for idx, val in sorted(
                self.userEventInfo.items(),
                key=lambda e: e[1]["usage"],
                reverse=True,
            ):

                if newLine:
                    SysMgr.printPipe()
                else:
                    newLine = True
                SysMgr.printPipe(
                    (
                        "{0:<32} {1:>16}({2:>7}) {3:>10.6f} {4:>10} {5:>10.6f} "
                        "{6:>10.6f} {7:>10.6f} {8:>10.6f}"
                    ).format(
                        idx,
                        "TOTAL",
                        "-",
                        val["usage"],
                        val["count"],
                        val["max"],
                        val["min"],
                        val["maxPeriod"],
                        val["minPeriod"],
                    )
                )

                for key, value in sorted(
                    self.userInfo.items(),
                    key=lambda e: 0 if not idx in e[1] else e[1][idx]["usage"],
                    reverse=True,
                ):

                    try:
                        value[idx]
                        self.threadData[key]["comm"]
                    except:
                        continue

                    SysMgr.printPipe(
                        (
                            "{0:<32} {1:>16}({2:>7}) {3:>10.6f} {4:>10} "
                            "{5:>10.6f} {6:>10.6f} {7:>10.6f} {8:>10.6f}"
                        ).format(
                            " ",
                            self.threadData[key]["comm"][:16],
                            key,
                            value[idx]["usage"],
                            value[idx]["count"],
                            value[idx]["max"],
                            value[idx]["min"],
                            value[idx]["maxPeriod"],
                            value[idx]["minPeriod"],
                        )
                    )
            SysMgr.printPipe(oneLine)

        # print user event history #
        if SysMgr.showAll and len(self.userEventData) > 0:
            SysMgr.clearPrint()
            SysMgr.printPipe("\n[Thread User Event History]\n%s" % twoLine)
            SysMgr.printPipe(
                (
                    "{0:^32} {1:>6} {2:^10} {3:>16}({4:>7}) "
                    "{5:^16} {6:>10}\n{7:1}"
                ).format(
                    "EVENT",
                    "TYPE",
                    "TIME",
                    "COMM",
                    "TID",
                    "CALLER",
                    "ELAPSED",
                    twoLine,
                )
            )

            cnt = 0
            callTable = {}
            for val in self.userEventData:
                elapsed = "-"

                skipFlag = False
                for fval in SysMgr.filterGroup:
                    if SysMgr.isValidTid(val[3], fval) or fval in val[2]:
                        skipFlag = False
                        break
                    skipFlag = True

                if skipFlag:
                    continue
                elif val[0] == "ENTER":
                    cid = "%s%s" % (val[1], val[3])
                    callTable[cid] = val[4]
                elif val[0] == "EXIT":
                    cid = "%s%s" % (val[1], val[3])
                    try:
                        elapsed = "%.6f" % (val[4] - callTable[cid])
                    except:
                        pass

                cnt += 1
                SysMgr.printPipe(
                    (
                        "{0:<32} {1:>6} {2:>10.6f} {3:>16}({4:>7}) "
                        "{5:>16} {6:>10}"
                    ).format(
                        val[1],
                        val[0],
                        val[4],
                        val[2][:16],
                        val[3],
                        val[5],
                        elapsed,
                    )
                )
            if cnt == 0:
                SysMgr.printPipe("\tNone")
            SysMgr.printPipe(oneLine)

        # print kernel event info #
        if self.kernelEventInfo:
            SysMgr.clearPrint()
            SysMgr.printPipe("\n[Thread Kernel Event Info]\n%s" % twoLine)
            SysMgr.printPipe(
                (
                    "{0:^32} {1:>16}({2:>7}) {3:>10} {4:>10} "
                    "{5:>10} {6:>10} {7:>10} {8:>10}\n{9:1}"
                ).format(
                    "Event",
                    "COMM",
                    "TID",
                    "Usage",
                    "Count",
                    "ProcMax",
                    "ProcMin",
                    "InterMax",
                    "InterMin",
                    twoLine,
                )
            )

            newLine = False
            for idx, val in sorted(
                self.kernelEventInfo.items(),
                key=lambda e: e[1]["usage"],
                reverse=True,
            ):

                if newLine:
                    SysMgr.printPipe()
                else:
                    newLine = True
                SysMgr.printPipe(
                    (
                        "{0:<32} {1:>16}({2:>7}) {3:>10.6f} {4:>10} {5:>10.6f} "
                        "{6:>10.6f} {7:>10.6f} {8:>10.6f}"
                    ).format(
                        idx,
                        "TOTAL",
                        "-",
                        val["usage"],
                        val["count"],
                        val["max"],
                        val["min"],
                        val["maxPeriod"],
                        val["minPeriod"],
                    )
                )

                for key, value in sorted(
                    self.kernelInfo.items(),
                    key=lambda e: 0 if not idx in e[1] else e[1][idx]["usage"],
                    reverse=True,
                ):

                    try:
                        value[idx]
                        self.threadData[key]["comm"]
                    except:
                        continue

                    SysMgr.printPipe(
                        (
                            "{0:<32} {1:>16}({2:>7}) {3:>10.6f} {4:>10} "
                            "{5:>10.6f} {6:>10.6f} {7:>10.6f} {8:>10.6f}"
                        ).format(
                            " ",
                            self.threadData[key]["comm"][:16],
                            key,
                            value[idx]["usage"],
                            value[idx]["count"],
                            value[idx]["max"],
                            value[idx]["min"],
                            value[idx]["maxPeriod"],
                            value[idx]["minPeriod"],
                        )
                    )
            SysMgr.printPipe(oneLine)

        # print kernel event history #
        if not SysMgr.showAll or not self.kernelEventData:
            return

        SysMgr.clearPrint()
        SysMgr.printPipe("\n[Thread Kernel Event History]\n%s" % twoLine)
        SysMgr.printPipe(
            (
                "{0:^32} {1:>6} {2:^10} {3:>16}({4:>7}) "
                "{5:^22} {6:>10} {7:<1}\n{8:1}"
            ).format(
                "EVENT",
                "TYPE",
                "TIME",
                "COMM",
                "TID",
                "CALLER",
                "ELAPSED",
                "ARG",
                twoLine,
            )
        )

        cnt = 0
        callTable = {}
        for val in self.kernelEventData:
            elapsed = "-"

            skipFlag = False
            for fval in SysMgr.filterGroup:
                if SysMgr.isValidTid(val[4], fval) or fval in val[3]:
                    skipFlag = False
                    break
                skipFlag = True

            if skipFlag:
                continue
            elif val[0] == "ENTER":
                cid = "%s%s" % (val[1], val[4])
                callTable[cid] = val[5]
            elif val[0] == "EXIT":
                cid = "%s%s" % (val[1], val[4])
                try:
                    elapsed = "%.6f" % (val[5] - callTable[cid])
                except:
                    pass

            cnt += 1
            args = (" ".join(val[7].split(" arg"))).replace("=", ">")
            SysMgr.printPipe(
                (
                    "{0:<32} {1:>6} {2:>10.6f} {3:>16}({4:>7}) "
                    "{5:>22} {6:>10} {7:<1}"
                ).format(
                    val[1],
                    val[0],
                    val[5],
                    val[3][:16],
                    val[4],
                    val[6],
                    elapsed,
                    args,
                )
            )
        if cnt == 0:
            SysMgr.printPipe("\tNone")
        SysMgr.printPipe(oneLine)

    def addSysInterval(self, res, key, value):
        if not SysMgr.maxInterval:
            return
        elif not res in SysMgr.thresholdTarget:
            return

        # TODO: filter only system resource #

        self.intervalData.setdefault(key, [])
        self.intervalData[key].append(value)
        mod = len(self.intervalData[key]) - SysMgr.maxInterval
        if mod > 0:
            self.intervalData[key] = self.intervalData[key][mod:]

    def addProcInterval(self, res, pid, target, key, value):
        if not SysMgr.maxInterval:
            return
        elif not SysMgr.taskThresholdEnable:
            return
        elif not res in SysMgr.thresholdTarget:
            return
        elif not SysMgr.thresholdTarget[res]:
            return

        try:
            target.setdefault(key, self.prevProcData[pid][key])
        except SystemExit:
            sys.exit(0)
        except:
            target.setdefault(key, [])

        target[key].append(value)
        mod = len(target[key]) - SysMgr.maxInterval
        if mod > 0:
            target[key] = target[key][mod:]

    def printUsage(self):
        # print system resource usage #
        self.printResourceUsage()

        # print communication info #
        self.printComInfo()

        # print event info #
        self.printEventInfo()

        # print page info #
        self.printPageInfo()

        # print block usage #
        self.printBlockInfo()

        # print fs usage #
        self.printFsInfo()

        # print open history #
        self.printOpenInfo()

        # print resource usage for threads on timeline #
        self.printIntervalInfo()

        # print kernel module info #
        self.printModuleInfo()

        # print dependency info #
        self.printDepInfo()

        # print lock usage #
        self.printFutexInfo()
        self.printFlockInfo()

        # print syscall usage #
        self.printSyscallInfo()

        # print LMK info #
        self.printLMKInfo()

        # print binder usage #
        self.printBinderInfo()

        # print kernel messages #
        self.printConsoleInfo()

    def printResourceUsage(self):
        # pylint: disable=undefined-variable

        title = "Thread Info"

        SysMgr.printLogo(big=True)

        # print system information #
        SysMgr.printInfoBuffer()

        convSize = UtilMgr.convSize2Unit
        convNum = UtilMgr.convNum

        # check trace event #
        if not (SysMgr.cpuEnable or SysMgr.memEnable or SysMgr.blockEnable):
            return

        # print menu #
        SysMgr.printPipe(
            (
                "[%s] [%s: %0.3f] [%s: %0.3f] [ActiveThread: %s] "
                "[ContextSwitch: %s] [LogSize: %s] (Unit: Sec/MB/NR)\n%s"
            )
            % (
                title,
                "Elapsed",
                round(float(self.totalTime), 7),
                "Start",
                round(float(SysMgr.startTime), 7),
                convNum(self.getRunTaskNum()),
                convNum(self.cxtSwitch),
                convSize(SysMgr.logSize),
                twoLine,
            )
        )

        lastAField = "{0:_^17}|{1:_^16}".format("Mem Info", "Process")
        lastBField = "%3s|%3s|%4s(%2s)" % ("Rcl", "Wst", "DRcl", "Nr")

        SysMgr.printPipe(
            "{0:_^34}|{1:_^35}|{2:_^22}|{3:_^26}|{4:_^34}|".format(
                title, "CPU Info", "SCHED Info", "BLOCK Info", lastAField
            )
        )

        SysMgr.printPipe("{0:^34}|{0:^35}|{0:^22}|{0:^26}|{0:^34}|".format(""))

        # set field name #
        if SysMgr.latEnable:
            field = "Latc"
        else:
            field = "Blck"

        SysMgr.printPipe(
            (
                "%16s(%6s/%6s)|%2s|%5s(%5s)|%5s|%6s|%3s|%5s|"
                "%5s|%5s|%5s|%4s|%5s(%3s/%4s)|%5s(%3s)|%4s(%3s/%3s/%3s)|%s|\n%s"
            )
            % (
                "Name",
                "TID",
                "PID",
                "LF",
                "Usage",
                "%",
                "Prmt",
                field,
                "Pri",
                "IRQ",
                "Yld",
                " Lose",
                "Steal",
                "Mig",
                "Read",
                "MB",
                "Cnt",
                "Write",
                "MB",
                "Sum",
                "Usr",
                "Buf",
                "Ker",
                lastBField,
                twoLine,
            )
        )

        # initialize swapper thread per core #
        for n in xrange(SysMgr.maxCore + 1):
            try:
                if SysMgr.perCoreList and n not in SysMgr.perCoreList:
                    continue

                coreId = "0[%s]" % n
                self.threadData[coreId]
            except:
                self.threadData[coreId] = dict(self.init_threadData)
                self.threadData[coreId]["comm"] = "swapper/" + str(n)
                self.threadData[coreId]["usage"] = 0

        # sort by size of I/O usage and convert read blocks to MB size #
        for key, value in sorted(
            self.threadData.items(),
            key=lambda e: e[1]["readBlock"],
            reverse=True,
        ):

            if value["readBlock"] > 0:
                value["readBlock"] = (
                    value["readBlock"] * SysMgr.blockSize
                ) >> 20
            if value["writeBlock"] > 0:
                value["writeBlock"] = (
                    value["writeBlock"] * SysMgr.blockSize
                ) >> 20
            if value["awriteBlock"] > 0:
                value["awriteBlock"] = (
                    value["awriteBlock"] * SysMgr.PAGESIZE
                ) >> 20

        # set precise flag #
        if "PRECISE" in SysMgr.environList:
            precise = True
        else:
            precise = False

        # print total information after sorting by CPU usage #
        count = 0
        SysMgr.clearPrint()
        for key, value in sorted(
            self.threadData.items(),
            key=lambda e: TaskAnalyzer.getCoreId(e[1]["comm"]),
            reverse=False,
        ):

            if not key.startswith("0["):
                # convert priority #
                try:
                    prio = long(value["pri"]) - 120
                    if prio >= -20:
                        value["pri"] = str(prio)
                    elif prio == -121:
                        value["pri"] = "D99"
                    else:
                        value["pri"] = "R%2s" % abs(prio + 21)
                except:
                    pass

                continue

            # change the name of swapper thread to CORE #
            value["comm"] = value["comm"].replace("swapper", "CORE")

            # modify idle time if this core is not woke up ever #
            if value["usage"] == 0 and value["coreSchedCnt"] == 0:
                value["usage"] = self.totalTime

            # calculate total core usage percentage #
            try:
                idle = float(value["usage"]) / float(self.totalTime)
                usagePercent = 100 - (round(idle, 7) * 100)
            except:
                usagePercent = 0

            if value["lastOff"] > 0:
                value["offTime"] += float(self.finishTime) - value["lastOff"]

            if SysMgr.powerEnable:
                if precise:
                    offTime = "%5.6f" % value["offTime"]
                else:
                    offTime = "%5.2f" % value["offTime"]
                offCnt = str(value["offCnt"])
            else:
                offTime = "-"
                offCnt = "-"

            if SysMgr.cpuEnable:
                if precise:
                    cpuTime = "%5.6f" % (self.totalTime - value["usage"])
                else:
                    cpuTime = "%5.2f" % (self.totalTime - value["usage"])

                cpuPer = "%5.1f" % usagePercent

                if SysMgr.latEnable:
                    schedVal = value["schedLatency"]
                else:
                    schedVal = value["schedBlock"]

                if precise:
                    schedLatency = "%5.6f" % schedVal
                else:
                    schedLatency = "%5.2f" % schedVal

                yieldCnt = "%5s" % convSize(value["yield"])
                preemptedCnt = "%5s" % convSize(value["preempted"])
                preemptionCnt = "%5s" % convSize(value["preemption"])
                migrateCnt = "%4s" % convSize(value["migrate"])
            else:
                cpuTime = "-"
                cpuPer = "-"
                schedLatency = "-"
                yieldCnt = "-"
                preemptedCnt = "-"
                preemptionCnt = "-"
                migrateCnt = "-"

            if SysMgr.irqEnable:
                if precise:
                    irqTime = "%5.6f" % value["irq"]
                else:
                    irqTime = "%5.2f" % value["irq"]
            else:
                irqTime = "-"

            if SysMgr.blockEnable:
                if precise:
                    ioRdWait = "%5.6f" % value["ioRdWait"]
                else:
                    ioRdWait = "%5.2f" % value["ioRdWait"]
                readBlock = "%3d" % value["readBlock"]
                readBlockCnt = "%4d" % value["readBlockCnt"]
                if precise:
                    ioWrWait = "%5.6f" % value["ioWrWait"]
                else:
                    ioWrWait = "%5.2f" % value["ioWrWait"]
                writeBlock = "%3d" % (
                    value["writeBlock"] + value["awriteBlock"]
                )
            else:
                ioRdWait = "-"
                readBlock = "-"
                readBlockCnt = "-"
                ioWrWait = "-"
                writeBlock = "-"

            if SysMgr.memEnable:
                usedMem = "%4d" % (
                    (value["nrPages"] >> 8) + (value["remainKmem"] >> 20)
                )
                userMem = "%3d" % (value["userPages"] >> 8)
                cacheMem = "%3d" % (value["cachePages"] >> 8)
                kernelMem = "%3d" % (
                    (value["kernelPages"] >> 8) + (value["remainKmem"] >> 20)
                )
                reclaimedMem = "%3d" % (value["reclaimedPages"] >> 8)
                wastedMem = "%3d" % (value["wasteKmem"] >> 20)
                if precise:
                    dreclaimedTime = "%4.6f" % value["dReclaimWait"]
                else:
                    dreclaimedTime = "%4.2f" % value["dReclaimWait"]
                dreclaimedCnt = "%2d" % value["dReclaimCnt"]
            else:
                usedMem = "-"
                userMem = "-"
                cacheMem = "-"
                kernelMem = "-"
                reclaimedMem = "-"
                wastedMem = "-"
                dreclaimedTime = "-"
                dreclaimedCnt = "-"

            lastField = "%3s|%3s|%4s(%2s)" % (
                reclaimedMem,
                wastedMem,
                dreclaimedTime,
                dreclaimedCnt,
            )

            SysMgr.addPrint(
                (
                    "%16s(%6s/%6s)|%s%s|%5s(%5s)|%5s|%6s|%3s|%5s|"
                    "%5s|%5s|%5s|%4s|%5s(%3s/%4s)|%5s(%3s)|"
                    "%4s(%3s/%3s/%3s)|%s|\n"
                )
                % (
                    value["comm"],
                    "-" * 5,
                    "-" * 5,
                    "-",
                    "-",
                    cpuTime,
                    cpuPer,
                    offTime,
                    schedLatency,
                    offCnt,
                    irqTime,
                    yieldCnt,
                    preemptedCnt,
                    preemptionCnt,
                    migrateCnt,
                    ioRdWait,
                    readBlock,
                    readBlockCnt,
                    ioWrWait,
                    writeBlock,
                    usedMem,
                    userMem,
                    cacheMem,
                    kernelMem,
                    lastField,
                )
            )
            count += 1

        SysMgr.printPipe("%s# %s: %d\n" % ("", "CPU", count))
        SysMgr.doPrint()
        SysMgr.printPipe(oneLine)

        # apply sort value automatically #
        if not SysMgr.sort:
            if SysMgr.cpuEnable:
                pass
            elif SysMgr.memEnable:
                SysMgr.sort = "m"
            elif SysMgr.blockEnable:
                SysMgr.sort = "b"

        # set sort value #
        if SysMgr.sort == "m":
            sortedThreadData = sorted(
                self.threadData.items(),
                key=lambda e: e[1]["nrPages"],
                reverse=True,
            )
        elif SysMgr.sort == "b":
            sortedThreadData = sorted(
                self.threadData.items(),
                key=lambda e: e[1]["readBlock"]
                + e[1]["writeBlock"]
                + e[1]["awriteBlock"],
                reverse=True,
            )
        else:
            # set CPU usage as default #
            sortedThreadData = sorted(
                self.threadData.items(),
                key=lambda e: e[1]["usage"],
                reverse=True,
            )

        # set total CPU variables #
        totalCpuTime = 0
        totalPrtTime = 0
        totalSchedLatency = 0
        totalYieldCnt = 0
        totalPreemptedCnt = 0
        totalPreemptionCnt = 0
        totalMigrateCnt = 0

        # set total irq variables #
        totalIrqTime = 0

        # set total I/O variables #
        totalIoRdWait = 0
        totalReadBlock = 0
        totalReadBlockCnt = 0
        totalIoWrWait = 0
        totalWriteBlock = 0

        # set total mem variables #
        totalUsedMem = 0
        totalUserMem = 0
        totalCacheMem = 0
        totalKernelMem = 0
        totalReclaimedMem = 0
        totalWastedMem = 0
        totalDreclaimedTime = 0
        totalDreclaimedCnt = 0

        # define variables for tasks #
        normCnt = 0
        newCnt = 0
        dieCnt = 0
        normThreadString = ""
        newThreadString = ""
        dieThreadString = ""

        # print thread information after sorting by time of CPU usage #
        count = 0
        SysMgr.clearPrint()
        for key, value in sortedThreadData:
            if key.startswith("0["):
                continue

            try:
                usagePercent = (
                    round(value["usage"] / float(self.totalTime), 7) * 100
                )
            except:
                usagePercent = 0

            # set break condition #
            if SysMgr.sort == "m":
                breakCond = value["nrPages"]
            elif SysMgr.sort == "b":
                breakCond = (
                    value["readBlock"]
                    + value["writeBlock"]
                    + value["awriteBlock"]
                )
            else:
                breakCond = usagePercent

            if (
                breakCond < 1
                and not SysMgr.showAll
                and SysMgr.filterGroup == []
            ):
                break

            if SysMgr.cpuEnable:
                if precise:
                    cpuTime = "%5.6f" % value["usage"]
                else:
                    cpuTime = "%5.2f" % value["usage"]

                totalCpuTime += value["usage"]

                cpuPer = "%5.1f" % usagePercent

                if SysMgr.latEnable:
                    schedVal = value["schedLatency"]
                else:
                    schedVal = value["schedBlock"]

                if precise:
                    prtTime = "%5.6f" % value["cpuWait"]
                    schedLatency = "%5.6f" % schedVal
                else:
                    prtTime = "%5.2f" % value["cpuWait"]
                    schedLatency = "%5.2f" % schedVal

                totalPrtTime += value["cpuWait"]
                totalSchedLatency += value["schedLatency"]

                pri = value["pri"]

                yieldCnt = "%5s" % convSize(value["yield"])
                totalYieldCnt += value["yield"]

                preemptedCnt = "%5s" % convSize(value["preempted"])
                totalPreemptedCnt += value["preempted"]

                preemptionCnt = "%5s" % convSize(value["preemption"])
                totalPreemptionCnt += value["preemption"]

                migrateCnt = "%4s" % convSize(value["migrate"])
                totalMigrateCnt += value["migrate"]
            else:
                cpuTime = "-"
                cpuPer = "-"
                prtTime = "-"
                schedLatency = "-"
                pri = "-"
                yieldCnt = "-"
                preemptedCnt = "-"
                preemptionCnt = "-"
                migrateCnt = "-"

                totalCpuPer = "-"
                totalCpuTime = "-"
                totalPrtTime = "-"
                totalSchedLatency = "-"
                totalYieldCnt = "-"
                totalPreemptedCnt = "-"
                totalPreemptionCnt = "-"
                totalMigrateCnt = "-"

            if SysMgr.irqEnable:
                if precise:
                    irqTime = "%5.6f" % value["irq"]
                else:
                    irqTime = "%5.2f" % value["irq"]
                totalIrqTime += value["irq"]
            else:
                irqTime = "-"
                totalIrqTime = "-"

            if SysMgr.blockEnable:
                if precise:
                    ioRdWait = "%5.6f" % value["ioRdWait"]
                else:
                    ioRdWait = "%5.2f" % value["ioRdWait"]
                totalIoRdWait += value["ioRdWait"]

                readBlock = "%3d" % value["readBlock"]
                totalReadBlock += value["readBlock"]

                readBlockCnt = "%4d" % value["readBlockCnt"]
                totalReadBlockCnt += value["readBlockCnt"]

                if precise:
                    ioWrWait = "%5.6f" % value["ioWrWait"]
                else:
                    ioWrWait = "%5.2f" % value["ioWrWait"]
                totalIoWrWait += value["ioWrWait"]

                writeBlock = "%3d" % (
                    value["writeBlock"] + value["awriteBlock"]
                )
                totalWriteBlock += value["writeBlock"] + value["awriteBlock"]
            else:
                ioRdWait = "-"
                readBlock = "-"
                readBlockCnt = "-"
                ioWrWait = "-"
                writeBlock = "-"

                totalIoRdWait = "-"
                totalReadBlock = "-"
                totalReadBlockCnt = "-"
                totalIoWrWait = "-"
                totalWriteBlock = "-"

            if SysMgr.memEnable:
                usedMem = (value["nrPages"] >> 8) + (value["remainKmem"] >> 20)
                totalUsedMem += usedMem
                usedMem = "%4d" % usedMem

                userMem = "%3d" % (value["userPages"] >> 8)
                totalUserMem += value["userPages"] >> 8

                cacheMem = "%3d" % (value["cachePages"] >> 8)
                totalCacheMem += value["cachePages"] >> 8

                kernelMem = (value["kernelPages"] >> 8) + (
                    value["remainKmem"] >> 20
                )
                totalKernelMem += kernelMem
                kernelMem = "%3d" % kernelMem

                reclaimedMem = "%3d" % (value["reclaimedPages"] >> 8)
                totalReclaimedMem += value["reclaimedPages"] >> 8

                wastedMem = "%3d" % (value["wasteKmem"] >> 20)
                totalWastedMem += value["wasteKmem"] >> 20

                if precise:
                    dreclaimedTime = "%4.6f" % value["dReclaimWait"]
                else:
                    dreclaimedTime = "%4.2f" % value["dReclaimWait"]
                totalDreclaimedTime += value["dReclaimWait"]

                dreclaimedCnt = "%2d" % value["dReclaimCnt"]
                totalDreclaimedCnt += value["dReclaimCnt"]
            else:
                usedMem = "-"
                userMem = "-"
                cacheMem = "-"
                kernelMem = "-"
                reclaimedMem = "-"
                wastedMem = "-"
                dreclaimedTime = "-"
                dreclaimedCnt = "-"

                totalUsedMem = "-"
                totalUserMem = "-"
                totalCacheMem = "-"
                totalKernelMem = "-"
                totalReclaimedMem = "-"
                totalWastedMem = "-"
                totalDreclaimedTime = "-"
                totalDreclaimedCnt = "-"

            # set last field #
            if SysMgr.savedProcComm:
                if value["tgid"] in SysMgr.savedProcComm:
                    lastField = "{0:>16}".format(
                        SysMgr.savedProcComm[value["tgid"]]
                    )[:16]
                elif key == value["tgid"]:
                    lastField = "{0:>16}".format(value["comm"])[:16]
                else:
                    lastField = "{0:>16}".format("?")
            else:
                lastField = "%3s|%3s|%4s(%2s)" % (
                    reclaimedMem,
                    wastedMem,
                    dreclaimedTime,
                    dreclaimedCnt,
                )

            if value["new"] != " ":
                newCnt += 1
                taskInfo = "%16s(%6s/%6s)" % (
                    value["comm"],
                    key,
                    value["ptid"],
                )
                newThreadString += (
                    "%s|%s%s|%5s(%5s)|%5s|%6s|%3s|%5s|"
                    "%5s|%5s|%5s|%4s|%5s(%3s/%4s)|%5s(%3s)|"
                    "%4s(%3s/%3s/%3s)|%s|\n"
                ) % (
                    taskInfo[:31],
                    value["new"],
                    value["die"],
                    cpuTime,
                    cpuPer,
                    prtTime,
                    schedLatency,
                    pri,
                    irqTime,
                    yieldCnt,
                    preemptedCnt,
                    preemptionCnt,
                    migrateCnt,
                    ioRdWait,
                    readBlock,
                    readBlockCnt,
                    ioWrWait,
                    writeBlock,
                    usedMem,
                    userMem,
                    cacheMem,
                    kernelMem,
                    lastField,
                )

            if value["die"] != " ":
                dieCnt += 1
                taskInfo = "%16s(%6s/%6s)" % (
                    value["comm"],
                    key,
                    value["ptid"],
                )
                dieThreadString += (
                    "%s|%s%s|%5s(%5s)|%5s|%6s|%3s|%5s|"
                    "%5s|%5s|%5s|%4s|%5s(%3s/%4s)|%5s(%3s)|"
                    "%4s(%3s/%3s/%3s)|%s|\n"
                ) % (
                    taskInfo[:31],
                    value["new"],
                    value["die"],
                    cpuTime,
                    cpuPer,
                    prtTime,
                    schedLatency,
                    pri,
                    irqTime,
                    yieldCnt,
                    preemptedCnt,
                    preemptionCnt,
                    migrateCnt,
                    ioRdWait,
                    readBlock,
                    readBlockCnt,
                    ioWrWait,
                    writeBlock,
                    usedMem,
                    userMem,
                    cacheMem,
                    kernelMem,
                    lastField,
                )

            normCnt += 1
            taskInfo = "%16s(%6s/%6s)" % (value["comm"], key, value["tgid"])
            normThreadString += (
                "%s|%s%s|%5s(%5s)|%5s|%6s|%3s|%5s|"
                "%5s|%5s|%5s|%4s|%5s(%3s/%4s)|%5s(%3s)|"
                "%4s(%3s/%3s/%3s)|%s|\n"
            ) % (
                taskInfo[:31],
                value["new"],
                value["die"],
                cpuTime,
                cpuPer,
                prtTime,
                schedLatency,
                pri,
                irqTime,
                yieldCnt,
                preemptedCnt,
                preemptionCnt,
                migrateCnt,
                ioRdWait,
                readBlock,
                readBlockCnt,
                ioWrWait,
                writeBlock,
                usedMem,
                userMem,
                cacheMem,
                kernelMem,
                lastField,
            )

        # build total usage string #
        try:
            totalCpuPer = "%5.1f" % (
                totalCpuTime / float(self.totalTime) * 100
            )
            if precise:
                totalCpuTime = "%5.6f" % totalCpuTime
                totalPrtTime = "%5.6f" % totalPrtTime
                totalSchedLatency = "%5.6f" % totalSchedLatency
            else:
                totalCpuTime = "%5.2f" % totalCpuTime
                totalPrtTime = "%5.2f" % totalPrtTime
                totalSchedLatency = "%5.2f" % totalSchedLatency
            totalYieldCnt = "%5s" % convSize(totalYieldCnt)
            totalPreemptedCnt = "%5s" % convSize(totalPreemptedCnt)
            totalPreemptionCnt = "%5s" % convSize(totalPreemptionCnt)
            totalMigrateCnt = "%4s" % convSize(totalMigrateCnt)
        except:
            pass

        try:
            if precise:
                totalIrqTime = "%5.6f" % totalIrqTime
            else:
                totalIrqTime = "%5.2f" % totalIrqTime
        except:
            pass

        try:
            if precise:
                totalIoRdWait = "%5.6f" % totalIoRdWait
            else:
                totalIoRdWait = "%5.2f" % totalIoRdWait
            totalReadBlock = "%3d" % totalReadBlock
            totalReadBlockCnt = "%4d" % totalReadBlockCnt
            if precise:
                totalIoWrWait = "%5.6f" % totalIoWrWait
            else:
                totalIoWrWait = "%5.2f" % totalIoWrWait
            totalWriteBlock = "%3d" % totalWriteBlock
        except:
            pass

        try:
            totalUsedMem = "%4d" % totalUsedMem
            totalUserMem = "%3d" % totalUserMem
            totalCacheMem = "%3d" % totalCacheMem
            totalKernelMem = "%3d" % totalKernelMem
            totalReclaimedMem = "%3d" % totalReclaimedMem
            totalWastedMem = "%3d" % totalWastedMem
            totalDreclaimedCnt = "%2d" % totalDreclaimedCnt
            if precise:
                totalDreclaimedTime = "%4.6f" % totalDreclaimedTime
            else:
                totalDreclaimedTime = "%4.2f" % totalDreclaimedTime
        except:
            pass

        lastField = "%3s|%3s|%4s(%2s)" % (
            totalReclaimedMem,
            totalWastedMem,
            totalDreclaimedTime,
            totalDreclaimedCnt,
        )

        # print TOTAL information #
        SysMgr.printPipe(
            (
                "%31s|%s%s|%5s(%5s)|%5s|%6s|%3s|%5s|"
                "%5s|%5s|%5s|%4s|%5s(%3s/%4s)|%5s(%3s)|%4s(%3s/%3s/%3s)|%s|"
            )
            % (
                "{0:>29}".format("[ TOTAL ]"),
                " ",
                " ",
                totalCpuTime,
                totalCpuPer,
                totalPrtTime,
                totalSchedLatency,
                "-",
                totalIrqTime,
                totalYieldCnt,
                totalPreemptedCnt,
                totalPreemptionCnt,
                totalMigrateCnt,
                totalIoRdWait,
                totalReadBlock,
                totalReadBlockCnt,
                totalIoWrWait,
                totalWriteBlock,
                totalUsedMem,
                totalUserMem,
                totalCacheMem,
                totalKernelMem,
                lastField,
            )
        )

        # print normal thread info #
        if normCnt > 0:
            SysMgr.printPipe(
                "%s# %s: %s\n%s\n%s"
                % ("", "Hot", convNum(normCnt), normThreadString, oneLine)
            )
        else:
            SysMgr.printPipe("\tNone\n%s" % oneLine)

        # print new thread info #
        if newCnt > 0:
            SysMgr.printPipe(
                "%s# %s: %s\n%s\n%s"
                % ("", "New", convNum(newCnt), newThreadString, oneLine)
            )

        # print die thread info #
        if dieCnt > 0:
            SysMgr.printPipe(
                "%s# %s: %s\n%s\n%s"
                % ("", "Die", convNum(dieCnt), dieThreadString, oneLine)
            )

        # print thread preempted information after sorting by time of CPU usage #
        for val in SysMgr.preemptGroup:
            index = SysMgr.preemptGroup.index(val)
            count = 0

            tid = SysMgr.preemptGroup[index]
            try:
                self.threadData[tid]
            except:
                SysMgr.printErr('failed to find "%s" thread' % tid)
                continue

            SysMgr.clearPrint()
            for key, value in sorted(
                self.preemptData[index][1].items(),
                key=lambda e: e[1]["usage"],
                reverse=True,
            ):

                count += 1
                stats = self.preemptData[index]

                if float(stats[4]) == 0:
                    break

                if precise:
                    SysMgr.addPrint(
                        "%16s(%6s/%6s)|%s%s|%5.6f(%5s)\n"
                        % (
                            self.threadData[key]["comm"],
                            key,
                            "0",
                            self.threadData[key]["new"],
                            self.threadData[key]["die"],
                            value["usage"],
                            "%.6f" % (value["usage"] / stats[4] * 100),
                        )
                    )
                else:
                    SysMgr.addPrint(
                        "%16s(%6s/%6s)|%s%s|%5.2f(%5s)\n"
                        % (
                            self.threadData[key]["comm"],
                            key,
                            "0",
                            self.threadData[key]["new"],
                            self.threadData[key]["die"],
                            value["usage"],
                            "%.2f" % (value["usage"] / stats[4] * 100),
                        )
                    )

            SysMgr.printPipe(
                "# %s: Target> %s(%s) / Total> %6.3f / Competitors> %d\n"
                % (
                    "PRT",
                    self.threadData[tid]["comm"],
                    tid,
                    self.preemptData[index][4],
                    count,
                )
            )

            SysMgr.doPrint()
            SysMgr.printPipe(oneLine)

        # print histo stats for runtime #
        if "runtime" in self.statData:
            runtimeStats = UtilMgr.convList2Histo(
                self.statData["runtime"], mult=1000000
            )
            UtilMgr.printHist(runtimeStats, "sched_runtime", "us")

        # print histo stats for preemption #
        if "prttime" in self.statData:
            prttimeStats = UtilMgr.convList2Histo(
                self.statData["prttime"], mult=1000000
            )
            UtilMgr.printHist(prttimeStats, "sched_preempted", "us")

        # print histo stats for latency #
        if "schedlat" in self.statData:
            latStats = UtilMgr.convList2Histo(
                self.statData["schedlat"], mult=1000000
            )
            UtilMgr.printHist(latStats, "sched_latency", "us")

        # print histo stats for block #
        if "schedblock" in self.statData:
            latStats = UtilMgr.convList2Histo(
                self.statData["schedblock"], mult=1000000
            )
            UtilMgr.printHist(latStats, "sched_block", "us")

        # prepare to draw graph #
        if not SysMgr.isRecordMode() and SysMgr.graphEnable:
            # check interval value #
            if SysMgr.intervalEnable == 0:
                SysMgr.printErr("use -i option if you want to draw graph")
                SysMgr.graphEnable = False
                return

            # get matplotlib object #
            matplotlib = SysMgr.getPkg("matplotlib", False)
            if not matplotlib:
                SysMgr.printPipWarn("matplotlib", "matplotlib")
                sys.exit(-1)
            from matplotlib.ticker import (
                MaxNLocator,
            )  # pylint: disable=import-error

            SysMgr.matplotlibVersion = float(
                ".".join(matplotlib.__version__.split(".")[:2])
            )

            # set dpi #
            matplotlib.rcParams["figure.dpi"] = SysMgr.matplotlibDpi

            # set backend #
            matplotlib.use("Agg")

            # get pylab object #
            SysMgr.importPkgItems("pylab")

            rc("legend", fontsize=5)
            rcParams.update({"font.size": 8})
        else:
            SysMgr.graphEnable = False

    def printModuleInfo(self):
        if len(self.moduleData) <= 0:
            return

        moduleTable = {}
        init_moduleData = {
            "startTime": 0.0,
            "loadCnt": 0,
            "elapsed": 0.0,
            "freeCnt": 0,
            "refCnt": 0,
            "getCnt": 0,
            "putCnt": 0,
        }

        # print module history #
        SysMgr.clearPrint()
        SysMgr.addPrint("\n[Thread Module History]\n")
        SysMgr.addPrint("%s\n" % twoLine)
        SysMgr.addPrint(
            "{3:>16} ({4:^7})|{0:^6}|{1:^12}|{2:^32}|{5:^12}|{6:^8}|\n".format(
                "Type", "Time", "Module", "Comm", "TID", "Elapsed", "RefCnt"
            )
        )
        SysMgr.addPrint("%s\n" % twoLine)

        printCnt = 0
        for val in self.moduleData:
            event = val[0]
            tid = val[1]
            time = val[2]
            module = val[3]

            current = float(time) - float(SysMgr.startTime)

            try:
                comm = self.threadData[tid]["comm"]
            except:
                continue

            moduleTable.setdefault(module, dict(init_moduleData))

            startTime = float(moduleTable[module]["startTime"])

            # module probe #
            if event == "load":
                moduleTable[module]["startTime"] = time
                moduleTable[module]["loadCnt"] += 1

                moduleTable[module]["refCnt"] = 1
                refCnt = moduleTable[module]["refCnt"]

                SysMgr.addPrint(
                    (
                        "{3:>16} ({4:>7})|{0:^6}|{1:12.6f}|"
                        "{2:^32}|{5:>12}|{6:^8}|\n"
                    ).format("LOAD", current, module, comm, tid, "", refCnt)
                )
                printCnt += 1

            # module remove #
            elif event == "free":
                if startTime > 0:
                    lifetime = "%.6f" % (float(time) - startTime)
                else:
                    lifetime = ""

                moduleTable[module]["freeCnt"] += 1
                moduleTable[module]["refCnt"] = 0
                refCnt = moduleTable[module]["refCnt"]

                SysMgr.addPrint(
                    (
                        "{3:>16} ({4:>7})|{0:^6}|{1:12.6f}|"
                        "{2:^32}|{5:>12}|{6:^8}|\n"
                    ).format(
                        "FREE", current, module, comm, tid, lifetime, refCnt
                    )
                )
                printCnt += 1

            # module refcount increase #
            elif event == "get":
                moduleTable[module]["getCnt"] += 1
                moduleTable[module]["refCnt"] = val[4]
                refCnt = moduleTable[module]["refCnt"]

                SysMgr.addPrint(
                    (
                        "{3:>16} ({4:>7})|{0:^6}|{1:12.6f}|"
                        "{2:^32}|{5:>12}|{6:^8}|\n"
                    ).format("GET", current, module, comm, tid, "", refCnt)
                )
                printCnt += 1

            # module refcount decrease #
            elif event == "put":
                moduleTable[module]["putCnt"] += 1
                moduleTable[module]["refCnt"] = val[4]
                refCnt = moduleTable[module]["refCnt"]

                if startTime > 0:
                    elapsed = float(time) - startTime
                    moduleTable[module]["elapsed"] += elapsed
                    moduleTable[module]["startTime"] = 0
                    elapsed = "%.6f" % elapsed
                else:
                    elapsed = ""

                SysMgr.addPrint(
                    (
                        "{3:>16} ({4:>7})|{0:^6}|{1:12.6f}|"
                        "{2:^32}|{5:>12}|{6:^8}|\n"
                    ).format(
                        "PUT", current, module, comm, tid, elapsed, refCnt
                    )
                )
                printCnt += 1

        if printCnt == 0:
            SysMgr.addPrint("\tNone\n%s\n" % oneLine)
        else:
            SysMgr.addPrint("%s\n" % oneLine)

        # print module info #
        SysMgr.printPipe("\n[Thread Module Info]\n%s" % twoLine)
        SysMgr.printPipe(
            "{0:^32}|{1:^10}|{2:^12}|{3:^10}|{4:^10}|{5:^10}|\n{6:1}".format(
                "Module",
                "LoadCnt",
                "LoadTime",
                "FreeCnt",
                "GetCnt",
                "PutCnt",
                twoLine,
            )
        )

        printCnt = 0
        for module, value in moduleTable.items():
            elapsed = "%.6f" % value["elapsed"]
            SysMgr.printPipe(
                "{0:^32}|{1:^10}|{2:>12}|{3:^10}|{4:^10}|{5:^10}|".format(
                    module,
                    value["loadCnt"],
                    elapsed,
                    value["freeCnt"],
                    value["getCnt"],
                    value["putCnt"],
                )
            )
            printCnt += 1

        if printCnt == 0:
            SysMgr.printPipe("\tNone\n%s" % oneLine)
        else:
            SysMgr.printPipe("%s" % oneLine)

        SysMgr.doPrint(clear=True)

    def printDepInfo(self):
        if not SysMgr.depEnable:
            return

        SysMgr.printPipe("\n[Thread Dependency Info]\n%s" % twoLine)
        SysMgr.printPipe(
            "\t%5s/%4s \t%32s(%7s) -> %32s(%7s) \t%5s\n%s"
            % ("Total", "Inter", "From", "TID", "To", "TID", "Event", twoLine)
        )
        SysMgr.printPipe("%s# %s: %d\n" % ("", "Dep", len(self.depData)))

        for icount in xrange(len(self.depData)):
            SysMgr.addPrint(self.depData[icount] + "\n")

        SysMgr.doPrint(clear=True)
        SysMgr.printPipe(oneLine)

    def printFutexInfo(self):
        SysMgr.clearPrint()

        if not self.futexData:
            return

        convNum = UtilMgr.convNum

        outputCnt = 0
        SysMgr.printPipe(
            (
                "\n[Thread Futex Lock Info] [Elapsed: %.3f] "
                "(Unit: Sec/NR) (LBlock: LOCK_PI)\n%s"
            )
            % (float(self.totalTime), twoLine)
        )
        SysMgr.printPipe(
            (
                "{0:>16}({1:>7}/{2:>7}) {3:>9} {4:>9} {5:>9} "
                "{6:>8} {7:>10} {8:>10} {9:>10} {10:>8} {11:>8} "
                "{12:>10} {13:>8} {14:>10}\n{15:1}"
            ).format(
                "Name",
                "TID",
                "PID",
                "Elapsed",
                "Process",
                "Block",
                "NrBlock",
                "CallMax",
                "Lock",
                "LockMax",
                "NrLock",
                "NrWait",
                "LBlock",
                "NrLBlock",
                "LastStat",
                twoLine,
            )
        )

        tinfo = {
            "ftxTotal": 0,
            "ftxMax": 0,
            "ftxLock": 0,
            "ftxLockMax": 0,
            "ftxLockCnt": 0,
            "ftxWaitCnt": 0,
            "ftxProcess": 0,
            "ftxBlockTotal": 0,
            "ftxLBlockTotal": 0,
            "ftxBlockCnt": 0,
            "ftxLSwitch": 0,
        }

        # print futex info of threads #
        for key, value in sorted(
            self.threadData.items(),
            key=lambda e: e[1]["ftxLockCnt"] + e[1]["ftxWaitCnt"],
            reverse=True,
        ):
            if key.startswith("0["):
                continue
            elif value["ftxTotal"] == 0:
                break

            if value["ftxEnter"] == 0:
                status = "Running"
            else:
                status = "Wait"

            pid = value["tgid"]

            # set thread info #
            ftxTotal = "%.3f" % float(value["ftxTotal"])
            ftxMax = "%.3f" % float(value["ftxMax"])
            ftxLock = "%.3f" % float(value["ftxLock"])
            ftxLockMax = "%.3f" % float(value["ftxLockMax"])
            ftxLockCall = convNum(value["ftxLockCnt"])
            ftxWaitCall = convNum(value["ftxWaitCnt"])

            # set total info #
            tinfo["ftxTotal"] += value["ftxTotal"]
            tinfo["ftxLock"] += value["ftxLock"]
            tinfo["ftxLockCnt"] += value["ftxLockCnt"]
            tinfo["ftxWaitCnt"] += value["ftxWaitCnt"]
            if tinfo["ftxMax"] == 0 or tinfo["ftxMax"] < value["ftxMax"]:
                tinfo["ftxMax"] = value["ftxMax"]
            if (
                tinfo["ftxLockMax"] == 0
                or tinfo["ftxLockMax"] < value["ftxLockMax"]
            ):
                tinfo["ftxLockMax"] = value["ftxLockMax"]

            if SysMgr.cpuEnable:
                ftxProcess = "%.3f" % float(value["ftxProcess"])
                ftxBlock = "%.3f" % float(value["ftxBlockTotal"])
                ftxLBlock = "%.3f" % float(value["ftxLBlockTotal"])
                ftxBlockCall = convNum(value["ftxBlockCnt"])
                ftxLSwitch = convNum(value["ftxLSwitch"])

                tinfo["ftxProcess"] += value["ftxProcess"]
                tinfo["ftxBlockTotal"] += value["ftxBlockTotal"]
                tinfo["ftxLBlockTotal"] += value["ftxLBlockTotal"]
                tinfo["ftxBlockCnt"] += value["ftxBlockCnt"]
                tinfo["ftxLSwitch"] += value["ftxLSwitch"]
            else:
                ftxProcess = tinfo["ftxProcess"] = "-"
                ftxBlock = tinfo["ftxBlockTotal"] = "-"
                ftxLBlock = tinfo["ftxLBlockTotal"] = "-"
                ftxBlockCall = tinfo["ftxBlockCnt"] = "-"
                ftxLSwitch = tinfo["ftxLSwitch"] = "-"

            futexInfo = (
                "{0:>16}({1:>7}/{2:>7}) {3:>9} {4:>9} {5:>9} "
                + "{6:>8} {7:>10} {8:>10} {9:>10} {10:>8} "
                + "{11:>8} {12:>10} {13:>8} {14:>10}"
            ).format(
                value["comm"],
                key,
                pid,
                ftxTotal,
                ftxProcess,
                ftxBlock,
                ftxBlockCall,
                ftxMax if value["ftxMax"] else "-",
                ftxLock if value["ftxLock"] else "-",
                ftxLockMax if value["ftxLockMax"] else "-",
                ftxLockCall if value["ftxLockCnt"] else "-",
                ftxWaitCall if value["ftxWaitCnt"] else "-",
                ftxLBlock if value["ftxLBlockTotal"] else "-",
                ftxLSwitch if value["ftxLSwitch"] else "-",
                status,
            )

            SysMgr.addPrint("%s\n%s\n" % (futexInfo, oneLine))
            outputCnt += 1

        if outputCnt == 0:
            SysMgr.printPipe("\tNone\n%s" % oneLine)
        else:
            # print total info #
            tinfo["ftxTotal"] = "%.3f" % tinfo["ftxTotal"]
            tinfo["ftxMax"] = "%.3f" % tinfo["ftxMax"]
            tinfo["ftxLock"] = "%.3f" % tinfo["ftxLock"]
            tinfo["ftxLockMax"] = "%.3f" % tinfo["ftxLockMax"]
            tinfo["ftxLockCnt"] = convNum(tinfo["ftxLockCnt"])
            tinfo["ftxWaitCnt"] = convNum(tinfo["ftxWaitCnt"])

            # convert format for total info #
            for item in ("ftxProcess", "ftxBlockTotal", "ftxLBlockTotal"):
                if tinfo[item] != "-":
                    tinfo[item] = "%.3f" % tinfo[item]
            for item in ("ftxBlockCnt", "ftxLSwitch"):
                if tinfo[item] != "-":
                    tinfo[item] = convNum(tinfo[item])

            def _convItem(name):
                try:
                    val = float(tinfo[name].replace(",", ""))
                    return tinfo[name] if val else "-"
                except SystemExit:
                    sys.exit(0)
                except:
                    return "-"

            totalFutexInfo = (
                "{0:>33} {1:>9} {2:>9} {3:>9} "
                "{4:>8} {5:>10} {6:>10} {7:>10} {8:>8} "
                "{9:>8} {10:>10} {11:>8} {12:>10}"
            ).format(
                "[ TOTAL ]",
                tinfo["ftxTotal"],
                tinfo["ftxProcess"],
                tinfo["ftxBlockTotal"],
                tinfo["ftxBlockCnt"],
                _convItem("ftxMax"),
                _convItem("ftxLock"),
                _convItem("ftxLockMax"),
                _convItem("ftxLockCnt"),
                _convItem("ftxWaitCnt"),
                _convItem("ftxLBlockTotal"),
                _convItem("ftxLSwitch"),
                "-",
            )

            SysMgr.printPipe("%s\n%s" % (totalFutexInfo, oneLine))

            # print thread info #
            SysMgr.doPrint(clear=True)

        if not SysMgr.showAll:
            return

        SysMgr.printPipe(
            "\n[Thread Futex Lock History] (Unit: Sec/NR)\n%s" % twoLine
        )
        SysMgr.printPipe(
            (
                "{0:>12} {1:>16}({2:>7}/{3:>7}) {4:>4} {5:^24} "
                "{6:^10} {7:>12} {8:>16} {9:>16} {10:>16}\n{11:1}"
            ).format(
                "Time",
                "Name",
                "Tid",
                "Pid",
                "Core",
                "Operation",
                "Type",
                "Elapsed",
                "Target",
                "Value",
                "Timer",
                twoLine,
            )
        )

        cnt = 0
        prevCnt = -1
        for icount in xrange(len(self.futexData)):
            try:
                value = self.futexData[icount]

                if value[1] == -1:
                    continue

                atime = float(value[1])
                stime = "%.6f" % (atime - float(SysMgr.startTime))

                comm = self.threadData[value[0]]["comm"]
                tid = "(%7s/%7s)" % (
                    value[0],
                    self.threadData[value[0]]["tgid"],
                )
                core = value[2]

                try:
                    if prevCnt < 0:
                        raise Exception("no previous item")

                    if self.futexData[prevCnt][2] == value[2]:
                        core = ""

                    if self.futexData[prevCnt][0] == value[0]:
                        tid = comm = "."
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

                nextCnt = icount + 1
                if (
                    icount + 1 <= len(self.futexData)
                    and self.futexData[nextCnt][0] == value[0]
                    and self.futexData[icount][4].startswith("ENT")
                    and self.futexData[nextCnt][4].endswith("RET")
                ):
                    otype = "{0:^10}".format("ALL")
                    elapsed = self.futexData[nextCnt][5]
                    self.futexData[nextCnt][1] = -1
                else:
                    otype = value[4]
                    elapsed = value[5]

                # convert error code #
                try:
                    ret = long(value[7])
                    if ret < 0:
                        try:
                            ret = "%s" % ConfigMgr.ERR_TYPE[abs(ret + 1)]
                        except:
                            pass
                except:
                    ret = value[7]

                SysMgr.printPipe(
                    (
                        "{0:>12} {1:>16}{2:>17} {3:>4} {4:<24} "
                        + "{5:>10} {6:>12} {7:>16} {8:>16} {9:>16}"
                    ).format(
                        stime,
                        comm,
                        tid,
                        core,
                        value[3],
                        otype,
                        elapsed,
                        value[6],
                        ret,
                        value[8],
                    )
                )

                prevCnt = icount
                cnt += 1
            except:
                pass

        if cnt == 0:
            SysMgr.printPipe("\tNone")
        SysMgr.printPipe(oneLine)

    def printFlockInfo(self):
        SysMgr.clearPrint()

        if not self.flockData:
            return

        outputCnt = 0
        SysMgr.printPipe(
            "\n[Thread File Lock Info] (Unit: Sec/NR)\n%s" % twoLine
        )
        SysMgr.printPipe(
            (
                "{0:>16}({1:>6})\t{2:>12}\t{3:>12}\t" "{4:>10}\t{5:>10}\n{6:1}"
            ).format(
                "Name", "TID", "Wait", "Lock", "nrTryLock", "nrLocked", twoLine
            )
        )

        for key, value in sorted(
            self.threadData.items(),
            key=lambda e: e[1]["lockWait"],
            reverse=True,
        ):

            if key.startswith("0["):
                continue
            elif (
                value["lockWait"]
                == value["lockTime"]
                == value["tryLockCnt"]
                == value["lockCnt"]
                == 0
            ):
                continue

            lockInfo = (
                "{0:>16}({1:>6})\t{2:>12}\t{3:>12}\t{4:>10}\t{5:>10}".format(
                    value["comm"],
                    key,
                    "%.3f" % float(value["lockWait"]),
                    "%.3f" % float(value["lockTime"]),
                    value["tryLockCnt"],
                    value["lockCnt"],
                )
            )
            SysMgr.printPipe("%s\n%s" % (lockInfo, oneLine))
            outputCnt += 1

        if outputCnt == 0:
            SysMgr.printPipe("\tNone\n%s" % oneLine)

        if not SysMgr.showAll:
            return

        SysMgr.printPipe(
            "\n[Thread File Lock History] (Unit: Sec/NR)\n%s" % twoLine
        )
        SysMgr.printPipe(
            (
                "{0:>16}({1:>6}) {2:>10} {3:>4} {4:>10} "
                "{5:>16} {6:>16} {7:>20}\n{8:1}"
            ).format(
                "Name",
                "TID",
                "Time",
                "Core",
                "Type",
                "Device",
                "Inode",
                "Context",
                twoLine,
            )
        )

        cnt = 0
        prevCnt = -1
        for icount in xrange(len(self.flockData)):
            try:
                if not self.flockData[icount][0] in self.threadData:
                    continue

                pos = self.flockData[icount][4].rfind("0x")
                dev = self.flockData[icount][4][:pos]
                inode = self.flockData[icount][4][pos:]
                atime = float(self.flockData[icount][1])
                time = "%.3f" % (atime - float(SysMgr.startTime))

                if (
                    prevCnt > -1
                    and self.flockData[prevCnt][0] == self.flockData[icount][0]
                ):
                    tid = comm = "."
                else:
                    comm = self.threadData[self.flockData[icount][0]]["comm"]
                    tid = "(%6s)" % self.flockData[icount][0]

                SysMgr.printPipe(
                    (
                        "{0:>16}{1:>8} {2:>10} {3:>4} {4:>10} "
                        "{5:>16} {6:>16} {7:>20}"
                    ).format(
                        comm,
                        tid,
                        time,
                        self.flockData[icount][2],
                        self.flockData[icount][3],
                        dev,
                        inode,
                        self.flockData[icount][5],
                    )
                )

                prevCnt = icount
                cnt += 1
            except:
                continue

        if cnt == 0:
            SysMgr.printPipe("\tNone")
        SysMgr.printPipe(oneLine)

    def printBinderInfo(self):
        if not self.binderServerData:
            return

        conv = UtilMgr.convNum

        # stats #
        for item in ["Server", "Client"]:
            if item == "Server":
                dataList = self.binderServerData
                opposite = "Client"
            else:
                dataList = self.binderCliData
                opposite = "Server"

            # server #
            outputCnt = 0
            SysMgr.printPipe(
                "\n[Thread Binder %s Info] [Elapsed: %.3f] (Unit: Sec/NR)\n%s"
                % (item, float(self.totalTime), twoLine)
            )

            SysMgr.printPipe(
                (
                    "{0:>42} {1:>12} {2:>12} {3:>12} {4:>12} {5:>12} "
                    "{6:>27} {7:>12}({8:>4})\n{9:1}"
                ).format(
                    item,
                    "Elapsed",
                    "Count",
                    "Min",
                    "Max",
                    "Avg",
                    "%s[CODE]" % opposite,
                    "Count",
                    "Per",
                    twoLine,
                )
            )

            for key, value in sorted(
                dataList.items(), key=lambda e: e[1]["usage"], reverse=True
            ):

                try:
                    avg = "%.6f" % (value["usage"] / value["count"])
                except:
                    avg = "-"

                # total stats #
                SysMgr.printPipe(
                    "{0:>42} {1:>12} {2:>12} {3:>12} {4:>12} {5:>12}".format(
                        key,
                        "%.6f" % value["usage"],
                        conv(value["count"]),
                        "%.6f" % value["min"],
                        "%.6f" % value["max"],
                        avg,
                    )
                )

                outputCnt += 1

                if not SysMgr.showAll or not "others" in value:
                    continue

                # opposite-side stats #
                for ckey, cvalue in sorted(
                    value["others"].items(),
                    key=lambda e: e[1]["count"],
                    reverse=True,
                ):
                    # get values #
                    totalCnt = cvalue["count"]
                    codeList = cvalue["call"]

                    try:
                        per = (totalCnt / float(value["count"])) * 100
                    except:
                        per = 0

                    SysMgr.printPipe(
                        "\n{0:>92} {1:>42} {2:>12}({3:>3}%)".format(
                            " ", ckey, conv(totalCnt), "%d" % per
                        )
                    )

                    # code stats #
                    for code, callCnt in sorted(
                        codeList.items(), key=lambda e: e[1], reverse=True
                    ):
                        codestr = "[%4s]" % code

                        try:
                            cper = (callCnt / float(totalCnt)) * 100
                        except:
                            cper = 0

                        SysMgr.printPipe(
                            "{0:>92} {1:>42} {2:>12}({3:>3}%)".format(
                                " ", codestr, conv(callCnt), "%d" % cper
                            )
                        )

                SysMgr.printPipe(oneLine)

            if outputCnt == 0:
                SysMgr.printPipe("\tNone\n%s" % oneLine)
            elif not SysMgr.showAll:
                SysMgr.printPipe(oneLine)

        if not SysMgr.showAll:
            return

        # history #
        SysMgr.printPipe(
            "\n[Thread Binder History] (Unit: Sec/NR)\n%s" % twoLine
        )
        SysMgr.printPipe(
            (
                "{0:>10} {1:^8} {7:>10} {3:^45} -> {4:^45} {2:>10} "
                "{5:>8} {6:>8}\n{8:1}"
            ).format(
                "Time",
                "Type",
                "TranID",
                "Sender",
                "Receiver",
                "Flags",
                "Code",
                "Elapsed",
                twoLine,
            )
        )

        outputCnt = 0
        for item in self.binderData:
            # get values #
            (
                stime,
                reply,
                tranid,
                sender,
                receiver,
                flags,
                code,
                diff,
                oneway,
            ) = item

            # type #
            if reply:
                ttype = "    REP"
            elif oneway:
                ttype = "REQ/ONE"
            else:
                ttype = "REQ    "

            # diff #
            if diff:
                diff = "%.6f" % diff
            else:
                diff = " "

            SysMgr.printPipe(
                (
                    "{0:>10} {1:>8} {7:>10} {3:>45} -> {4:>45} {2:>10} "
                    "{5:>8} {6:>8}"
                ).format(
                    "%.6f" % stime,
                    ttype,
                    tranid,
                    sender,
                    receiver,
                    flags,
                    code,
                    diff,
                )
            )

            outputCnt += 1

        if outputCnt == 0:
            SysMgr.printPipe("\tNone\n%s" % oneLine)
        else:
            SysMgr.printPipe(oneLine)

    def printSyscallInfo(self):
        if not self.syscallData:
            return

        convNum = UtilMgr.convNum

        outputCnt = 0
        SysMgr.printPipe(
            "\n[Thread Syscall Info] [Elapsed: %.3f] (Unit: Sec/NR)\n%s"
            % (float(self.totalTime), twoLine)
        )
        SysMgr.printPipe(
            (
                "{0:>16}({1:>7}) {2:>30}({3:>3}) {4:>12} {5:>12} "
                "{6:>12} {7:>12} {8:>12} {9:>12}\n{10:1}"
            ).format(
                "Name",
                "TID",
                "Syscall",
                "SID",
                "Elapsed",
                "Count",
                "Error",
                "Min",
                "Max",
                "Avg",
                twoLine,
            )
        )

        totalInfo = {}

        for key, value in sorted(
            self.threadData.items(),
            key=lambda e: e[1]["nrSyscall"],
            reverse=True,
        ):

            threadInfo = ""
            syscallInfo = ""

            # skip swapper #
            if key.startswith("0["):
                continue

            try:
                if not value["syscallInfo"]:
                    continue

                threadInfo = "%16s(%7s)" % (value["comm"], key)
            except:
                continue

            for sysId, val in sorted(
                value["syscallInfo"].items(),
                key=lambda e: e[1]["usage"],
                reverse=True,
            ):

                if val["count"] == 0:
                    continue

                # apply syscall filter #
                if (
                    SysMgr.syscallList
                    and long(sysId) not in SysMgr.syscallList
                ):
                    continue

                # print per-thread syscall table #
                try:
                    val["average"] = "%.6f" % (val["usage"] / val["count"])
                    syscall = ConfigMgr.sysList[int(sysId)][4:]
                    syscallInfo = (
                        "{0:1} {1:>30}({2:>3}) {3:>12} "
                        "{4:>12} {5:>12} {6:>12} {7:>12} {8:>12}\n"
                    ).format(
                        syscallInfo + (" " * len(threadInfo)),
                        syscall,
                        sysId,
                        "%.6f" % val["usage"],
                        convNum(val["count"]),
                        convNum(val["err"]),
                        "%.6f" % val["min"],
                        "%.6f" % val["max"],
                        val["average"],
                    )
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

                # add total info #
                try:
                    if not sysId in totalInfo:
                        totalInfo[sysId] = {}
                        totalInfo[sysId]["usage"] = 0
                        totalInfo[sysId]["count"] = 0
                        totalInfo[sysId]["err"] = 0
                        totalInfo[sysId]["min"] = 0
                        totalInfo[sysId]["max"] = 0
                        totalInfo[sysId]["average"] = 0

                    totalInfo[sysId]["usage"] += val["usage"]
                    totalInfo[sysId]["count"] += val["count"]
                    totalInfo[sysId]["err"] += val["err"]

                    if (
                        totalInfo[sysId]["min"] == 0
                        or totalInfo[sysId]["min"] > val["min"]
                    ):
                        totalInfo[sysId]["min"] = val["min"]

                    if (
                        totalInfo[sysId]["max"] == 0
                        or totalInfo[sysId]["max"] < val["max"]
                    ):
                        totalInfo[sysId]["max"] = val["max"]

                    totalInfo[sysId]["average"] = (
                        totalInfo[sysId]["usage"] / totalInfo[sysId]["count"]
                    )
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

            if syscallInfo != "":
                outputCnt += 1
                SysMgr.addPrint("%s\n" % threadInfo)
                SysMgr.addPrint("%s\n%s\n" % (syscallInfo, oneLine))

        if outputCnt == 0:
            SysMgr.printPipe("\tNone\n%s" % oneLine)
        else:
            totalStrInfo = "{0:>25}".format("[ TOTAL ]")
            SysMgr.printPipe(totalStrInfo)

            # print total info #
            syscallInfo = ""
            for sysId, val in sorted(
                totalInfo.items(), key=lambda e: e[1]["usage"], reverse=True
            ):
                try:
                    syscall = ConfigMgr.sysList[int(sysId)][4:]
                except:
                    continue

                syscallInfo = (
                    "{0:1} {1:>30}({2:>3}) {3:>12} "
                    "{4:>12} {5:>12} {6:>12} {7:>12} {8:>12}"
                ).format(
                    " " * len(totalStrInfo),
                    syscall,
                    sysId,
                    "%.6f" % val["usage"],
                    convNum(val["count"]),
                    convNum(val["err"]),
                    "%.6f" % val["min"],
                    "%.6f" % val["max"],
                    "%.6f" % val["average"],
                )

                SysMgr.printPipe(syscallInfo)
            SysMgr.printPipe("\n%s" % oneLine)

            # print thread info #
            SysMgr.doPrint(clear=True)

        if not SysMgr.showAll:
            return

        SysMgr.printPipe(
            "\n[Thread Syscall History] (Unit: Sec/NR)\n%s" % twoLine
        )
        SysMgr.printPipe(
            (
                "{0:>10} {1:>16}({2:>7}) {3:>4} {4:>18} {5:>3} "
                "{6:>5} {7:>10} {8:>16} {9:<1}\n{10:1}"
            ).format(
                "Time",
                "Name",
                "TID",
                "Core",
                "Syscall",
                "SID",
                "Type",
                "Elapsed",
                "Return",
                "Arguments",
                twoLine,
            )
        )

        # remove calls of unavailable threads #
        for icount in xrange(len(self.syscallData)):
            try:
                self.threadData[self.syscallData[icount][2]]
            except SystemExit:
                sys.exit(0)
            except:
                try:
                    del self.syscallData[icount]
                except SystemExit:
                    sys.exit(0)
                except:
                    break

        cnt = 0
        nrErr = 0
        prevCnt = -1
        proto = ConfigMgr.SYSCALL_PROTOTYPES
        startTime = float(SysMgr.startTime)
        for icount in xrange(len(self.syscallData)):
            try:
                prevData = self.syscallData[prevCnt]
                nowData = self.syscallData[icount]

                if nowData[1] == -1 or not nowData[2] in self.threadData:
                    continue

                if len(self.syscallData) > icount + 1:
                    nextData = self.syscallData[icount + 1]
                else:
                    nextData = None

                try:
                    syscall = ConfigMgr.sysList[int(nowData[4])]
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printWarn(
                        "failed to recognize syscall %s for number %s"
                        % (nowData[0], nowData[4]),
                        True,
                    )
                    continue

                if nowData[0] == "ENT":
                    # all #
                    if (
                        nextData
                        and nextData[0] == "RET"
                        and nowData[2] == nextData[2]
                        and nowData[4] == nextData[4]
                    ):
                        eventType = "{0:^5}".format("ALL")
                        eventTime = float(nowData[1]) - startTime
                        elapsed = "%6.6f" % (
                            float(nextData[1]) - float(nowData[1])
                        )
                        param = nowData[5]
                        ret = nextData[5]
                        nextData[1] = -1
                    else:
                        eventType = "{0:<5}".format(nowData[0])
                        eventTime = float(nowData[1]) - startTime
                        elapsed = " " * 8
                        param = nowData[5]
                        ret = " "

                    # trim real arguments #
                    try:
                        call = syscall[4:]
                        nrArgs = len(proto[call][1])
                        assert nrArgs > 0

                        paramlist = param[1:-1].split(",")[:nrArgs]

                        # convert values #
                        for idx, args in enumerate(proto[call][1]):
                            val = paramlist[idx]

                            # check type #
                            if "*" in args[0]:
                                paramlist[idx] = "0x%s" % val.strip()
                                continue
                            if (
                                not "int" in args[0]
                                and not "short" in args[0]
                                and not "long" in args[0]
                            ):
                                paramlist[idx] = "0x%s" % val.strip()
                                continue

                            # type casting #
                            if "unsigned" in args[0]:
                                paramlist[idx] = str(long(val, 16))
                                continue

                            val = long(val, 16)
                            if "short" in args[0]:
                                paramlist[idx] = -(val & 0x8000) | (
                                    val & 0x7FFF
                                )
                            elif "int" in args[0]:
                                paramlist[idx] = -(val & 0x80000000) | (
                                    val & 0x7FFFFFFF
                                )

                        param = "(%s)" % ", ".join(list(map(str, paramlist)))
                    except SystemExit:
                        sys.exit(0)
                    except AssertionError:
                        param = " "
                    except:
                        SysMgr.printWarn(
                            "failed to analyze syscall info", reason=True
                        )
                        param = " "
                        nrErr += 1

                elif nowData[0] == "RET":
                    eventType = nowData[0]
                    eventTime = float(nowData[1]) - startTime
                    param = " "
                    ret = nowData[5]

                    try:
                        elapsed = "%6.6f" % nowData[6]
                    except SystemExit:
                        sys.exit(0)
                    except:
                        elapsed = " " * 8
                        nrErr += 1

                try:
                    # convert error code #
                    nrRet = long(ret)
                    if nrRet < 0:
                        ret = ConfigMgr.ERR_TYPE[abs(nrRet) - 1]
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

                if prevCnt > -1 and prevData[2] == nowData[2]:
                    tid = comm = "."
                else:
                    comm = self.threadData[nowData[2]]["comm"]
                    tid = "(%7s)" % nowData[2]

                if prevCnt > -1 and prevData[3] == nowData[3]:
                    core = ""
                else:
                    core = nowData[3]

                SysMgr.printPipe(
                    (
                        "{0:>10} {1:>16}{2:>9} {3:>4} {4:>18} {5:>3} "
                        "{6:>5} {7:>10} {8:>16} {9:<1}"
                    ).format(
                        "%.6f" % eventTime,
                        comm,
                        tid,
                        core,
                        syscall[4:],
                        nowData[4],
                        eventType,
                        elapsed,
                        ret,
                        param,
                    )
                )

                prevCnt = icount
                cnt += 1
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("failed to analyze syscall info", True)

        if cnt == 0:
            SysMgr.printPipe("\tNone")
        SysMgr.printPipe(oneLine)

        # print total error #
        if nrErr:
            SysMgr.printWarn(
                "failed to parse a total of %s syscalls" % convNum(nrErr), True
            )

    def printLMKInfo(self):
        if not self.lmkData:
            return

        SysMgr.printPipe("\n[Thread LMK Info] (Unit: KB)\n%s" % twoLine)
        SysMgr.printPipe(
            "%10s %16s %10s %10s %10s %10s\n%s"
            % ("Time", "Name", "TID", "free", "file", "minfree", twoLine)
        )

        startTime = float(SysMgr.startTime)

        cnt = 0
        for msg in self.lmkData:
            try:
                SysMgr.printPipe(
                    "%10.3f %16s %10s %10s %10s %10s"
                    % (
                        round(float(msg[0]) - startTime, 7),
                        msg[1],
                        msg[2],
                        msg[3],
                        msg[4],
                        msg[5],
                    )
                )
                cnt += 1
            except:
                continue

        if cnt == 0:
            SysMgr.printPipe("\tNone")
        SysMgr.printPipe(twoLine)

    def printConsoleInfo(self):
        if not self.consoleData or not SysMgr.showAll:
            return

        SysMgr.printPipe("\n[Thread Message Info]\n%s" % twoLine)
        SysMgr.printPipe(
            "%16s %7s %4s %10s %30s\n%s"
            % ("Name", "TID", "Core", "Time", "Console message", twoLine)
        )

        startTime = float(SysMgr.startTime)

        cnt = 0
        for msg in self.consoleData:
            try:
                SysMgr.printPipe(
                    "%16s %7s %4s %10.3f %s"
                    % (
                        self.threadData[msg[0]]["comm"],
                        msg[0],
                        msg[1],
                        round(float(msg[2]) - startTime, 7),
                        msg[3],
                    )
                )
                cnt += 1
            except:
                continue

        if cnt == 0:
            SysMgr.printPipe("\tNone")
        SysMgr.printPipe(twoLine)

    def printPageInfo(self):
        # check pages #
        if not self.allocPageData:
            return

        orderTable = list(sorted(self.allocPageData))
        orders = " ".join(
            ["{0:>5}".format(UtilMgr.convNum(order)) for order in orderTable]
        )
        SysMgr.printPipe("\n[Thread Page Info]\n%s" % twoLine)
        SysMgr.printPipe(
            "{0:^25} {1:>1}\n{2:1}".format("Thread / Order", orders, twoLine)
        )

        # print total pages #
        totalInfo = "{0:^25} ".format("TOTAL")
        for order in orderTable:
            totalInfo += "{0:>5} ".format(
                UtilMgr.convNum(self.allocPageData[order])
            )
        SysMgr.printPipe(totalInfo)
        SysMgr.printPipe(oneLine)

        # print task pages #
        for tid, value in sorted(
            self.threadData.items(),
            key=lambda e: e[1]["nrAllocPages"],
            reverse=True,
        ):
            if tid[0] == "0":
                continue
            if not "orderPages" in value:
                continue

            comm = self.threadData[tid]["comm"]
            taskInfo = "{0:>25} ".format("%s(%s)" % (comm, tid))
            for order in orderTable:
                if order in value["orderPages"]:
                    addval = UtilMgr.convNum(value["orderPages"][order])
                else:
                    addval = " "
                taskInfo += "{0:>5} ".format(addval)
            SysMgr.printPipe(taskInfo)

        SysMgr.printPipe(oneLine)

    def printBlockInfo(self):
        def _printBlkUsage(cid, data, opt, tcnt):
            convSize = UtilMgr.convSize2Unit
            convNum = UtilMgr.convNum

            for num, val in sorted(
                data.items(), key=lambda e: e[1], reverse=True
            ):
                if tcnt == 0:
                    pass
                else:
                    cid = " "

                try:
                    mountInfo = SysMgr.savedMountTree
                    fs = mountInfo[num]["filesystem"]
                    mountdata = mountInfo[num]["mount"]
                    if mountdata == "-":
                        dev = mountInfo[num]["dev"]
                    else:
                        dev = mountdata
                except SystemExit:
                    sys.exit(0)
                except:
                    dev = "?"
                    fs = "?"

                try:
                    seqPer = round((val[3] / float(val[0])) * 100, 1)
                except SystemExit:
                    sys.exit(0)
                except:
                    seqPer = "?"

                size = convSize(val[0])
                seqSize = convSize(val[3])
                seqString = "%s(%5.1f)" % (seqSize, seqPer)

                if tcnt > 0:
                    SysMgr.printPipe()

                SysMgr.printPipe(
                    (
                        "{0:>25} {1:>5} {2:>8} {3:>20} "
                        "{4:>25} {5:^12} {6:1}"
                    ).format(cid, opt, num, size, seqString, fs, dev)
                )

                opt = ""

                # print per-operation size statistics #
                for optSize, cnt in sorted(val[5].items()):
                    start = convSize(optSize, True)
                    end = convSize((optSize << 1) - 1024, True)
                    SysMgr.printPipe(
                        (
                            "{0:^25} {0:^8} {0:^5} {1:>20} "
                            "{2:>25} {0:^12} {0:<20}"
                        ).format(
                            "", "[%7s - %7s]" % (start, end), convNum(cnt)
                        )
                    )

                tcnt += 1

            return tcnt

        # check block option #
        if not SysMgr.blockEnable:
            return

        SysMgr.printPipe("\n[Thread Block Info] (Unit: NR)\n%s" % twoLine)
        SysMgr.printPipe(
            "{0:^25} {1:>5} {2:>8} {3:>20} {4:>25} {5:^12} {6:^20}".format(
                "ID",
                "OPT",
                "NrDev",
                "TOTAL",
                "SEQUENTIAL(    %)",
                "FS",
                "PATH",
            )
        )
        SysMgr.printPipe(
            (
                "{0:^25} {1:>5} {2:>8} {3:>20} {4:>25} "
                "{5:^12} {6:^20}\n{7:1}"
            ).format("", "", "", "[ACCESS]", "COUNT", "", "", twoLine)
        )

        tcnt = 0
        totalStr = "{0:^25}".format("TOTAL")

        # total read #
        if self.blockTable[0]:
            tcnt = _printBlkUsage(totalStr, self.blockTable[0], "READ", tcnt)

        # total write #
        if self.blockTable[1]:
            tcnt = _printBlkUsage(totalStr, self.blockTable[1], "WRITE", tcnt)

        if tcnt > 0:
            SysMgr.printPipe(oneLine)
        else:
            SysMgr.printPipe("\tNone")
            SysMgr.printPipe(oneLine)

        # sort threads by read size #
        for tid, data in sorted(
            self.blockTable[2].items(), key=lambda e: e[1][2], reverse=True
        ):
            tcnt = 0

            # task info #
            if tid in self.threadData:
                comm = self.threadData[tid]["comm"][:16]
            else:
                comm = "??"
            cid = "%s(%s)" % (comm, tid)

            # thread read #
            if data[0]:
                tcnt = _printBlkUsage(cid, data[0], "READ", tcnt)

            # thread write #
            if data[1]:
                tcnt = _printBlkUsage(cid, data[1], "WRITE", tcnt)

            if tcnt > 0:
                SysMgr.printPipe(oneLine)

    def printOpenInfo(self):
        if not self.openData:
            return

        # print menu #
        SysMgr.printPipe("\n[Thread Open History] (Unit: NR)\n%s" % twoLine)
        SysMgr.printPipe(
            "{0:^10} {1:>25} {2:>6} {3:>6} {4:>1}\n{5:1}".format(
                "Time", "Task(Comm)", "Flags", "Mode", "Name", twoLine
            )
        )

        # print history #
        for item in self.openData:
            atime, tid, path, flags, mode = item
            if not tid in self.threadData:
                continue

            comm = self.threadData[tid]["comm"]
            taskInfo = "%s(%s)" % (comm, tid)

            SysMgr.printPipe(
                "{0:>10.6f} {1:>25} {2:>6} {3:>6} {4:>1}".format(
                    atime, taskInfo, flags, mode, path
                )
            )

        SysMgr.printPipe(twoLine)

    def printFsInfo(self):
        # get readahead items #
        (
            raPath,
            raMin,
            raAllowList,
            raDenyList,
            raAddList,
        ) = FileAnalyzer.getReadaheadItems()

        # check fs data #
        if raAddList:
            pass
        elif not self.fsTable or not self.fsTable[0]:
            if raPath:
                SysMgr.printWarn("no filesystem data for readahead list", True)
            return

        # print menu #
        SysMgr.printPipe("\n[Thread FS Info] (Unit: NR)\n%s" % twoLine)
        SysMgr.printPipe(
            (
                "{0:^25} {1:>7} {2:>8} {3:>12} {4:>12} "
                "{5:>12} {6:<75}\n{7:1}"
            ).format(
                "ID", "OPT", "NrDev", "INODE", "Size", "FS", "PATH", twoLine
            )
        )

        convSize = UtilMgr.convSize2Unit

        # merge target inode list #
        inodeList = {}
        if self.fsTable[0]:
            for value in self.fsTable[0].values():
                for dev, inodes in value.items():
                    if dev in inodeList:
                        inodeList[dev].update(inodes)
                    else:
                        inodeList[dev] = inodes

        # make target inode filter #
        fileInfo = {}
        inodeInfo = {}
        inodeCache = {}
        inodeFilter = []
        mountInfo = SysMgr.savedMountTree
        for did in list(inodeList):
            inodeFilter += list(inodeList[did])
        inodeFilter = list(set(inodeFilter))

        # get target inode info #
        if inodeFilter and "CONVINODE" in SysMgr.environList:
            # get scan dir #
            if not "SET" in SysMgr.environList["CONVINODE"]:
                targetDir = os.path.realpath(
                    SysMgr.environList["CONVINODE"][0]
                )
                # check dir #
                if not os.path.isdir(targetDir):
                    SysMgr.printErr(
                        "wrong dir path '%s' for inode scan" % targetDir
                    )
                    sys.exit(-1)
            else:
                targetDir = "/"

            SysMgr.printStat(
                r"start traversing inodes from '%s'..." % targetDir
            )

            # get inode info #
            inodeInfo = UtilMgr.getInodes(
                targetDir, inodeFilter=inodeFilter, fileAttr=fileInfo
            )

        # TOTAL #
        idstr = "TOTAL"
        for op, data in sorted(
            self.fsTable[0].items(), key=lambda e: str(e[1]), reverse=True
        ):
            opSize = 0
            devStr = ""

            for did, item in sorted(data.items()):
                try:
                    fs = mountInfo[did]["filesystem"]
                    mountdata = mountInfo[did]["mount"]
                    if mountdata == "-":
                        dev = mountInfo[did]["dev"]
                    else:
                        dev = mountdata
                except SystemExit:
                    sys.exit(0)
                except:
                    dev = "?"
                    fs = "?"

                totalSize = 0
                inodeStr = ""

                for inode, cnt in sorted(
                    item.items(), key=lambda e: e[1], reverse=True
                ):

                    # convert page to size #
                    realSize = cnt << 12
                    totalSize += realSize
                    size = convSize(realSize)

                    # convert inode to path #
                    """
                    use a below command to convert inode to path
                    # debugfs -R 'ncheck INODE' DEVNODE_PATH
                    """
                    # set file name #
                    if did in inodeInfo and inode in inodeInfo[did]:
                        path = inodeInfo[did][inode]
                        if path in fileInfo:
                            fsize = convSize(fileInfo[path].st_size)
                            path = "%s[%s]" % (path, fsize)
                    # search candidate files for incorrect device ID #
                    else:
                        path = " "
                        mdid = "%s:" % did.split(":")[0]
                        pathList = []
                        for devid in sorted(list(inodeInfo)):
                            if not inode in inodeInfo[devid]:
                                continue
                            cpath = inodeInfo[devid][inode]
                            if cpath in fileInfo:
                                fsize = convSize(fileInfo[cpath].st_size)
                                cpath = "%s[%s]" % (cpath, fsize)
                            pathList.append(cpath)
                        if pathList:
                            path = " | ".join(pathList)

                    # cache inode #
                    cacheId = "%s#%s" % (did, inode)
                    inodeCache[cacheId] = path

                    # build final string #
                    inodeStr += (
                        "{0:^25} {1:>7} {2:>8} {3:>12} {4:>12} "
                        "{5:>12} {6:<1}\n"
                    ).format(" ", " ", " ", inode, size, " ", path)

                opSize += totalSize

                devStr += (
                    "{0:^25} {1:>7} {2:>8} {3:>12} {4:>12} " "{5:>12} {6:<1}\n"
                ).format("", "", did, "", convSize(totalSize), fs, dev)

                devStr += inodeStr

            SysMgr.printPipe(
                "{0:^25} {1:>7} {2:>8} {3:>12} {4:>12} ".format(
                    idstr, op, " ", " ", convSize(opSize)
                )
            )
            SysMgr.printPipe(devStr)
            idstr = ""

        if not self.fsTable or not self.fsTable[0]:
            SysMgr.printPipe("\tNone\n")
        SysMgr.printPipe(oneLine)

        # THREAD #
        previnfo = ""
        for tid, size in sorted(
            self.fsTable[2].items(), key=lambda e: e[1], reverse=True
        ):
            # check thread data #
            if not tid in self.fsTable[1]:
                continue

            # define thread info #
            if tid in self.threadData:
                tinfo = "%s(%s)" % (self.threadData[tid]["comm"][:16], tid)
            else:
                tinfo = "??(%s)" % (tid)

            for op, data in sorted(
                self.fsTable[1][tid].items(),
                key=lambda e: str(e[1]),
                reverse=True,
            ):
                opSize = 0
                devStr = ""

                for did, item in sorted(data.items()):
                    try:
                        fs = mountInfo[did]["filesystem"]
                        mountdata = mountInfo[did]["mount"]
                        if mountdata == "-":
                            dev = mountInfo[did]["dev"]
                        else:
                            dev = mountdata
                    except SystemExit:
                        sys.exit(0)
                    except:
                        dev = "?"
                        fs = "?"

                    totalSize = 0
                    inodeStr = ""

                    for inode, cnt in sorted(
                        item.items(), key=lambda e: e[1], reverse=True
                    ):

                        # convert page to size #
                        realSize = cnt << 12
                        totalSize += realSize
                        size = convSize(realSize)

                        # get file name from inode cache #
                        cacheId = "%s#%s" % (did, inode)
                        path = inodeCache[cacheId]

                        # build final string #
                        inodeStr += (
                            "{0:^25} {1:>7} {2:>8} {3:>12} {4:>12} "
                            "{5:>12} {6:<1}\n"
                        ).format(" ", " ", " ", inode, size, " ", path)

                    opSize += totalSize

                    devStr += (
                        "{0:>25} {1:>7} {2:>8} {3:>12} {4:>12} "
                        "{5:>12} {6:<1}\n"
                    ).format("", "", did, "", convSize(totalSize), fs, dev)

                    devStr += inodeStr

                # update previous thread info #
                if previnfo == tinfo:
                    tinfo = ""
                previnfo = tinfo

                SysMgr.printPipe(
                    "{0:>25} {1:>7} {2:>8} {3:>12} {4:>12} ".format(
                        tinfo, op, " ", " ", convSize(opSize)
                    )
                )
                SysMgr.printPipe(devStr)
            SysMgr.printPipe(oneLine)

        # check return condition #
        if raPath and self.fsData[0]:
            pass
        elif raAddList:
            pass
        elif not SysMgr.showAll:
            return
        elif not self.fsData[0] and not self.fsData[1]:
            return

        # define readahead list #
        pathConvList = {}
        readaheadList = []

        # print menu #
        SysMgr.printPipe(
            "\n[Thread FS History] (Type: Read) (Unit: Byte)\n%s" % twoLine
        )
        SysMgr.printPipe(
            (
                "{0:>8} {1:>25} {2:>7} {3:>10} {4:>16} "
                "{5:>12} {6:<1}\n{7:1}"
            ).format(
                "Time",
                "Task",
                "Dev",
                "Inode",
                "Offset",
                "Size",
                "Path",
                twoLine,
            )
        )

        skipFiles = {}
        for item in self.fsData[0]:
            tid, atime, dev, inode, offset, size = item

            # set task info #
            if not tid in self.threadData:
                continue
            comm = self.threadData[tid]["comm"]
            taskInfo = "%s(%s)" % (comm, tid)

            # get file path #
            cacheId = "%s#%s" % (dev, inode)
            if cacheId in inodeCache:
                path = inodeCache[cacheId]
            else:
                path = ""

            SysMgr.printPipe(
                "{0:>8} {1:>25} {2:>7} {3:>10} {4:>16} {5:>12} {6:<1}".format(
                    atime, taskInfo, dev, inode, offset, size, path
                )
            )

            # check readahead list #
            if raPath and path.strip():
                if path in pathConvList:
                    path, idx = pathConvList[path]
                # skip implicit files #
                elif "|" in path:
                    continue
                else:
                    origPath = path
                    pathConvList[origPath] = [
                        path[: path.rfind("[")],
                        len(pathConvList),
                    ]
                    path, idx = pathConvList[origPath]

                # check allow list #
                if raAllowList and not UtilMgr.isValidStr(path, raAllowList):
                    skip = True
                # check deny list #
                elif raDenyList and UtilMgr.isValidStr(path, raDenyList):
                    skip = True
                else:
                    skip = False

                # check skip condition #
                if skip:
                    skipFiles.setdefault(path, None)
                    continue

                # add to readahead list #
                readaheadList.append([idx, offset, size])

        # print no item result #
        if not self.fsData[0]:
            SysMgr.printPipe("\tNone\n")
        SysMgr.printPipe(oneLine)

        if not raPath:
            return

        # print skip files #
        for path in sorted(list(skipFiles)):
            SysMgr.printWarn("skipped adding '%s' to readahead list" % path)

        # make readahead list file #
        readaheadList, raSummary = FileAnalyzer.makeReadaheadFile(
            raPath, readaheadList, pathConvList, raMin, raAddList
        )

        # print readahead list info #
        SysMgr.printPipe(
            FileAnalyzer.getReadaheadListStr(readaheadList, raSummary)
        )

    def printEventIntervalInfo(self):
        # timeline #
        timeLine = ""
        titleLine = "%16s(%7s/%7s):" % ("Name", "TID", "PID")
        maxLineLen = SysMgr.lineLength
        timeLineLen = titleLineLen = len(titleLine)
        intervalEnable = SysMgr.intervalEnable

        # custom event usage on timeline #
        SysMgr.clearPrint()
        if SysMgr.customEventList:
            for idx, val in sorted(
                self.customEventInfo.items(),
                key=lambda e: e[1]["count"],
                reverse=True,
            ):

                for key, value in sorted(
                    self.customInfo.items(),
                    key=lambda e: 0 if not idx in e[1] else e[1][idx]["count"],
                    reverse=True,
                ):
                    timeLine = ""
                    timeLineLen = titleLineLen
                    lval = long(float(self.totalTime) / intervalEnable) + 1
                    for icount in xrange(lval):
                        newFlag = " "
                        dieFlag = " "

                        if timeLineLen + 4 > maxLineLen:
                            timeLine += "\n" + (" " * (titleLineLen + 1))
                            timeLineLen = titleLineLen + 4
                        else:
                            timeLineLen += 4

                        try:
                            self.intData[icount][key]["customEvent"]
                        except:
                            timeLine += "%3d " % 0
                            continue

                        nowVal = self.intData[icount][key]

                        try:
                            prevVal = self.intData[icount - 1][key]
                        except:
                            prevVal = nowVal

                        if icount > 0:
                            try:
                                if nowVal["new"] != prevVal["new"]:
                                    newFlag = nowVal["new"]
                            except:
                                newFlag = nowVal["new"]
                            try:
                                if nowVal["die"] != prevVal["die"]:
                                    dieFlag = nowVal["die"]
                            except:
                                dieFlag = nowVal["die"]
                        else:
                            newFlag = nowVal["new"]
                            dieFlag = nowVal["die"]

                        cnt = str(nowVal["customEvent"][idx]["count"])

                        timeLine += "%4s" % (newFlag + cnt + dieFlag)

                    if (
                        idx not in value or value[idx]["count"] == 0
                    ) and not SysMgr.showAll:
                        break

                    SysMgr.addPrint(
                        "%16s(%7s/%7s): "
                        % (
                            self.threadData[key]["comm"],
                            key,
                            self.threadData[key]["tgid"],
                        )
                        + timeLine
                        + "\n"
                    )

                SysMgr.printPipe("%s# %s\n" % ("", "%s(Cnt)" % idx))
                SysMgr.doPrint(clear=True)
                SysMgr.printPipe(oneLine)

        # user event usage on timeline #
        SysMgr.clearPrint()
        if SysMgr.userEventList:
            for idx, val in sorted(
                self.userEventInfo.items(),
                key=lambda e: e[1]["count"],
                reverse=True,
            ):

                for key, value in sorted(
                    self.userInfo.items(),
                    key=lambda e: 0 if not idx in e[1] else e[1][idx]["usage"],
                    reverse=True,
                ):
                    timeLine = ""
                    timeLineLen = titleLineLen
                    lval = long(float(self.totalTime) / intervalEnable) + 1
                    for icount in xrange(lval):
                        newFlag = " "
                        dieFlag = " "

                        if timeLineLen + 4 > maxLineLen:
                            timeLine += "\n" + (" " * (titleLineLen + 1))
                            timeLineLen = titleLineLen + 4
                        else:
                            timeLineLen += 4

                        try:
                            self.intData[icount][key]["userEvent"]
                        except:
                            timeLine += "%3d " % 0
                            continue

                        nowVal = self.intData[icount][key]

                        try:
                            prevVal = self.intData[icount - 1][key]
                        except:
                            prevVal = nowVal

                        if icount > 0:
                            try:
                                if nowVal["new"] != prevVal["new"]:
                                    newFlag = nowVal["new"]
                            except:
                                newFlag = nowVal["new"]
                            try:
                                if nowVal["die"] != prevVal["die"]:
                                    dieFlag = nowVal["die"]
                            except:
                                dieFlag = nowVal["die"]
                        else:
                            newFlag = nowVal["new"]
                            dieFlag = nowVal["die"]

                        res = str(nowVal["userEvent"][idx]["count"])

                        """
                        res = str(nowVal['userEvent'][idx]['usage']) / \
                            SysMgr.intervalEnable * 100
                        """

                        timeLine += "%4s" % (newFlag + res + dieFlag)

                    if (
                        idx not in value or value[idx]["count"] == 0
                    ) and not SysMgr.showAll:
                        break

                    SysMgr.addPrint(
                        "%16s(%7s/%7s): "
                        % (
                            self.threadData[key]["comm"],
                            key,
                            self.threadData[key]["tgid"],
                        )
                        + timeLine
                        + "\n"
                    )

                SysMgr.printPipe("%s# %s\n" % ("", "%s(Cnt)" % idx))
                SysMgr.doPrint(clear=True)
                SysMgr.printPipe(oneLine)

        # kernel event usage on timeline #
        SysMgr.clearPrint()
        if SysMgr.kernelEventList:
            for idx, val in sorted(
                self.kernelEventInfo.items(),
                key=lambda e: e[1]["count"],
                reverse=True,
            ):

                for key, value in sorted(
                    self.kernelInfo.items(),
                    key=lambda e: 0 if not idx in e[1] else e[1][idx]["usage"],
                    reverse=True,
                ):
                    timeLine = ""
                    timeLineLen = titleLineLen
                    lval = long(float(self.totalTime) / intervalEnable) + 1
                    for icount in xrange(lval):
                        newFlag = " "
                        dieFlag = " "

                        if timeLineLen + 4 > maxLineLen:
                            timeLine += "\n" + (" " * (titleLineLen + 1))
                            timeLineLen = titleLineLen + 4
                        else:
                            timeLineLen += 4

                        try:
                            self.intData[icount][key]["kernelEvent"]
                        except:
                            timeLine += "%3d " % 0
                            continue

                        nowVal = self.intData[icount][key]

                        try:
                            prevVal = self.intData[icount - 1][key]
                        except:
                            prevVal = nowVal

                        if icount > 0:
                            try:
                                if nowVal["new"] != prevVal["new"]:
                                    newFlag = nowVal["new"]
                            except:
                                newFlag = nowVal["new"]
                            try:
                                if nowVal["die"] != prevVal["die"]:
                                    dieFlag = nowVal["die"]
                            except:
                                dieFlag = nowVal["die"]
                        else:
                            newFlag = nowVal["new"]
                            dieFlag = nowVal["die"]

                        res = str(nowVal["kernelEvent"][idx]["count"])

                        """
                        res = str(nowVal['kernelEvent'][idx]['usage']) / \
                            SysMgr.intervalEnable * 100
                        """

                        timeLine += "%4s" % (newFlag + res + dieFlag)

                    if (
                        idx not in value or value[idx]["count"] == 0
                    ) and not SysMgr.showAll:
                        break

                    SysMgr.addPrint(
                        "%16s(%7s/%7s): "
                        % (
                            self.threadData[key]["comm"],
                            key,
                            self.threadData[key]["tgid"],
                        )
                        + timeLine
                        + "\n"
                    )

                SysMgr.printPipe("%s# %s\n" % ("", "%s(Cnt)" % idx))
                SysMgr.doPrint(clear=True)
                SysMgr.printPipe(oneLine)

    def printIntervalInfo(self):
        # pylint: disable=undefined-variable

        if SysMgr.intervalEnable <= 0 or not (
            SysMgr.cpuEnable or SysMgr.memEnable or SysMgr.blockEnable
        ):
            return

        # print title #
        intervalEnable = SysMgr.intervalEnable
        SysMgr.printPipe(
            "\n[Thread Interval Info] [Start: %s] (Unit: %s Sec)\n%s"
            % (round(float(SysMgr.startTime), 7), intervalEnable, twoLine)
        )

        # graph list #
        cpuUsageList = []
        cpuThrLabelList = []
        cpuThrUsageList = []
        ioLabelList = []
        ioUsageList = []

        # timeline #
        timeLine = ""
        titleLine = "%16s(%7s/%7s):" % ("Name", "TID", "PID")
        maxLineLen = SysMgr.lineLength
        timeLineLen = titleLineLen = len(titleLine)
        startTime = float(SysMgr.startTime)
        lval = long(float(self.totalTime) / intervalEnable) + 2
        for icount in xrange(1, lval):
            checkEvent = " "
            cnt = icount - 1

            # check suspend event #
            for val in self.suspendData:
                if (
                    startTime + cnt * intervalEnable
                    < float(val[0])
                    < startTime + ((cnt + 1) * intervalEnable)
                ):
                    if val[1] == "S":
                        checkEvent = "!"
                    elif val[1] == "F":
                        checkEvent = "^"
                    else:
                        checkEvent = ">"

            # check mark event #
            for val in self.markData:
                if (
                    startTime + cnt * intervalEnable
                    < float(val)
                    < startTime + ((cnt + 1) * intervalEnable)
                ):
                    checkEvent = "v"

            if timeLineLen + 4 > maxLineLen:
                timeLine += "\n" + (" " * (titleLineLen + 1))
                timeLineLen = titleLineLen + 4
            else:
                timeLineLen += 4

            # print timeline #
            if icount * intervalEnable <= float(self.totalTime):
                timeLine += "%s%2d " % (checkEvent, icount * intervalEnable)
            else:
                timeLine += "%s%.2f " % (checkEvent, self.totalTime)

        SysMgr.printPipe("%s %s\n%s" % (titleLine, timeLine, twoLine))
        SysMgr.clearPrint()

        # total CPU usage on timeline #
        cpuStr = ""
        lval = long(float(self.totalTime) / intervalEnable) + 1
        cpuAvgUsage = [0] * lval
        cpuCnt = 0
        for key, value in sorted(
            self.threadData.items(),
            key=lambda e: TaskAnalyzer.getCoreId(e[1]["comm"]),
            reverse=False,
        ):

            if not SysMgr.cpuEnable:
                break
            elif not key.startswith("0["):
                continue

            cpuCnt += 1

            timeLine = ""
            timeLineLen = titleLineLen
            for icount in xrange(lval):
                try:
                    # revise core usage in DVFS system #
                    if self.threadData[key]["coreSchedCnt"] == 0 and (
                        self.threadData[key]["offCnt"] > 0
                        or not core in self.lastTidPerCore
                        or self.lastTidPerCore[core] == 0
                    ):
                        raise Exception("core off")
                    else:
                        per = 100 - self.intData[icount][key]["cpuPer"]
                        timeLine += "%3d " % per
                        cpuAvgUsage[icount] += per
                except SystemExit:
                    sys.exit(0)
                except:
                    timeLine += "%3s " % "0"

                if timeLineLen + 4 >= maxLineLen:
                    timeLine += "\n" + (" " * (titleLineLen + 1))
                    timeLineLen = titleLineLen + 4
                else:
                    timeLineLen += 4

            cpuStr += (
                "%16s(%7s/%7s): " % (value["comm"][:16], "-", "-")
                + timeLine
                + "\n"
            )

            # make CPU usage list for graph #
            if SysMgr.graphEnable and SysMgr.cpuEnable:
                timeLine = timeLine.replace("N", "")
                timeLine = timeLine.replace("D", "")
                timeLine = timeLine.replace("F", "")
                timeLineData = [int(n) for n in timeLine.split()]
                cpuUsageList.append(timeLineData)

        # average CPU usage on timeline #
        if SysMgr.cpuEnable:
            timeLine = ""
            timeLineLen = titleLineLen
            for icount, per in enumerate(cpuAvgUsage):
                try:
                    timeLine += "%3d " % (per / cpuCnt)
                except:
                    timeLine += "%3s " % "0"

                if timeLineLen + 4 >= maxLineLen:
                    timeLine += "\n" + (" " * (titleLineLen + 1))
                    timeLineLen = titleLineLen + 4
                else:
                    timeLineLen += 4

            # print final CPU usage #
            cpuAvgStr = (
                "%16s(%7s/%7s): " % ("CPU/AVG", "-", "-") + timeLine + "\n"
            ) + cpuStr
            SysMgr.addPrint(cpuAvgStr)

        # total memory usage on timeline #
        timeLine = ""
        timeLineLen = titleLineLen
        for icount in xrange(lval):
            if timeLineLen + 4 > maxLineLen:
                timeLine += "\n" + (" " * (titleLineLen + 1))
                timeLineLen = titleLineLen + 4
            else:
                timeLineLen += 4

            try:
                timeLine += "%3d " % (
                    (self.intData[icount]["toTal"]["totalMem"] >> 8)
                    + (self.intData[icount]["toTal"]["totalKmem"] >> 20)
                )
            except:
                timeLine += "%3d " % (0)

        if SysMgr.memEnable:
            SysMgr.addPrint(
                "\n%16s(%7s/%7s): " % ("MEM", "-", "-") + timeLine + "\n"
            )
            if SysMgr.graphEnable:
                timeLineData = [int(n) for n in timeLine.split()]
                ioUsageList.append(timeLineData)
                ioLabelList.append("RAM Usage")

        # total block usage on timeline #
        if SysMgr.blockEnable:
            # total block read usage on timeline #
            brtotal = 0
            timeLine = ""
            timeLineLen = titleLineLen
            for icount in xrange(lval):
                if timeLineLen + 4 > maxLineLen:
                    timeLine += "\n" + (" " * (titleLineLen + 1))
                    timeLineLen = titleLineLen + 4
                else:
                    timeLineLen += 4

                try:
                    timeLine += "%3d " % (
                        (
                            self.intData[icount]["toTal"]["totalBr"]
                            * SysMgr.blockSize
                        )
                        >> 20
                    )
                    brtotal += self.intData[icount]["toTal"]["totalBr"]
                except:
                    timeLine += "%3d " % (0)

            if brtotal > 0:
                SysMgr.addPrint(
                    "\n%16s(%7s/%7s): " % ("BLK_RD", "-", "-")
                    + timeLine
                    + "\n"
                )
                if SysMgr.graphEnable:
                    timeLineData = [int(n) for n in timeLine.split()]
                    ioUsageList.append(timeLineData)
                    ioLabelList.append("Block Read")

            # total block write usage on timeline #
            bwtotal = 0
            timeLine = ""
            timeLineLen = titleLineLen
            for icount in xrange(lval):
                if timeLineLen + 4 > maxLineLen:
                    timeLine += "\n" + (" " * (titleLineLen + 1))
                    timeLineLen = titleLineLen + 4
                else:
                    timeLineLen += 4

                try:
                    timeLine += "%3d " % (
                        (
                            self.intData[icount]["toTal"]["totalBw"]
                            * SysMgr.blockSize
                        )
                        >> 20
                    )
                    bwtotal += self.intData[icount]["toTal"]["totalBw"]
                except:
                    timeLine += "%3d " % (0)

            if bwtotal > 0:
                if brtotal == 0:
                    SysMgr.addPrint("\n")
                SysMgr.addPrint(
                    "%16s(%7s/%7s): " % ("BLK_WR", "0", "-----")
                    + timeLine
                    + "\n"
                )
                if SysMgr.graphEnable:
                    timeLineData = [int(n) for n in timeLine.split()]
                    ioUsageList.append(timeLineData)
                    ioLabelList.append("Block Write")

        # total custom event usage on timeline #
        newLine = True
        for evt, value in sorted(
            self.customEventInfo.items(),
            key=lambda e: e[1]["count"],
            reverse=True,
        ):

            timeLine = ""
            timeLineLen = titleLineLen
            for icount in xrange(lval):
                if timeLineLen + 4 > maxLineLen:
                    timeLine += "\n" + (" " * (titleLineLen + 1))
                    timeLineLen = titleLineLen + 4
                else:
                    timeLineLen += 4

                try:
                    timeLine += (
                        "%3d "
                        % self.intData[icount]["toTal"]["customEvent"][evt][
                            "count"
                        ]
                    )
                except:
                    timeLine += "%3d " % 0

            if newLine:
                SysMgr.addPrint("\n")
                newLine = False

            SysMgr.addPrint(
                "%16s(%7s/%7s): " % (evt[: SysMgr.commLen], "-", "-")
                + timeLine
                + "\n"
            )

        # total user event usage on timeline #
        newLine = True
        for evt, value in sorted(
            self.userEventInfo.items(),
            key=lambda e: e[1]["count"],
            reverse=True,
        ):

            timeLine = ""
            timeLineLen = titleLineLen
            for icount in xrange(lval):
                if timeLineLen + 4 > maxLineLen:
                    timeLine += "\n" + (" " * (titleLineLen + 1))
                    timeLineLen = titleLineLen + 4
                else:
                    timeLineLen += 4

                try:
                    timeLine += (
                        "%3d "
                        % self.intData[icount]["toTal"]["userEvent"][evt][
                            "count"
                        ]
                    )

                    """
                    timeLine += '%3d ' % \
                        (self.intData[icount]['toTal']['userEvent'][evt]['usage'] / \
                        intervalEnable * 100)
                    """
                except:
                    timeLine += "%3d " % (0)

            if newLine:
                SysMgr.addPrint("\n")
                newLine = False

            SysMgr.addPrint(
                "%16s(%7s/%7s): " % (evt[: SysMgr.commLen], "-", "-")
                + timeLine
                + "\n"
            )

        # total kernel event usage on timeline #
        newLine = True
        for evt, value in sorted(
            self.kernelEventInfo.items(),
            key=lambda e: e[1]["count"],
            reverse=True,
        ):

            timeLine = ""
            timeLineLen = titleLineLen
            for icount in xrange(lval):
                if timeLineLen + 4 > maxLineLen:
                    timeLine += "\n" + (" " * (titleLineLen + 1))
                    timeLineLen = titleLineLen + 4
                else:
                    timeLineLen += 4

                try:
                    evtVal = self.intData[icount]["toTal"]["kernelEvent"][evt]
                    timeLine += "%3d " % evtVal["count"]

                    """
                    timeLine += '%3d ' % \
                        (evtVal['usage'] / intervalEnable * 100)
                    """
                except:
                    timeLine += "%3d " % (0)

            if newLine:
                SysMgr.addPrint("\n")
                newLine = False

            SysMgr.addPrint(
                "%16s(%7s/%7s): " % (evt[: SysMgr.commLen], "-", "-")
                + timeLine
                + "\n"
            )

        # print buffered info #
        SysMgr.printPipe("%s# %s\n" % ("", "Total(%/MB/Cnt)"))
        SysMgr.doPrint()
        SysMgr.printPipe(oneLine)
        SysMgr.clearPrint()

        if SysMgr.graphEnable:
            # get matplotlib object #
            matplotlib = SysMgr.getPkg("matplotlib", False)
            if not matplotlib:
                SysMgr.printPipWarn("matplotlib", "matplotlib")
                sys.exit(-1)
            from matplotlib.ticker import (
                MaxNLocator,
            )  # pylint: disable=import-error

            SysMgr.matplotlibVersion = float(
                ".".join(matplotlib.__version__.split(".")[:2])
            )

            # set backend #
            matplotlib.pyplot.switch_backend("agg")

            # get pylab object #
            SysMgr.importPkgItems("pylab")

        # draw I/O graph #
        if SysMgr.graphEnable and len(ioUsageList) > 0:
            timelen = len(ioUsageList[0])
            ax = subplot2grid((6, 1), (5, 0), rowspan=1, colspan=1)
            ax.xaxis.set_major_locator(MaxNLocator(integer=True))
            ax.yaxis.set_major_locator(MaxNLocator(integer=True))

            timeline = list(
                xrange(
                    intervalEnable,
                    (timelen + 1) * intervalEnable,
                    intervalEnable,
                )
            )
            timeline[-1] = self.totalTime

            for idx, item in enumerate(ioUsageList):
                minIdx = item.index(min(item))
                maxIdx = item.index(max(item))
                nrColor = long(idx) % 3
                if nrColor == 0:
                    color = "blue"
                elif nrColor == 1:
                    color = "red"
                else:
                    color = "green"

                plot(timeline, item, "-", c=color)

                margin = self.getMargin()

                if minIdx > 0:
                    minUsage = str(item[minIdx])
                    text(
                        minIdx + 1,
                        item[minIdx] - margin,
                        minUsage,
                        fontsize=self.lfsize + 1,
                        color=color,
                        fontweight="bold",
                    )
                if maxIdx > 0:
                    maxUsage = str(item[maxIdx])
                    text(
                        maxIdx + 1,
                        item[maxIdx] - margin,
                        maxUsage,
                        fontsize=self.lfsize + 1,
                        color=color,
                        fontweight="bold",
                    )

            # draw label #
            TaskAnalyzer.drawLabel(ioLabelList, draw=True, anchor=(1.1, 1))

            # add % unit to each value #
            try:
                ytickLabel = ax.get_yticks().tolist()
                ytickLabel = list(map(long, ytickLabel))

                # convert label units #
                convNum = UtilMgr.convSize2Unit
                ytickLabel = [convNum(val << 20, True) for val in ytickLabel]

                ax.set_yticklabels(ytickLabel)
            except:
                pass

            grid(which="both", linestyle=":", linewidth=0.2)
            yticks(fontsize=5)
            xticks(fontsize=self.xfsize)

            # draw base #
            TaskAnalyzer.drawFigure()

        # CPU usage on timeline #
        for key, value in sorted(
            self.threadData.items(), key=lambda e: e[1]["usage"], reverse=True
        ):

            if key.startswith("0["):
                continue

            timeLine = ""
            timeLineLen = titleLineLen
            for icount in xrange(lval):
                newFlag = " "
                dieFlag = " "

                if timeLineLen + 4 > maxLineLen:
                    timeLine += "\n" + (" " * (titleLineLen + 1))
                    timeLineLen = titleLineLen + 4
                else:
                    timeLineLen += 4

                try:
                    self.intData[icount][key]
                except:
                    timeLine += "%3d " % 0
                    continue

                nowVal = self.intData[icount][key]

                try:
                    prevVal = self.intData[icount - 1][key]
                except:
                    prevVal = nowVal

                if icount > 0:
                    try:
                        if nowVal["new"] != prevVal["new"]:
                            newFlag = nowVal["new"]
                    except:
                        newFlag = nowVal["new"]
                    try:
                        if nowVal["die"] != prevVal["die"]:
                            dieFlag = nowVal["die"]
                    except:
                        dieFlag = nowVal["die"]
                else:
                    newFlag = self.intData[icount][key]["new"]
                    dieFlag = self.intData[icount][key]["die"]

                # Do not use 100% because of output format #
                cpuPer = str(long(self.intData[icount][key]["cpuPer"]))
                if cpuPer == "100":
                    cpuPer = "99"

                timeLine += "%4s" % (newFlag + cpuPer + dieFlag)

            try:
                pid = SysMgr.savedProcTree[key]
            except:
                pid = value["tgid"]

            SysMgr.addPrint(
                "%16s(%7s/%7s): " % (value["comm"][:16], key, pid)
                + timeLine
                + "\n"
            )

            if SysMgr.graphEnable and SysMgr.cpuEnable:
                timeLine = timeLine.replace("N", "")
                timeLine = timeLine.replace("D", "")
                timeLine = timeLine.replace("F", "")
                cpuThrUsageList.append([int(n) for n in timeLine.split()])
                tinfo = "%s(%s)" % (value["comm"], key)
                cpuThrLabelList.append(tinfo)

            if (
                not SysMgr.showAll
                and value["usage"] / float(self.totalTime) * 100 < 1
            ):
                break

        # draw CPU graph #
        if SysMgr.graphEnable and len(cpuUsageList) > 0:
            timelen = len(cpuUsageList[0])
            ax = subplot2grid((6, 1), (0, 0), rowspan=5, colspan=1)
            ax.xaxis.set_major_locator(MaxNLocator(integer=True))
            ax.yaxis.set_major_locator(MaxNLocator(integer=True))

            # CPU total usage #
            totalCpuUsage = None
            for item in cpuUsageList:
                if totalCpuUsage is None:
                    totalCpuUsage = item
                    continue

                totalCpuUsage = list(map(int.__add__, totalCpuUsage, item))

            avgCpuUsage = [x / len(cpuUsageList) for x in totalCpuUsage]

            timeline = list(
                xrange(
                    intervalEnable,
                    (timelen + 1) * intervalEnable,
                    intervalEnable,
                )
            )
            timeline[-1] = self.totalTime

            plot(
                timeline,
                avgCpuUsage,
                ".-",
                linewidth=3,
                solid_capstyle="round",
            )

            # CPU usage of threads #
            for idx, item in enumerate(cpuThrUsageList):
                maxIdx = item.index(max(item))

                color = plot(timeline, item, "-")[0].get_color()

                margin = self.getMargin()

                maxCpuPer = str(item[maxIdx])
                label = "%s[max: %s%%]" % (cpuThrLabelList[idx], maxCpuPer)
                text(
                    maxIdx + 1,
                    item[maxIdx] + margin,
                    label,
                    fontsize=self.lfsize,
                    color=color,
                    fontweight="bold",
                )

            # draw label #
            totalLabel = [" CPU Average "] + cpuThrLabelList
            TaskAnalyzer.drawLabel(totalLabel, draw=True, anchor=(1.12, 1))

            # add % unit to each value #
            try:
                ytickLabel = ax.get_yticks().tolist()
                ymax = max(ytickLabel)
                ylim([0, ymax + long(ymax / 10)])
                inc = long(ymax / 10)
                if inc == 0:
                    inc = 1
                yticks(xrange(0, long(ymax + inc), inc), fontsize=5)
            except:
                pass

            suptitle("Guider Thread Graph", fontsize=8)

            grid(which="both", linestyle=":", linewidth=0.2)
            yticks(fontsize=5)
            xticks(fontsize=self.xfsize)

            # draw base #
            TaskAnalyzer.drawFigure()

        if SysMgr.cpuEnable:
            SysMgr.printPipe("%s# %s\n" % ("", "CPU(%)"))
            SysMgr.doPrint()
            SysMgr.printPipe(oneLine)

        # preempted units on timeline #
        SysMgr.clearPrint()
        for key, value in sorted(
            self.threadData.items(),
            key=lambda e: e[1]["cpuWait"],
            reverse=True,
        ):

            if (
                value["cpuWait"] / float(self.totalTime) * 100 < 1
                and not SysMgr.showAll
            ):
                break
            elif key.startswith("0["):
                continue

            timeLine = ""
            timeLineLen = titleLineLen
            for icount in xrange(lval):
                newFlag = " "
                dieFlag = " "

                if timeLineLen + 4 > maxLineLen:
                    timeLine += "\n" + (" " * (titleLineLen + 1))
                    timeLineLen = titleLineLen + 4
                else:
                    timeLineLen += 4

                try:
                    self.intData[icount][key]
                except:
                    timeLine += "%3d " % 0
                    continue

                nowVal = self.intData[icount][key]

                try:
                    prevVal = self.intData[icount - 1][key]
                except:
                    prevVal = nowVal

                if icount > 0:
                    try:
                        if nowVal["new"] != prevVal["new"]:
                            newFlag = self.intData[icount][key]["new"]
                    except:
                        newFlag = nowVal["new"]
                    try:
                        if nowVal["die"] != prevVal["die"]:
                            dieFlag = nowVal["die"]
                    except:
                        dieFlag = nowVal["die"]
                else:
                    newFlag = nowVal["new"]
                    dieFlag = nowVal["die"]

                # Do not use 100% because of output format #
                totalPrt = nowVal["preempted"] / float(intervalEnable)
                prtPer = str(long(totalPrt * 100))
                if prtPer == "100":
                    prtPer = "99"

                timeLine += "%4s" % (newFlag + prtPer + dieFlag)

            try:
                pid = SysMgr.savedProcTree[key]
            except:
                pid = value["tgid"]

            SysMgr.addPrint(
                "%16s(%7s/%7s): " % (value["comm"][:16], key, pid)
                + timeLine
                + "\n"
            )

        if SysMgr.bufferString:
            SysMgr.printPipe("%s# %s\n" % ("", "Delay(%)"))
            SysMgr.doPrint()
            SysMgr.printPipe(oneLine)

        # memory usage on timeline #
        SysMgr.clearPrint()
        if SysMgr.memEnable:
            for key, value in sorted(
                self.threadData.items(),
                key=lambda e: e[1]["nrPages"],
                reverse=True,
            ):

                if (
                    not SysMgr.showAll
                    and (value["nrPages"] >> 8) + (value["remainKmem"] >> 20)
                    < 1
                ):
                    break
                elif key.startswith("0["):
                    continue

                timeLine = ""
                timeLineLen = titleLineLen
                for icount in xrange(lval):
                    newFlag = " "
                    dieFlag = " "

                    if timeLineLen + 4 > maxLineLen:
                        timeLine += "\n" + (" " * (titleLineLen + 1))
                        timeLineLen = titleLineLen + 4
                    else:
                        timeLineLen += 4

                    try:
                        self.intData[icount][key]
                    except:
                        timeLine += "%3d " % 0
                        continue

                    nowVal = self.intData[icount][key]

                    try:
                        prevVal = self.intData[icount - 1][key]
                    except:
                        prevVal = nowVal

                    if icount > 0:
                        try:
                            if nowVal["new"] != prevVal["new"]:
                                newFlag = self.intData[icount][key]["new"]
                        except:
                            newFlag = nowVal["new"]
                        try:
                            if nowVal["die"] != prevVal["die"]:
                                dieFlag = nowVal["die"]
                        except:
                            dieFlag = nowVal["die"]
                    else:
                        newFlag = nowVal["new"]
                        dieFlag = nowVal["die"]

                    memUsage = self.intData[icount][key]["memUsage"] >> 8
                    kmemUsage = self.intData[icount][key]["kmemUsage"] >> 20
                    timeLine += "%4s" % (
                        newFlag + str(memUsage + kmemUsage) + dieFlag
                    )

                try:
                    pid = SysMgr.savedProcTree[key]
                except:
                    pid = value["tgid"]

                SysMgr.addPrint(
                    "%16s(%7s/%7s): " % (value["comm"][:16], key, pid)
                    + timeLine
                    + "\n"
                )

            if SysMgr.bufferString:
                SysMgr.printPipe("%s# %s\n" % ("", "MEM(MB)"))
                SysMgr.doPrint()
                SysMgr.printPipe(oneLine)

        # block read usage on timeline #
        SysMgr.clearPrint()
        if SysMgr.blockEnable:
            for key, value in sorted(
                self.threadData.items(),
                key=lambda e: e[1]["reqRdBlock"],
                reverse=True,
            ):

                if value["readBlock"] < 1 and not SysMgr.showAll:
                    break
                elif key.startswith("0["):
                    continue

                timeLine = ""
                timeLineLen = titleLineLen
                for icount in xrange(lval):
                    newFlag = " "
                    dieFlag = " "

                    if timeLineLen + 4 > maxLineLen:
                        timeLine += "\n" + (" " * (titleLineLen + 1))
                        timeLineLen = titleLineLen + 4
                    else:
                        timeLineLen += 4

                    try:
                        self.intData[icount][key]
                    except:
                        timeLine += "%3d " % 0
                        continue

                    nowVal = self.intData[icount][key]

                    try:
                        prevVal = self.intData[icount - 1][key]
                    except:
                        prevVal = nowVal

                    if icount > 0:
                        try:
                            if nowVal["new"] != prevVal["new"]:
                                newFlag = self.intData[icount][key]["new"]
                        except:
                            newFlag = nowVal["new"]
                        try:
                            if nowVal["die"] != prevVal["die"]:
                                dieFlag = nowVal["die"]
                        except:
                            dieFlag = nowVal["die"]
                    else:
                        newFlag = nowVal["new"]
                        dieFlag = nowVal["die"]

                    timeLine += "%4s" % (
                        newFlag
                        + str(
                            long(
                                (
                                    self.intData[icount][key]["brUsage"]
                                    * SysMgr.blockSize
                                )
                                >> 20
                            )
                        )
                        + dieFlag
                    )

                try:
                    pid = SysMgr.savedProcTree[key]
                except:
                    pid = value["tgid"]

                SysMgr.addPrint(
                    "%16s(%7s/%7s): " % (value["comm"][:16], key, pid)
                    + timeLine
                    + "\n"
                )

            if SysMgr.bufferString:
                SysMgr.printPipe("%s# %s\n" % ("", "BLK_RD(MB)"))
                SysMgr.doPrint()
                SysMgr.printPipe(oneLine)

        # block write usage on timeline #
        SysMgr.clearPrint()
        if SysMgr.blockEnable:
            for key, value in sorted(
                self.threadData.items(),
                key=lambda e: e[1]["reqWrBlock"] + (e[1]["awriteBlock"] << 3),
                reverse=True,
            ):

                if (
                    value["reqWrBlock"] + (value["awriteBlock"] << 3) < 1
                    and not SysMgr.showAll
                ):
                    break
                elif key.startswith("0["):
                    continue

                timeLine = ""
                timeLineLen = titleLineLen
                for icount in xrange(lval):
                    newFlag = " "
                    dieFlag = " "

                    if timeLineLen + 4 > maxLineLen:
                        timeLine += "\n" + (" " * (titleLineLen + 1))
                        timeLineLen = titleLineLen + 4
                    else:
                        timeLineLen += 4

                    try:
                        self.intData[icount][key]
                    except:
                        timeLine += "%3d " % 0
                        continue

                    nowVal = self.intData[icount][key]

                    try:
                        prevVal = self.intData[icount - 1][key]
                    except:
                        prevVal = nowVal

                    if icount > 0:
                        try:
                            if nowVal["new"] != prevVal["new"]:
                                newFlag = self.intData[icount][key]["new"]
                        except:
                            newFlag = nowVal["new"]
                        try:
                            if nowVal["die"] != prevVal["die"]:
                                dieFlag = nowVal["die"]
                        except:
                            dieFlag = nowVal["die"]
                    else:
                        newFlag = nowVal["new"]
                        dieFlag = nowVal["die"]

                    timeLine += "%4s" % (
                        newFlag
                        + str(
                            long(
                                (
                                    self.intData[icount][key]["bwUsage"]
                                    * SysMgr.blockSize
                                )
                                >> 20
                            )
                        )
                        + dieFlag
                    )

                try:
                    pid = SysMgr.savedProcTree[key]
                except:
                    pid = value["tgid"]

                SysMgr.addPrint(
                    "%16s(%7s/%7s): "
                    % (value["comm"][:16], key, value["tgid"])
                    + timeLine
                    + "\n"
                )

            if SysMgr.bufferString:
                SysMgr.printPipe("%s# %s\n" % ("", "BLK_WR(MB)"))
                SysMgr.doPrint()
                SysMgr.printPipe(oneLine)

        # event usage on timeline #
        self.printEventIntervalInfo()

        # save graph #
        if SysMgr.graphEnable and (
            len(cpuUsageList) > 0 or len(ioUsageList) > 0
        ):
            TaskAnalyzer.saveImage(SysMgr.inputFile, "graph")

    def getNetworkUsage(self, prev, now):
        if not now or prev == now:
            return (0, 0)

        nowIn = nowOut = prevIn = prevOut = 0

        idx = -1

        for line in now:
            idx += 1
            if not line:
                continue
            elif type(line) is not str:
                continue
            elif not line.startswith("IpExt"):
                continue

            try:
                if SysMgr.netInIndex < 0:
                    SysMgr.netInIndex = line.split().index("InOctets")

                nowStat = line.split()
                nowIn = long(nowStat[SysMgr.netInIndex])
                nowOut = long(nowStat[SysMgr.netInIndex + 1])

                if SysMgr.totalEnable:
                    prevIn = prevOut = 0
                else:
                    prevStat = prev[idx].split()
                    prevIn = long(prevStat[SysMgr.netInIndex])
                    prevOut = long(prevStat[SysMgr.netInIndex + 1])

                inDiff = nowIn - prevIn
                outDiff = nowOut - prevOut

                return (inDiff, outDiff)
            except SystemExit:
                sys.exit(0)
            except:
                continue

        return (0, 0)

    @staticmethod
    def printThreadTree():
        orig = SysMgr.processEnable

        try:
            SysMgr.processEnable = False

            # save task info #
            obj = TaskAnalyzer(onlyInstance=True)
            obj.saveProcStat()

            # set color flag #
            if SysMgr.checkMode("filerec"):
                color = True
            else:
                color = False

            # print task tree #
            TaskAnalyzer.printProcTree(
                instance=obj.procData,
                printFunc=SysMgr.infoBufferPrint,
                color=color,
            )
        except SystemExit:
            sys.exit(0)
        except:
            pass
        finally:
            SysMgr.processEnable = orig

    @staticmethod
    def readTraceData(fname):
        try:
            # not compressed data #
            if SysMgr.isRecordMode() or not UtilMgr.isCompressed(fname):
                if sys.version_info >= (3, 0, 0):
                    with open(fname, "r", encoding="latin-1") as fr:
                        return fr.readlines()
                else:
                    with open(fname, "r") as fr:
                        return fr.readlines()

            # compressed data #
            with open(fname, "rb") as fd:
                compressor = SysMgr.getPkg("gzip")
                fd = compressor.GzipFile(fileobj=fd)

                lines = []
                tlines = fd.read().decode().split("\n")
                for item in tlines:
                    if not item:
                        continue
                    lines.append("%s\n" % item)

                return lines
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenErr(fname)
            sys.exit(-1)

    @staticmethod
    def setLastField(option):
        SysMgr.affinityEnable = False
        SysMgr.wchanEnable = False
        SysMgr.sigHandlerEnable = False
        SysMgr.oomEnable = False

        if option == "affinity":
            SysMgr.affinityEnable = True
        elif option == "wchan":
            SysMgr.wchanEnable = True
        elif option == "signal":
            SysMgr.sigHandlerEnable = True
        elif option == "oom":
            SysMgr.oomEnable = True
        else:
            SysMgr.printErr("failed to set '%s' as a last field" % option)

    @staticmethod
    def parseProcLine(index, procLine):
        TA = TaskAnalyzer
        procIndexData = TA.procIntData[index]

        # time #
        if "time" not in procIndexData:
            m = re.match(
                (
                    r".+\[Time:\s*(?P<time>[0-9]+.[0-9]+)\].+"
                    r"\[Ctxt:\s*(?P<nrCtxt>[0-9]+)\].+"
                    r"\[IRQ:\s*(?P<nrIrq>[0-9]+)\].+"
                    r"\[Core:\s*(?P<nrCore>[0-9]+)\].+"
                    r"\[Task:\s*(?P<nrProc>[0-9]+)"
                    r"/(?P<nrThread>[0-9]+)"
                ),
                procLine,
            )
            if m:
                d = m.groupdict()
                procIndexData["time"] = d["time"]
                procIndexData["nrCtxt"] = d["nrCtxt"]
                procIndexData["nrIrq"] = d["nrIrq"]
                procIndexData["nrCore"] = d["nrCore"]
                procIndexData["nrProc"] = d["nrProc"]
                procIndexData["nrThread"] = d["nrThread"]
            return

        # shortcut #
        convUnit2Size = UtilMgr.convUnit2Size

        # split stats #
        tokens = procLine.split("|")

        # total #
        if "total" not in procIndexData and tokens[0].startswith("Total"):

            # parse CPU & BLOCK stat #
            m = re.match(
                (
                    r"\s*(?P<cpu>\-*[0-9]+)\s*%\s*\(\s*"
                    r"(?P<user>\-*[0-9]+)\s*\/s*\s*"
                    r"(?P<kernel>\-*[0-9]+)\s*\/s*\s*"
                    r"(?P<block>\-*[0-9]+)"
                ),
                tokens[1],
            )
            if not m:
                return

            d = m.groupdict()

            # CPU stat #
            cpu = long(d["cpu"])

            # sum total CPU usage #
            TA.procTotData["total"]["cpu"] += cpu

            # get total max CPU usage #
            if TA.procTotData["total"]["cpuMax"] < cpu:
                TA.procTotData["total"]["cpuMax"] = cpu

            # get total min CPU usage #
            if TA.procTotData["total"]["cpuMin"] < 0:
                TA.procTotData["total"]["cpuMin"] = cpu
            elif TA.procTotData["total"]["cpuMin"] > cpu:
                TA.procTotData["total"]["cpuMin"] = cpu

            procIndexData["total"] = dict(TA.init_procIntData)

            # save CPU usage on this interval #
            try:
                procIndexData["total"]["cpu"] = cpu
            except:
                procIndexData["total"]["cpu"] = 0

            # save blkwait on this interval #
            try:
                procIndexData["total"]["blkwait"] = long(d["block"])
            except:
                procIndexData["total"]["blkwait"] = 0

            # parse MEM stat #
            m = re.match(
                (
                    r"\s*(?P<free>[0-9]+)\s*\(\s*(?P<freePer>[0-9]+)\s*"
                    r"/\s*(?P<anon>[0-9]+)\s*/\s*(?P<cache>[0-9]+)\s*"
                    r"/\s*(?P<kernel>[0-9]+)"
                ),
                tokens[2],
            )
            if not m:
                return

            d = m.groupdict()

            # MEM stats #
            freeMem = long(d["free"])
            freeMemPer = long(d["freePer"])
            anonMem = long(d["anon"])
            cacheMem = long(d["cache"])
            kernelMem = long(d["kernel"])

            if TA.procTotData["total"]["initMem"] == 0:
                TA.procTotData["total"]["initMem"] = freeMem

            TA.procTotData["total"]["lastMem"] = freeMem

            # set minimum free memory #
            if (
                TA.procTotData["total"]["minMem"] == 0
                or TA.procTotData["total"]["minMem"] > freeMem
            ):
                TA.procTotData["total"]["minMem"] = freeMem
            # set maximum free memory #
            if TA.procTotData["total"]["maxMem"] < freeMem:
                TA.procTotData["total"]["maxMem"] = freeMem

            procIndexData["total"]["mem"] = freeMem
            procIndexData["total"]["memper"] = freeMemPer
            procIndexData["total"]["anonmem"] = anonMem
            procIndexData["total"]["cachemem"] = cacheMem
            procIndexData["total"]["kernelmem"] = kernelMem

            try:
                procIndexData["total"]["blk"] = tokens[5]
            except:
                procIndexData["total"]["blk"] = "-"

            # parse swap stat #
            m = re.match(r"\s*(?P<swap>\-*[0-9]+)", tokens[3])
            if not m:
                return

            d = m.groupdict()

            # swap stat #
            procIndexData["total"]["swap"] = long(d["swap"])

            try:
                procIndexData["total"]["rclm"] = tokens[4].strip()
            except:
                procIndexData["total"]["rclm"] = "-"

            try:
                procIndexData["total"]["nrFlt"] = long(tokens[6])
            except:
                procIndexData["total"]["nrFlt"] = "-"

            try:
                procIndexData["total"]["netIO"] = tokens[11].strip()
            except:
                procIndexData["total"]["netIO"] = "-"

            return

        # GPU #
        elif len(tokens) == 5:
            m = re.match(
                r"\s*(?P<gpu>.+)\s*\(\s*(?P<usage>[0-9]+)\s*%\)", tokens[0]
            )
            if m:
                d = m.groupdict()

                gpu = d["gpu"].strip()
                usage = long(d["usage"])

                procIndexData["total"].setdefault("gpu", {})

                TA.procTotData["total"].setdefault("gpu", {})
                totalData = TA.procTotData["total"]["gpu"]

                try:
                    totalData[gpu]["usage"] += usage

                    if totalData[gpu]["min"] > usage:
                        totalData[gpu]["min"] = usage
                    elif totalData[gpu]["max"] < usage:
                        totalData[gpu]["max"] = usage
                except:
                    totalData[gpu] = {}
                    totalData[gpu]["usage"] = usage
                    totalData[gpu]["min"] = usage
                    totalData[gpu]["max"] = usage

                try:
                    procIndexData["total"]["gpu"][gpu] = usage
                except:
                    pass

            return

        # storage #
        elif len(tokens) == 12 and tokens[0][0] == "/":
            procIndexData["total"].setdefault("storage", {})
            TA.procTotData["total"].setdefault("storage", {})

            try:
                # get device name #
                dev = tokens[0].strip()
                dev = dev[dev.rfind("/") + 1 :]

                procIndexData["total"]["storage"].setdefault(dev, {})
                indexData = procIndexData["total"]["storage"][dev]

                TA.procTotData["total"]["storage"].setdefault(dev, {})
                totalData = TA.procTotData["total"]["storage"][dev]

                # get busy time and average queue-length #
                busy = convUnit2Size(tokens[1].strip()[:-1])
                avq = tokens[2].strip()

                # get storage stats in MB #
                read = convUnit2Size(tokens[3].strip())
                write = convUnit2Size(tokens[4].strip())

                freestat = tokens[5].strip().split("(")
                freeDiff = convUnit2Size(freestat[1][:-1].strip())

                # busy #
                try:
                    indexData["busy"] = busy
                    totalData["busy"] += busy
                except:
                    totalData["busy"] = busy

                # avq #
                try:
                    indexData["avq"] = avq
                    totalData["avq"] += avq
                except:
                    totalData["avq"] = avq

                # read #
                try:
                    indexData["read"] = read
                    totalData["read"] += read
                except:
                    totalData["read"] = read

                # write #
                try:
                    indexData["write"] = write
                    totalData["write"] += write
                except:
                    totalData["write"] = write

                # freediff #
                try:
                    indexData["free"] = freeDiff
                    totalData["free"] += freeDiff
                except:
                    totalData["free"] = freeDiff
            except SystemExit:
                sys.exit(0)
            except:
                pass

            return

        # network #
        elif len(tokens) == 13 and not tokens[0].startswith("Total"):
            # check condition #
            if tokens[0].strip() == "ID" or tokens[0].strip() == "Dev":
                return

            procIndexData["total"].setdefault("netdev", {})
            TA.procTotData["total"].setdefault("netdev", {})

            try:
                # get device name #
                dev = tokens[0].strip()

                procIndexData["total"]["netdev"].setdefault(dev, {})
                TA.procTotData["total"]["netdev"].setdefault(dev, {})

                # get storage stats in MB #
                recv = convUnit2Size(tokens[2].strip())
                tran = convUnit2Size(tokens[7].strip())

                # recv #
                try:
                    procIndexData["total"]["netdev"][dev]["recv"] = recv
                    TA.procTotData["total"]["netdev"][dev]["recv"] += recv
                except:
                    TA.procTotData["total"]["netdev"][dev]["recv"] = recv

                # tran #
                try:
                    procIndexData["total"]["netdev"][dev]["tran"] = tran
                    TA.procTotData["total"]["netdev"][dev]["tran"] += tran
                except:
                    TA.procTotData["total"]["netdev"][dev]["tran"] = tran
            except:
                pass

            return

        # cgroup #
        elif len(tokens) == 9:
            tokens = UtilMgr.cleanItem(tokens, False)
            if len(tokens) != 8:
                return

            try:
                system, proc, task, cpu, thr, mem, read, write = tokens
            except:
                return

            # CPU #
            target = "cgroup.cpu"

            try:
                usage = float(cpu)
            except:
                return

            TA.procTotData["total"].setdefault(target, {})
            totalData = TA.procTotData["total"][target]

            try:
                totalData[system]["usage"] += usage

                if totalData[system]["min"] > usage:
                    totalData[system]["min"] = usage
                elif totalData[system]["max"] < usage:
                    totalData[system]["max"] = usage
            except:
                totalData[system] = {}
                totalData[system]["usage"] = usage
                totalData[system]["min"] = usage
                totalData[system]["max"] = usage

            try:
                procIndexData["total"].setdefault(target, {})
                procIndexData["total"][target][system] = usage
            except:
                pass

            # Memory #
            target = "cgroup.mem"

            try:
                usage = UtilMgr.convUnit2Size(mem)
            except:
                return

            TA.procTotData["total"].setdefault(target, {})
            totalData = TA.procTotData["total"][target]

            try:
                totalData[system]["usage"] = usage

                if totalData[system]["min"] > usage:
                    totalData[system]["min"] = usage
                elif totalData[system]["max"] < usage:
                    totalData[system]["max"] = usage
            except:
                totalData[system] = {}
                totalData[system]["usage"] = usage
                totalData[system]["min"] = usage
                totalData[system]["max"] = usage

            try:
                procIndexData["total"].setdefault(target, {})
                procIndexData["total"][target][system] = usage
            except:
                pass

            return

        # check return condition #
        if "ONLYTOTAL" in SysMgr.environList:
            return
        elif procLine in (oneLine, twoLine):
            return

        # process #
        m = re.match(
            (
                r"\s*(?P<comm>.+) \(\s*(?P<pid>[0-9]+)\/\s*(?P<ppid>[0-9]+)"
                r"\/\s*(?P<nrThreads>[0-9]+)\/(?P<pri>.{4})\)\|"
                r"\s*(?P<cpu>\S+)\(.+/.+/(?P<dly>.+)\)\|\s*"
                r"(?P<vss>[0-9]+)\(\s*(?P<rss>[0-9]+)\/\s*"
                r"(?P<text>.+)\/\s*(?P<shm>.+)\/\s*(?P<swap>.+)\)\|\s*"
                r"(?P<blk>\S+)\(\s*(?P<blkrd>.+)\/\s*(?P<blkwr>.+)\/\s*"
                r"(?P<nrflt>.+)\)\|\s*(?P<sid>.+)\|\s*(?P<user>.+)\|\s*"
                r"(?P<fd>.+)\|\s*(?P<life>.+)\|\s*(?P<parent>.+)\|"
            ),
            procLine,
        )
        if not m:
            return

        # check excepting for shm #
        if "EXCEPTSHM" in SysMgr.environList and (
            SysMgr.isDrawMode() or SysMgr.checkMode("topsum")
        ):
            exceptShm = True
        else:
            exceptShm = False

        d = m.groupdict()
        pid = d["pid"]
        comm = d["comm"].strip("*")

        # check filter #
        if SysMgr.filterGroup:
            if (
                not SysMgr.groupProcEnable
                and not UtilMgr.isValidStr(pid)
                and not UtilMgr.isValidStr(comm)
            ):
                return

        try:
            # ignore special processes #
            if len(comm) > 2 and comm[0] == "[" and comm[2] == "]":
                # define real comm #
                rcomm = comm[3:]

                # initialize lifecycle data #
                if rcomm not in TA.lifecycleData:
                    TA.lifecycleData[rcomm] = [0] * 8
                TA.lifeIntData.setdefault(pid, {})
                TA.lifeIntData[pid].setdefault(index, [])
                lifecycleData = TA.lifecycleData[rcomm]

                # died process #
                if comm[1] == "-":
                    lifecycleData[1] += 1

                    # get index #
                    if index == 0:
                        idx = 0
                    else:
                        idx = index - 1

                    if not pid in TA.procIntData[idx]:
                        TA.procIntData[idx][pid] = dict(TA.init_procIntData)

                    TA.procIntData[idx][pid]["die"] = True
                    TA.lifeIntData[pid][index].append("FINISH")

                    # convert lifetime #
                    ts = UtilMgr.convTime2Sec(d["life"])

                    # end time #
                    ets = TA.procIntData[idx]["time"]

                    # start time #
                    if ts:
                        if index:
                            sts = long(float(TA.procIntData[idx]["time"])) - ts
                        else:
                            start = long(float(TA.procIntData[0]["time"]))
                            sts = start - SysMgr.intervalEnable - ts
                    else:
                        sts = -2

                    TA.lifeProcData.setdefault(
                        pid,
                        {
                            "START": -2,
                            "FINISH": -2,
                            "comm": rcomm,
                            "parent": d["parent"],
                            "user": d["user"],
                        },
                    )

                    TA.lifeProcData[pid]["comm"] = rcomm
                    TA.lifeProcData[pid]["START"] = sts
                    TA.lifeProcData[pid]["FINISH"] = ets
                    if TA.lifeProcData[pid]["user"] == "-":
                        TA.lifeProcData[pid]["user"] = d["user"]
                # created process #
                elif comm[1] == "+":
                    lifecycleData[0] += 1
                    TA.lifeIntData[pid][index].append("START")

                    ts = UtilMgr.convTime2Sec(d["life"])
                    if ts:
                        ts = long(float(TA.procIntData[index]["time"])) - ts
                    else:
                        ts = TA.procIntData[index]["time"]

                    TA.lifeProcData.setdefault(
                        pid,
                        {
                            "START": -2,
                            "FINISH": -2,
                            "comm": rcomm,
                            "parent": d["parent"],
                            "user": d["user"],
                        },
                    )

                    TA.lifeProcData[pid]["comm"] = rcomm
                    TA.lifeProcData[pid]["START"] = ts
                    if TA.lifeProcData[pid]["user"] == "-":
                        TA.lifeProcData[pid]["user"] = d["user"]
                # zomebie process #
                elif comm[1].upper() == "Z":
                    lifecycleData[2] += 1
                    TA.lifeIntData[pid][index].append("ZOMBIE")
                # stopped process #
                elif comm[1] == "T":
                    lifecycleData[3] += 1
                # traced process #
                elif comm[1] == "t":
                    lifecycleData[4] += 1
                # wait process #
                elif comm[1].upper() == "D":
                    lifecycleData[5] += 1
                # waking process #
                elif comm[1].upper() == "W":
                    lifecycleData[6] += 1
                # parked process #
                elif comm[1].upper() == "P":
                    lifecycleData[7] += 1

                return
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # update comm for life data #
        if pid in TA.lifeProcData:
            TA.lifeProcData[pid]["comm"] = comm
            if TA.lifeProcData[pid]["user"] == "-":
                TA.lifeProcData[pid]["user"] = d["user"]

        # check pid in list #
        if pid not in TA.procTotData:
            TA.procTotData[pid] = dict(TA.init_procTotData)
            TA.procTotData[pid]["startIdx"] = index

        cpu = long(float(d["cpu"]))

        try:
            dly = long(d["dly"])
        except:
            dly = 0

        blk = long(float(d["blk"]))

        try:
            blkrd = long(d["blkrd"])
            blkwr = long(d["blkwr"])

            SysMgr.blockEnable = True
        except SystemExit:
            sys.exit(0)
        except:
            blkrd = blkwr = 0

        # save process info #
        TA.procTotData[pid]["comm"] = d["comm"]
        TA.procTotData[pid]["ppid"] = d["ppid"]
        TA.procTotData[pid]["nrThreads"] = d["nrThreads"]
        TA.procTotData[pid]["pri"] = d["pri"]

        # save CPU usage of process #
        TA.procTotData[pid]["cpu"] += cpu
        TA.procTotData[pid]["dly"] += dly

        if TA.procTotData[pid]["cpuMax"] < cpu:
            TA.procTotData[pid]["cpuMax"] = cpu

        if index > 0 and TA.procTotData[pid]["cpuMin"] < 0:
            TA.procTotData[pid]["cpuMin"] = 0
        elif TA.procTotData[pid]["cpuMin"] < 0:
            TA.procTotData[pid]["cpuMin"] = cpu
        elif TA.procTotData[pid]["cpuMin"] > cpu:
            TA.procTotData[pid]["cpuMin"] = cpu

        # save block usage of process #
        TA.procTotData[pid]["blk"] += blk
        TA.procTotData[pid]["blkrd"] += blkrd
        TA.procTotData[pid]["blkwr"] += blkwr

        # set vss #
        vss = long(d["vss"])
        if TA.procTotData[pid]["minVss"] >= vss:
            TA.procTotData[pid]["minVss"] = vss
        if TA.procTotData[pid]["maxVss"] < vss:
            TA.procTotData[pid]["maxVss"] = vss

        # set rss #
        rss = long(d["rss"])
        if exceptShm:
            try:
                rss -= long(d["text"])
                rss -= long(d["shm"])
            except SystemExit:
                sys.exit(0)
            except:
                pass
            finally:
                if rss < 0:
                    rss = 0

        if TA.procTotData[pid]["minMem"] >= rss:
            TA.procTotData[pid]["minMem"] = rss
        if TA.procTotData[pid]["maxMem"] <= rss:
            TA.procTotData[pid]["maxMem"] = rss

        # set mem #
        if TA.procTotData[pid]["initMem"] == 0:
            TA.procTotData[pid]["initMem"] = rss
            TA.procTotData[pid]["lastMem"] = rss

        # save process stats on this interval #
        if pid not in procIndexData:
            procIndexData[pid] = dict(TA.init_procIntData)
            procIndexData[pid]["cpu"] = cpu
            procIndexData[pid]["dly"] = dly
            procIndexData[pid]["vss"] = vss
            procIndexData[pid]["blk"] = blk
            procIndexData[pid]["blkrd"] = blkrd
            procIndexData[pid]["blkwr"] = blkwr
            procIndexData[pid]["mem"] = rss
            procIndexData[pid]["memDiff"] = (
                rss - TA.procTotData[pid]["lastMem"]
            )
            TA.procTotData[pid]["lastMem"] = rss

    @staticmethod
    def summarizeInterval():
        if "total" not in TaskAnalyzer.procTotData:
            TaskAnalyzer.procTotData["total"] = dict(
                TaskAnalyzer.init_procTotData
            )

        idx = 0
        for val in reversed(SysMgr.procBuffer):
            if len(TaskAnalyzer.procIntData) < idx + 1:
                TaskAnalyzer.procIntData.append({})

            # parse interval items #
            for line in val.split("\n"):
                TaskAnalyzer.parseProcLine(idx, line)

            idx += 1
            UtilMgr.printProgress(idx, len(SysMgr.procBuffer))

        if idx == 0:
            return

        UtilMgr.deleteProgress()

        # calculate final stat #
        for pid, val in TaskAnalyzer.procTotData.items():
            val["cpuAvg"] = round(val["cpu"] / float(idx), 1)
            val["memDiff"] = val["lastMem"] - val["initMem"]

    @staticmethod
    def printFileTable():
        if not SysMgr.fileInstance:
            return

        convNum = UtilMgr.convNum

        nrEvent = nrSocket = nrDevice = nrPipe = nrProc = nrFile = 0
        for filename in list(SysMgr.fileInstance):
            # increase type count per process #
            if filename.startswith("anon"):
                nrEvent += 1
            elif filename.startswith("socket"):
                nrSocket += 1
            elif filename.startswith("/dev"):
                nrDevice += 1
            elif filename.startswith("pipe"):
                nrPipe += 1
            elif filename.startswith(SysMgr.procPath):
                nrProc += 1
            else:
                nrFile += 1

        SysMgr.printPipe(
            (
                "\n[Top File Table] [TOTAL: %s] [FILE: %s] [EVENT: %s] "
                "[SOCKET: %s] [DEV: %s] [PIPE: %s] [PROC: %s]\n"
            )
            % (
                convNum(len(SysMgr.fileInstance)),
                convNum(nrFile),
                convNum(nrEvent),
                convNum(nrSocket),
                convNum(nrDevice),
                convNum(nrPipe),
                convNum(nrProc),
            )
        )
        SysMgr.printPipe(
            "{2:1}\n{0:^5} | {1:^144} |\n{3:1}\n".format(
                "REF", "FILE", twoLine, oneLine
            )
        )

        for filename, value in sorted(
            SysMgr.fileInstance.items(), key=lambda e: long(e[1]), reverse=True
        ):
            SysMgr.printPipe("{0:>5} | {1:<144} |\n".format(value, filename))

        if not SysMgr.fileInstance:
            SysMgr.printPipe("\tN/A\n")

        SysMgr.printPipe("%s\n" % oneLine)

    @staticmethod
    def printTimeline():
        SysMgr.printPipe("\n[Top Summary Info]\n%s\n" % twoLine)

        # check available memory type #
        if SysMgr.freeMemEnable:
            memTitle = "Free/User/Cache"
        else:
            memTitle = "Avl/User/Cache"

        SysMgr.printPipe(
            (
                "{0:^5} | {1:^27} | {2:^3} | {3:^18} | {4:^7} | {5:^3} | "
                "{6:^4} | {7:^9} | {8:^5} | {9:^6} | {10:^6} | {11:^8} | "
                "{12:^4} | {13:^8} |\n"
            ).format(
                "IDX",
                "Interval",
                "CPU",
                memTitle,
                "BlkRW",
                "Blk",
                "SWAP",
                "NrPgRclm",
                "NrFlt",
                "NrCtx",
                "NrIRQ",
                "NrTask",
                "Core",
                "Network",
            )
        )
        SysMgr.printPipe("%s\n" % twoLine)

        pCnt = 0
        for idx, val in list(enumerate(TaskAnalyzer.procIntData)):
            if idx == 0:
                before = "START"
            elif "time" in TaskAnalyzer.procIntData[idx - 1]:
                before = TaskAnalyzer.procIntData[idx - 1]["time"]
            else:
                continue

            if "total" not in val:
                continue

            task = "%s/%s" % (val["nrProc"], val["nrThread"])

            SysMgr.printPipe(
                (
                    "{0:>5} | {1:>12} - {2:>12} | {3:>3} | {4:^18} | "
                    "{5:^7} | {6:>3} | {7:>4} | {8:^9} | {9:>5} | {10:>6} | "
                    "{11:>6} | {12:>8} | {13:^4} | {14:^8} |\n"
                ).format(
                    idx + 1,
                    before,
                    val["time"],
                    val["total"]["cpu"],
                    "%s/%s/%s"
                    % (
                        val["total"]["mem"],
                        val["total"]["anonmem"],
                        val["total"]["cachemem"],
                    ),
                    val["total"]["blk"],
                    val["total"]["blkwait"],
                    val["total"]["swap"],
                    val["total"]["rclm"],
                    val["total"]["nrFlt"],
                    val["nrCtxt"],
                    val["nrIrq"],
                    task,
                    val["nrCore"],
                    val["total"]["netIO"],
                )
            )
            pCnt += 1

        if not TaskAnalyzer.procIntData or pCnt == 0:
            SysMgr.printPipe("\tNone\n")

        SysMgr.printPipe("%s\n" % oneLine)

    @staticmethod
    def printEventInterval():
        if not TaskAnalyzer.procEventData:
            return

        # remove invalid events #
        try:
            raise Exception("ignore")

            initTime = TaskAnalyzer.procIntData[0]["time"]

            eventList = list(TaskAnalyzer.procEventData)
            for event in eventList:
                time = event[0]

                # skip unbounded events #
                if float(initTime) > time:
                    del TaskAnalyzer.procEventData[0]
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # check events #
        if not TaskAnalyzer.procEventData:
            return

        # print title #
        SysMgr.printPipe("\n[Top Event Info] (Unit: %%)\n%s\n" % twoLine)
        SysMgr.printPipe(
            ("{0:^12} | {1:^12} | {2:^12} | {3:1}\n{4:1}\n").format(
                "Timeline", "Realtime", "Interval", "Event", twoLine
            )
        )

        procIntData = TaskAnalyzer.procIntData
        procEventData = TaskAnalyzer.procEventData
        for idx, event in enumerate(procEventData):
            name = event[1]
            time = "%.2f" % float(event[0])
            rtime = float(event[2])
            rtimestr = "%.2f" % rtime

            try:
                # from previous event #
                if len(procEventData) > 1 and idx > 0:
                    diff = rtime - float(procEventData[idx - 1][2])
                # from start #
                else:
                    diff = rtime - SysMgr.startTime
            except SystemExit:
                sys.exit(0)
            except:
                diff = 0

            # check diff #
            if diff < 0:
                diff = 0

            diff = "%.2f" % diff
            SysMgr.printPipe(
                ("{0:>12} | {1:>12} | {2:>12} | {3:1}\n").format(
                    time, rtimestr, diff, name
                )
            )

        SysMgr.printPipe("%s\n" % oneLine)

    @staticmethod
    def printCpuInterval():
        # check skip flag #
        if "NOCPUSUMMARY" in SysMgr.environList:
            return

        TA = TaskAnalyzer

        # set comm and pid size #
        pd = SysMgr.pidDigit
        cl = 26 - (pd * 2)

        SysMgr.printPipe(
            "\n[Top CPU Info] (Unit: %%) (New: +) (Die: -)\n%s\n" % twoLine
        )

        if SysMgr.processEnable:
            idName = "PID"
            pidName = "PPID"
        else:
            idName = "TID"
            pidName = "PID"

        # Print menu #
        procInfo = (
            "{0:>{cl}} ({1:>{pd}}/{2:>{pd}}/{3:>4}/{4:>4})| {5:^17} |".format(
                "COMM",
                idName,
                pidName,
                "Nr",
                "Pri",
                "Min/Avg/Max/Tot",
                cl=cl,
                pd=pd,
            )
        )
        procInfoLen = len(procInfo)
        maxLineLen = SysMgr.lineLength
        margin = 5

        # Print timeline #
        TA.printTimelineInterval(margin, procInfoLen, procInfo, 1)

        value = TA.procTotData["total"]
        cpuInfo = "%d/%.1f/%d/%d" % (
            value["cpuMin"] if value["cpuMin"] > 0 else 0,
            value["cpuAvg"],
            value["cpuMax"],
            value["cpu"],
        )

        # Print total CPU usage #
        procInfo = (
            "{0:>{cl}} ({1:>{pd}}/{2:>{pd}}/{3:>4}/{4:>4})| {5:^17} |".format(
                "[CPU/AVG]", "-", "-", "-", "-", cpuInfo, cl=cl, pd=pd
            )
        )
        procInfoLen = len(procInfo)
        maxLineLen = SysMgr.lineLength

        timeLine = ""
        lineLen = len(procInfo)
        for idx in xrange(len(TA.procIntData)):
            if lineLen + margin > maxLineLen:
                timeLine += "\n" + (" " * (procInfoLen - 1)) + "| "
                lineLen = len(procInfo)

            if "total" in TA.procIntData[idx]:
                usage = TA.procIntData[idx]["total"]["cpu"]
            else:
                usage = 0

            timeLine += "{0:>6} ".format(usage)
            lineLen += margin + 2

        SysMgr.printPipe(
            ("{0:1} {1:1}\n{2:1}\n").format(procInfo, timeLine, oneLine)
        )

        # Print CPU usage of processes #
        for pid, value in sorted(
            TA.procTotData.items(), key=lambda e: e[1]["cpu"], reverse=True
        ):

            if pid == "total":
                continue

            cpuInfo = "%d/%.1f/%d/%d" % (
                value["cpuMin"] if value["cpuMin"] > 0 else 0,
                value["cpuAvg"],
                value["cpuMax"],
                value["cpu"],
            )

            procInfo = "{0:>{cl}} ({1:>{pd}}/{2:>{pd}}/{3:>4}/{4:>4})| {5:^17} |".format(
                value["comm"][:cl],
                pid,
                value["ppid"],
                value["nrThreads"],
                value["pri"],
                cpuInfo,
                cl=cl,
                pd=pd,
            )
            procInfoLen = len(procInfo)
            maxLineLen = SysMgr.lineLength

            timeLine = ""
            lineLen = len(procInfo)
            total = 0
            for idx in xrange(len(TA.procIntData)):
                if lineLen + margin > maxLineLen:
                    timeLine += "\n" + (" " * (procInfoLen - 1)) + "| "
                    lineLen = len(procInfo)

                if pid in TA.procIntData[idx]:
                    usage = TA.procIntData[idx][pid]["cpu"]
                    total += TA.procIntData[idx][pid]["cpu"]
                else:
                    usage = 0

                lflag = ""
                if pid in TA.lifeIntData and idx in TA.lifeIntData[pid]:
                    for item in TA.lifeIntData[pid][idx]:
                        if item == "START":
                            lflag += "+"
                        elif item == "FINISH":
                            lflag += "-"

                # append lifecycle flag to usage #
                usage = lflag + str(usage)

                timeLine += "{0:>6} ".format(usage)
                lineLen += margin + 2

            # skip process used no CPU #
            if total == 0:
                continue

            SysMgr.printPipe(
                ("{0:1} {1:1}\n{2:1}\n").format(procInfo, timeLine, oneLine)
            )

    @staticmethod
    def printDlyInterval():
        # check skip flag #
        if "NODELAYSUMMARY" in SysMgr.environList:
            return

        TA = TaskAnalyzer

        # set comm and pid size #
        pd = SysMgr.pidDigit
        cl = 26 - (pd * 2)

        SysMgr.printPipe(
            "\n[Top Delay Info] (Unit: %%) (Target: THREAD)\n%s\n" % twoLine
        )

        if SysMgr.processEnable:
            idName = "PID"
            pidName = "PPID"
        else:
            idName = "TID"
            pidName = "PID"

        # Print menu #
        procInfo = (
            "{0:>{cl}} ({1:>{pd}}/{2:>{pd}}/{3:>4}/{4:>4})| {5:^5} |".format(
                "COMM", idName, pidName, "Nr", "Pri", "Tot", cl=cl, pd=pd
            )
        )
        procInfoLen = len(procInfo)
        maxLineLen = SysMgr.lineLength
        margin = 5

        # Print timeline #
        TA.printTimelineInterval(margin, procInfoLen, procInfo, 1)

        # Print CPU delay for processes #
        cnt = 0
        for pid, value in sorted(
            TA.procTotData.items(), key=lambda e: e[1]["dly"], reverse=True
        ):

            if pid == "total":
                continue

            dlyInfo = "%d" % value["dly"]

            procInfo = "{0:>{cl}} ({1:>{pd}}/{2:>{pd}}/{3:>4}/{4:>4})| {5:^5} |".format(
                value["comm"][:cl],
                pid,
                value["ppid"],
                value["nrThreads"],
                value["pri"],
                dlyInfo,
                cl=cl,
                pd=pd,
            )
            procInfoLen = len(procInfo)
            maxLineLen = SysMgr.lineLength

            timeLine = ""
            lineLen = len(procInfo)
            total = 0
            for idx in xrange(len(TA.procIntData)):
                if lineLen + margin > maxLineLen:
                    timeLine += "\n" + (" " * (procInfoLen - 1)) + "| "
                    lineLen = len(procInfo)

                if pid in TA.procIntData[idx]:
                    usage = TA.procIntData[idx][pid]["dly"]
                    total += TA.procIntData[idx][pid]["dly"]
                else:
                    usage = 0

                timeLine += "{0:>6} ".format(usage)
                lineLen += margin + 2

            # skip no delayed procdss #
            if total == 0:
                continue

            SysMgr.printPipe(
                ("{0:1} {1:1}\n{2:1}\n").format(procInfo, timeLine, oneLine)
            )

            cnt += 1

        if cnt == 0:
            SysMgr.printPipe("\tNone\n%s\n" % oneLine)

    @staticmethod
    def printGpuInterval():
        # check skip flag #
        if "NOGPUSUMMARY" in SysMgr.environList:
            return

        TA = TaskAnalyzer

        # Check GPU data #
        if "gpu" not in TA.procTotData["total"]:
            return

        SysMgr.printPipe("\n[Top GPU Info] (Unit: %%)\n%s\n" % twoLine)

        # Print menu #
        gpuInfo = "{0:>23} | {1:^17} |".format("GPU", "Min/Avg/Max/Tot")
        gpuInfoLen = len(gpuInfo)
        maxLineLen = SysMgr.lineLength
        margin = 5

        # Print timeline #
        TA.printTimelineInterval(margin, gpuInfoLen, gpuInfo, 1)

        # Print GPU usage #
        for gpu, stat in TA.procTotData["total"]["gpu"].items():
            try:
                avg = stat["usage"] / float(len(TA.procIntData))
            except:
                avg = 0

            # get stats #
            stats = "%d/%.1f/%d/%d" % (
                stat["min"] if stat["min"] > 0 else 0,
                avg,
                stat["max"],
                stat["usage"],
            )

            gpuInfo = "{0:>23} | {1:^17} |".format(gpu, stats)
            gpuInfoLen = len(gpuInfo)
            maxLineLen = SysMgr.lineLength

            timeLine = ""
            lineLen = len(gpuInfo)
            total = 0
            margin = 5
            for idx in xrange(len(TA.procIntData)):
                if lineLen + margin > maxLineLen:
                    timeLine += "\n" + (" " * (gpuInfoLen - 1)) + "| "
                    lineLen = len(gpuInfo)

                try:
                    usage = TA.procIntData[idx]["total"]["gpu"][gpu]
                    total += usage
                except:
                    usage = 0

                timeLine += "{0:>6} ".format(usage)
                lineLen += 7

            SysMgr.printPipe(
                ("{0:1} {1:1}\n{2:1}\n").format(gpuInfo, timeLine, oneLine)
            )

    @staticmethod
    def printRssInterval():
        # check skip flag #
        if "NORSSSUMMARY" in SysMgr.environList:
            return

        TA = TaskAnalyzer

        # set comm and pid size #
        pd = SysMgr.pidDigit
        cl = 26 - (pd * 2)

        # check memory type #
        if SysMgr.pssEnable:
            mtype = "PSS"
        elif SysMgr.ussEnable:
            mtype = "USS"
        else:
            mtype = "RSS"

        SysMgr.printPipe(
            "\n[Top %s Info] (Unit: MB) (Change: ^)\n%s\n" % (mtype, twoLine)
        )

        if SysMgr.processEnable:
            idName = "PID"
            pidName = "PPID"
        else:
            idName = "TID"
            pidName = "PID"

        # Print menu #
        procInfo = (
            "{0:>{cl}} ({1:>{pd}}/{2:>{pd}}/{3:>4}/{4:>4})|{5:^6} |".format(
                "COMM", idName, pidName, "Nr", "Pri", " Max", cl=cl, pd=pd
            )
        )
        procInfoLen = len(procInfo)
        maxLineLen = SysMgr.lineLength
        margin = 5

        # Print timeline #
        TA.printTimelineInterval(margin, procInfoLen, procInfo, 1)

        # Print total free memory #
        value = TA.procTotData["total"]
        procInfo = (
            "{0:>{cl}} ({1:>{pd}}/{2:>{pd}}/{3:>4}/{4:>4})|{5:>6} |".format(
                "[FREE/MIN]", "-", "-", "-", "-", value["minMem"], cl=cl, pd=pd
            )
        )
        procInfoLen = len(procInfo)
        maxLineLen = SysMgr.lineLength

        timeLine = ""
        lineLen = len(procInfo)
        for idx in xrange(len(TA.procIntData)):
            if lineLen + margin > maxLineLen:
                timeLine += "\n" + (" " * (procInfoLen - 1)) + "| "
                lineLen = len(procInfo)

            if "total" in TA.procIntData[idx]:
                usage = TA.procIntData[idx]["total"]["mem"]
            else:
                usage = 0

            timeLine += "{0:>6} ".format(usage)
            lineLen += 7

        SysMgr.printPipe(
            ("{0:1} {1:1}\n{2:1}\n").format(procInfo, timeLine, oneLine)
        )

        # Print rss of processes #
        for pid, value in sorted(
            TA.procTotData.items(),
            key=lambda e: 0 if not "maxMem" in e[1] else e[1]["maxMem"],
            reverse=True,
        ):

            if pid == "total" or value["maxMem"] == 0:
                continue

            procInfo = (
                "{0:>{cl}} ({1:>{pd}}/{2:>{pd}}/" "{3:>4}/{4:>4})|{5:>6} |"
            ).format(
                value["comm"][:cl],
                pid,
                value["ppid"],
                value["nrThreads"],
                value["pri"],
                value["maxMem"],
                cl=cl,
                pd=pd,
            )
            procInfoLen = len(procInfo)
            maxLineLen = SysMgr.lineLength

            prev = 0
            timeLine = ""
            minRss = maxRss = 0
            lineLen = len(procInfo)
            intData = TA.procIntData
            for idx in xrange(len(intData)):
                if lineLen + margin > maxLineLen:
                    timeLine += "\n" + (" " * (procInfoLen - 1)) + "| "
                    lineLen = len(procInfo)

                # process is shown #
                if pid in intData[idx]:
                    if intData[idx][pid]["die"]:
                        try:
                            usage = intData[idx][pid]["mem"]
                        except:
                            prev = usage = 0
                    else:
                        usage = intData[idx][pid]["mem"]
                        if usage == 0 and prev > 0:
                            usage = prev
                        else:
                            prev = usage
                # process was shown previously #
                elif prev > 0:
                    try:
                        # process was terminated #
                        if intData[idx - 1][pid]["die"]:
                            prev = usage = 0
                        # process is alive #
                        else:
                            usage = prev
                    except:
                        usage = prev
                else:
                    prev = usage = 0

                if usage == 0:
                    pass
                else:
                    if minRss == 0 or minRss > usage:
                        minRss = usage
                    if maxRss == 0 or maxRss < usage:
                        maxRss = usage

                timeLine += "{0:>6} ".format(usage)
                lineLen += 7

            # mark change #
            if maxRss - minRss > 0:
                try:
                    procInfo = procInfo.replace(" (", "^(", 1)
                except:
                    pass

            SysMgr.printPipe(
                "{0:1} {1:1}\n{2:1}\n".format(procInfo, timeLine, oneLine)
            )

    @staticmethod
    def printVssInterval():
        # check skip flag #
        if "NOVSSSUMMARY" in SysMgr.environList:
            return

        TA = TaskAnalyzer

        # set comm and pid size #
        pd = SysMgr.pidDigit
        cl = 26 - (pd * 2)

        SysMgr.printPipe(
            "\n[Top VSS Info] (Unit: MB) (Change: ^)\n%s\n" % twoLine
        )

        if SysMgr.processEnable:
            idName = "PID"
            pidName = "PPID"
        else:
            idName = "TID"
            pidName = "PID"

        # Print menu #
        procInfo = (
            "{0:>{cl}} ({1:>{pd}}/{2:>{pd}}/{3:>4}/{4:>4})|{5:^6} |".format(
                "COMM", idName, pidName, "Nr", "Pri", " Max", cl=cl, pd=pd
            )
        )
        procInfoLen = len(procInfo)
        maxLineLen = SysMgr.lineLength
        margin = 5

        # Print timeline #
        TA.printTimelineInterval(margin, procInfoLen, procInfo, 1)

        # Print total free memory #
        value = TA.procTotData["total"]
        procInfo = (
            "{0:>{cl}} ({1:>{pd}}/{2:>{pd}}/{3:>4}/{4:>4})|{5:>6} |".format(
                "[FREE/MIN]", "-", "-", "-", "-", value["minMem"], cl=cl, pd=pd
            )
        )
        procInfoLen = len(procInfo)
        maxLineLen = SysMgr.lineLength

        timeLine = ""
        lineLen = len(procInfo)
        for idx in xrange(len(TA.procIntData)):
            if lineLen + margin > maxLineLen:
                timeLine += "\n" + (" " * (procInfoLen - 1)) + "| "
                lineLen = len(procInfo)

            if "total" in TA.procIntData[idx]:
                usage = TA.procIntData[idx]["total"]["mem"]
            else:
                usage = 0

            timeLine += "{0:>6} ".format(usage)
            lineLen += 7

        SysMgr.printPipe(
            "{0:1} {1:1}\n{2:1}\n".format(procInfo, timeLine, oneLine)
        )

        # Print vss of processes #
        for pid, value in sorted(
            TA.procTotData.items(),
            key=lambda e: 0 if not "maxVss" in e[1] else e[1]["maxVss"],
            reverse=True,
        ):

            if pid == "total" or value["maxVss"] == 0:
                continue

            procInfo = (
                "{0:>{cl}} ({1:>{pd}}/{2:>{pd}}/" "{3:>4}/{4:>4})|{5:>6} |"
            ).format(
                value["comm"][:cl],
                pid,
                value["ppid"],
                value["nrThreads"],
                value["pri"],
                value["maxVss"],
                cl=cl,
                pd=pd,
            )
            procInfoLen = len(procInfo)
            maxLineLen = SysMgr.lineLength

            prev = 0
            timeLine = ""
            minVss = maxVss = 0
            lineLen = len(procInfo)
            intData = TA.procIntData
            for idx in xrange(len(intData)):
                if lineLen + margin > maxLineLen:
                    timeLine += "\n" + (" " * (procInfoLen - 1)) + "| "
                    lineLen = len(procInfo)

                # process is shown #
                if pid in intData[idx]:
                    if intData[idx][pid]["die"]:
                        try:
                            usage = intData[idx][pid]["vss"]
                        except:
                            prev = usage = 0
                    else:
                        usage = intData[idx][pid]["vss"]
                        if usage == 0 and prev > 0:
                            usage = prev
                        else:
                            prev = usage
                # process was shown previously #
                elif prev > 0:
                    try:
                        # process was terminated #
                        if intData[idx - 1][pid]["die"]:
                            prev = usage = 0
                        # process is alive #
                        else:
                            usage = prev
                    except:
                        usage = prev
                else:
                    prev = usage = 0

                if usage == 0:
                    pass
                else:
                    if minVss == 0 or minVss > usage:
                        minVss = usage
                    if maxVss == 0 or maxVss < usage:
                        maxVss = usage

                timeLine += "{0:>6} ".format(usage)
                lineLen += 7

            # mark change #
            if maxVss - minVss > 0:
                try:
                    procInfo = procInfo.replace(" (", "^(", 1)
                except:
                    pass

            SysMgr.printPipe(
                "{0:1} {1:1}\n{2:1}\n".format(procInfo, timeLine, oneLine)
            )

    @staticmethod
    def printBlkInterval():
        # check skip flag #
        if "NOBLOCKSUMMARY" in SysMgr.environList:
            return

        TA = TaskAnalyzer

        # set comm and pid size #
        pd = SysMgr.pidDigit
        cl = 26 - (pd * 2)

        SysMgr.printPipe("\n[Top Block Info] (Unit: %%)\n%s\n" % twoLine)

        if SysMgr.processEnable:
            idName = "PID"
            pidName = "PPID"
        else:
            idName = "TID"
            pidName = "PID"

        # Print menu #
        procInfo = (
            "{0:>{cl}} ({1:>{pd}}/{2:>{pd}}/{3:>4}/{4:>4})| {5:^5} |".format(
                "COMM", idName, pidName, "Nr", "Pri", " Sum", cl=cl, pd=pd
            )
        )
        procInfoLen = len(procInfo)
        maxLineLen = SysMgr.lineLength
        margin = 5

        # Print timeline #
        TA.printTimelineInterval(margin, procInfoLen, procInfo, 1)

        # Print block usage of processes #
        itemCnt = 0
        for pid, value in sorted(
            TA.procTotData.items(), key=lambda e: e[1]["blk"], reverse=True
        ):

            if (
                pid == "total"
                or value["blk"] == value["blkrd"] == value["blkwr"] == 0
            ):
                continue

            if SysMgr.blockEnable:
                bstat = "%s/%s" % (value["blkrd"], value["blkwr"])
            else:
                bstat = value["blk"]

            procInfo = (
                "{0:>{cl}} ({1:>{pd}}/{2:>{pd}}/" "{3:>4}/{4:>4})| {5:>5} |"
            ).format(
                value["comm"][:cl],
                pid,
                value["ppid"],
                value["nrThreads"],
                value["pri"],
                bstat,
                cl=cl,
                pd=pd,
            )
            procInfoLen = len(procInfo)
            maxLineLen = SysMgr.lineLength

            timeLine = ""
            lineLen = len(procInfo)
            for idx in xrange(len(TA.procIntData)):
                if lineLen + margin > maxLineLen:
                    timeLine += "\n" + (" " * (procInfoLen - 1)) + "| "
                    lineLen = len(procInfo)

                if pid in TA.procIntData[idx]:
                    target = TA.procIntData[idx][pid]
                    if SysMgr.blockEnable:
                        if target["blkrd"] or target["blkwr"]:
                            usage = "%s/%s" % (
                                target["blkrd"],
                                target["blkwr"],
                            )
                        else:
                            usage = 0
                    else:
                        usage = target["blk"]
                else:
                    usage = 0

                timeLine += "{0:>6} ".format(usage)
                lineLen += 7

            SysMgr.printPipe(
                ("{0:1} {1:1}\n{2:1}\n").format(procInfo, timeLine, oneLine)
            )
            itemCnt += 1

        if itemCnt == 0:
            SysMgr.printPipe("\tNone\n%s\n" % oneLine)

    @staticmethod
    def printStorageInterval():
        # check skip flag #
        if "NOSTORAGESUMMARY" in SysMgr.environList:
            return

        TA = TaskAnalyzer

        convSize2Unit = UtilMgr.convSize2Unit

        SysMgr.printPipe("\n[Top Storage Info] (Unit: %%/MB)\n%s\n" % twoLine)

        # Print menu #
        storageInfo = "{0:>16} | {1:^21} |".format(
            "Device", "Busy/Read/Write/Free"
        )
        storageInfoLen = len(storageInfo)
        maxLineLen = SysMgr.lineLength
        margin = 21

        # Print timeline #
        TA.printTimelineInterval(margin, storageInfoLen, storageInfo)

        # Check storage data #
        if "storage" not in TA.procTotData["total"]:
            SysMgr.printPipe("\tNone\n%s\n" % oneLine)
            return

        # Print storage usage #
        for dev, val in TA.procTotData["total"]["storage"].items():
            if dev == "[ TOTAL ]":
                continue

            try:
                total = "%s/%s/%s/%s" % (
                    "%.1f" % (val["busy"] / len(TA.procIntData)),
                    convSize2Unit(val["read"], True),
                    convSize2Unit(val["write"], True),
                    convSize2Unit(val["free"], True),
                )
            except SystemExit:
                sys.exit(0)
            except:
                continue

            storageInfo = "{0:>16} | {1:^21} |".format(dev, total)
            storageInfoLen = len(storageInfo)
            maxLineLen = SysMgr.lineLength

            timeLine = ""
            lineLen = len(storageInfo)
            for idx in xrange(len(TA.procIntData)):
                if lineLen + margin > maxLineLen:
                    timeLine += "\n" + (" " * (storageInfoLen - 1)) + "| "
                    lineLen = len(storageInfo)

                try:
                    stats = TA.procIntData[idx]["total"]["storage"][dev]
                    if (
                        stats["busy"]
                        == stats["read"]
                        == stats["write"]
                        == stats["free"]
                        == 0
                    ):
                        usage = "0"
                    else:
                        usage = "%s/%s/%s/%s" % (
                            stats["busy"],
                            convSize2Unit(stats["read"], True),
                            convSize2Unit(stats["write"], True),
                            convSize2Unit(stats["free"], True),
                        )
                except SystemExit:
                    sys.exit(0)
                except:
                    usage = "0"

                timeLine += "{0:>21} ".format(usage)
                lineLen += margin

            SysMgr.printPipe(
                ("{0:1} {1:1}\n{2:1}\n").format(storageInfo, timeLine, oneLine)
            )

    @staticmethod
    def printNetworkInterval():
        # check skip flag #
        if "NONETSUMMARY" in SysMgr.environList:
            return

        TA = TaskAnalyzer

        convSize2Unit = UtilMgr.convSize2Unit

        SysMgr.printPipe("\n[Top Network Info] (Unit: Byte)\n%s\n" % twoLine)

        # Print menu #
        networkInfo = "{0:>16} | {1:^21} |".format("Device", "In/Out")
        networkInfoLen = len(networkInfo)
        maxLineLen = SysMgr.lineLength
        margin = 21

        # Print timeline #
        TA.printTimelineInterval(margin, networkInfoLen, networkInfo)

        # Check network data #
        if "netdev" not in TA.procTotData["total"]:
            SysMgr.printPipe("\tNone\n%s\n" % oneLine)
            return

        # Print network usage #
        for dev, val in TA.procTotData["total"]["netdev"].items():
            if dev == "[ TOTAL ]":
                continue

            try:
                total = "%s/%s" % (
                    convSize2Unit(val["recv"], True),
                    convSize2Unit(val["tran"], True),
                )
            except:
                continue

            networkInfo = "{0:>16} | {1:^21} |".format(dev, total)
            networkInfoLen = len(networkInfo)
            maxLineLen = SysMgr.lineLength

            timeLine = ""
            lineLen = len(networkInfo)
            for idx in xrange(len(TA.procIntData)):
                if lineLen + margin > maxLineLen:
                    timeLine += "\n" + (" " * (networkInfoLen - 1)) + "| "
                    lineLen = len(networkInfo)

                try:
                    stats = TA.procIntData[idx]["total"]["netdev"][dev]
                    if stats["recv"] == stats["tran"] == 0:
                        usage = "0"
                    else:
                        usage = "%s/%s" % (
                            convSize2Unit(stats["recv"], True),
                            convSize2Unit(stats["tran"], True),
                        )
                except:
                    usage = "0"

                timeLine += "{0:>21} ".format(usage)
                lineLen += margin

            SysMgr.printPipe(
                ("{0:1} {1:1}\n{2:1}\n").format(networkInfo, timeLine, oneLine)
            )

    @staticmethod
    def printTimelineInterval(margin, length, title, more=0):
        timeLine = ""
        lineLen = length
        maxLineLen = SysMgr.lineLength

        if more > 0:
            spaces = more * 2
        else:
            spaces = more

        for i in xrange(1, len(TaskAnalyzer.procIntData) + 1):
            if lineLen + margin > maxLineLen:
                timeLine += "\n" + (" " * (length - 1)) + "| "
                lineLen = length

            timeLine += "{0:>{margin}} ".format(i, margin=margin + more)
            lineLen += margin + spaces

        SysMgr.printPipe(
            ("{0:1} {1:1}\n{2:1}\n").format(title, timeLine, twoLine)
        )

    @staticmethod
    def printCgCpuInterval():
        # check skip flag #
        if "NOCGCPUSUMMARY" in SysMgr.environList:
            return

        TA = TaskAnalyzer

        convSize2Unit = UtilMgr.convSize2Unit

        SysMgr.printPipe("\n[Top Cgroup.CPU Info] (Unit: %%)\n%s\n" % twoLine)

        # Print menu #
        cpuInfo = "{0:<48} | {1:^21} |".format("Cgroup", "Min/Avg/Max/Tot")
        cpuInfoLen = len(cpuInfo)
        margin = 5

        # Print timeline #
        TA.printTimelineInterval(margin, cpuInfoLen, cpuInfo, 1)

        # Check CPU data #
        if "cgroup.cpu" not in TA.procTotData["total"]:
            SysMgr.printPipe("\tNone\n%s\n" % oneLine)
            return

        # Print CPU usage #
        for group, val in sorted(
            TA.procTotData["total"]["cgroup.cpu"].items(),
            key=lambda e: e[1]["usage"],
            reverse=True,
        ):
            total = long(val["usage"])
            minval = long(val["min"])
            maxval = long(val["max"])

            try:
                avg = total / len(TaskAnalyzer.procIntData)
            except:
                avg = 0

            usagestr = "%s/%.1f/%s/%s" % (minval, avg, maxval, total)

            cgroupInfo = "{0:<48} | {1:^21} |".format(group, usagestr)
            cgroupInfoLen = len(cgroupInfo)
            maxLineLen = SysMgr.lineLength

            timeLine = ""
            lineLen = len(cgroupInfo)
            for idx in xrange(len(TA.procIntData)):
                if lineLen + margin > maxLineLen:
                    timeLine += "\n" + (" " * (cgroupInfoLen - 1)) + "| "
                    lineLen = len(cgroupInfo)

                try:
                    usage = TA.procIntData[idx]["total"]["cgroup.cpu"][group]
                except:
                    usage = 0

                timeLine += "{0:>6} ".format(usage)
                lineLen += margin + 2

            SysMgr.printPipe(
                ("{0:1} {1:1}\n{2:1}\n").format(cgroupInfo, timeLine, oneLine)
            )

    @staticmethod
    def printLifeHistory():
        # check skip flag #
        if "NOLIFESUMMARY" in SysMgr.environList:
            return

        TA = TaskAnalyzer

        SysMgr.printPipe("\n[Top Life Info]\n%s\n" % twoLine)

        # set target #
        if SysMgr.processEnable:
            target = "Process"
            parent = "Parent"
        else:
            target = "Thread"
            parent = "Process"

        # Print menu #
        SysMgr.printPipe(
            (
                "{0:^32} | {1:^16} | {2:^16} | {3:^16} | "
                "{4:^32} | {5:^25} |\n{6:1}"
            ).format(
                target, "START", "END", "DURATION", parent, "USER", oneLine
            )
        )

        nrPrint = 0
        procIntData = TaskAnalyzer.procIntData

        # Print times #
        for pid, value in sorted(
            TA.lifeProcData.items(), key=lambda x: long(x[0])
        ):

            # check filter #
            if SysMgr.filterGroup and (
                not UtilMgr.isValidStr(pid)
                and not UtilMgr.isValidStr(value["comm"])
            ):
                continue

            # name #
            name = "%s(%s)" % (value["comm"], pid)

            # start #
            try:
                start = value["START"]
                if start == -2:
                    start = "<-"
                else:
                    start = float(start)
            except SystemExit:
                sys.exit(0)
            except:
                start = "x"

            # end #
            try:
                end = value["FINISH"]
                if end == -2:
                    end = "-"
                elif end == -1:
                    startTime = float(procIntData[0]["time"])
                    end = float(startTime - SysMgr.intervalEnable)
                else:
                    end = float(end)
            except:
                end = "x"

            # duration #
            try:
                duration = "%.1f" % (end - start)
            except:
                duration = " "

            # convert start #
            try:
                start = UtilMgr.convTime(long(start))
            except:
                pass

            # convert end #
            try:
                end = UtilMgr.convTime(long(end))
            except:
                pass

            SysMgr.printPipe(
                (
                    "{0:>32} | {1:>16} | {2:>16} | {3:>16} | "
                    "{4:>32} | {5:>25} |"
                ).format(
                    name, start, end, duration, value["parent"], value["user"]
                )
            )

            nrPrint += 1

        if not nrPrint:
            SysMgr.printPipe("\tNone")

        SysMgr.printPipe("%s\n" % oneLine)

    @staticmethod
    def printCgMemInterval():
        # check skip flag #
        if "NOCGMEMSUMMARY" in SysMgr.environList:
            return

        TA = TaskAnalyzer

        convSize2Unit = UtilMgr.convSize2Unit

        SysMgr.printPipe(
            "\n[Top Cgroup.Mem Info] (Unit: Byte)\n%s\n" % twoLine
        )

        # Print menu #
        memInfo = "{0:<48} | {1:^15} |".format("Cgroup", "Min/Max")
        memInfoLen = len(memInfo)
        margin = 5

        # Print timeline #
        TA.printTimelineInterval(margin, memInfoLen, memInfo, 1)

        # Check Memory data #
        if "cgroup.mem" not in TA.procTotData["total"]:
            SysMgr.printPipe("\tNone\n%s\n" % oneLine)
            return

        # Print Memory usage #
        for group, val in sorted(
            TA.procTotData["total"]["cgroup.mem"].items(),
            key=lambda e: e[1]["max"],
            reverse=True,
        ):
            minval = convSize2Unit(val["min"])
            maxval = convSize2Unit(val["max"])

            usagestr = "%s/%s" % (minval, maxval)

            cgroupInfo = "{0:<48} | {1:^15} |".format(group, usagestr)
            cgroupInfoLen = len(cgroupInfo)
            maxLineLen = SysMgr.lineLength

            timeLine = ""
            lineLen = len(cgroupInfo)
            for idx in xrange(len(TA.procIntData)):
                if lineLen + margin > maxLineLen:
                    timeLine += "\n" + (" " * (cgroupInfoLen - 1)) + "| "
                    lineLen = len(cgroupInfo)

                try:
                    usage = TA.procIntData[idx]["total"]["cgroup.mem"][group]
                    usage = convSize2Unit(usage)
                except:
                    usage = 0

                timeLine += "{0:>6} ".format(usage)
                lineLen += margin + 2

            SysMgr.printPipe(
                ("{0:1} {1:1}\n{2:1}\n").format(cgroupInfo, timeLine, oneLine)
            )

    @staticmethod
    def printIntervalUsage(onlyTotal=False, onlySummary=False):
        def _printMenu(title):
            stars = "*" * long((long(SysMgr.lineLength) - len(title)) / 2)
            SysMgr.printPipe("\n\n\n\n%s%s%s\n\n" % (stars, title, stars))

        # check skip condition #
        try:
            if SysMgr.printFd:
                if (
                    SysMgr.printFd.name == SysMgr.nullPath
                    or SysMgr.outPath == "NUL"
                ):
                    return
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # ftop mode #
        if SysMgr.fileTopEnable:
            TaskAnalyzer.printFileTable()
        # check skip condition #
        elif SysMgr.jsonEnable or SysMgr.dltTopEnable or SysMgr.dbusTopEnable:
            pass
        # top mode #
        else:
            # build summary interval table #
            TaskAnalyzer.summarizeInterval()

            # print interval info #
            TaskAnalyzer.printTimeline()

            if not onlyTotal:
                TaskAnalyzer.printEventInterval()
                TaskAnalyzer.printCpuInterval()
                TaskAnalyzer.printDlyInterval()
                TaskAnalyzer.printGpuInterval()
                TaskAnalyzer.printVssInterval()
                TaskAnalyzer.printRssInterval()
                TaskAnalyzer.printBlkInterval()
                TaskAnalyzer.printStorageInterval()
                TaskAnalyzer.printNetworkInterval()
                TaskAnalyzer.printCgCpuInterval()
                TaskAnalyzer.printCgMemInterval()
                TaskAnalyzer.printLifeHistory()

        # print only summary #
        if onlySummary:
            # print detail for only one tick #
            _printMenu(" Detailed Statistics ")
            SysMgr.printPipe(SysMgr.procBuffer[:1])

            # print lifecycle info #
            if SysMgr.processEnable:
                msg = " Process Lifecycle "
            else:
                msg = " Thread Lifecycle "
            _printMenu(msg)
            TaskAnalyzer.printProcLifecycle()

            # quit #
            return

        # print interval info #
        TaskAnalyzer.printMemAnalysis()

        # print detailed statistics #
        _printMenu(" Detailed Statistics ")
        if not SysMgr.procBuffer:
            SysMgr.printPipe("\n\tNone")
        else:
            SysMgr.printPipe(SysMgr.procBuffer)

        # print lifecycle info #
        if SysMgr.processEnable:
            msg = " Process Lifecycle "
        else:
            msg = " Thread Lifecycle "
        _printMenu(msg)
        TaskAnalyzer.printProcLifecycle()

        # print process tree #
        if SysMgr.processEnable:
            msg = " Process Tree "
        else:
            msg = " Thread Tree "
        _printMenu(msg)
        TaskAnalyzer.printProcTree()

        # print Leak hint #
        _printMenu(" Leak Hint ")
        TaskAnalyzer.printLeakHint()

        # print kernel messages #
        try:
            _printMenu(" Kernel Message ")
            SysMgr.printPipe(LogMgr.getKmsg(SysMgr.kmsgLine))
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("failed to save kernel message", reason=True)

        # initialize parse buffer #
        TaskAnalyzer.lifeIntData = {}
        TaskAnalyzer.lifeProcData = {}
        TaskAnalyzer.lifecycleData = {}
        TaskAnalyzer.procTotData = {}
        TaskAnalyzer.procIntData = []

        # shrink heap #
        SysMgr.shrinkHeap()

    @staticmethod
    def printLeakHint():
        if (
            not SysMgr.isLinux
            or not SysMgr.isTopMode()
            or not SysMgr.topInstance
        ):
            SysMgr.printPipe("\n\tNone")
            return

        convNum = UtilMgr.convNum
        convSize = UtilMgr.convSize2Unit

        for pid in tuple(SysMgr.procInstance):
            path = "%s/%s" % (SysMgr.procPath, pid)
            SysMgr.topInstance.updateOOMScore(path, pid)
            SysMgr.topInstance.saveProcStatusData(path, pid)

        if SysMgr.processEnable:
            pidType = "PID"
            ppidType = "PPID"
        else:
            pidType = "TID"
            ppidType = "PID"

        SysMgr.printPipe(
            (
                "\n{0:1}\n{1:>16}({2:>7}/{3:>7}) "
                "{4:>8} {5:>8} {6:>8} {7:>12} {8:>20}\n{9:^1}\n"
            ).format(
                twoLine,
                "Name",
                pidType,
                ppidType,
                "VSS",
                "RSS",
                "SHM",
                "OOM_SCORE",
                "LifeTime",
                oneLine,
            )
        )

        cnt = 0
        commIdx = SysMgr.topInstance.commIdx
        ppidIdx = SysMgr.topInstance.ppidIdx
        vssIdx = SysMgr.topInstance.vssIdx
        rssIdx = SysMgr.topInstance.rssIdx
        shrIdx = SysMgr.topInstance.shrIdx
        starttimeIdx = SysMgr.topInstance.starttimeIdx

        for pid, val in sorted(
            SysMgr.procInstance.items(),
            key=lambda x: long(x[1]["oomScore"] if "oomScore" in x[1] else 0),
            reverse=True,
        ):
            if "oomScore" not in val or val["oomScore"] == 0:
                break

            # skip sibling threads #
            if not val["isMain"]:
                continue

            stat = val["stat"]
            statm = val["statm"]
            comm = stat[commIdx].strip("()")
            runtime = SysMgr.uptime - (float(val["stat"][starttimeIdx]) / 100)

            if SysMgr.processEnable:
                ppid = stat[ppidIdx]
            else:
                ppid = val["mainID"]

            try:
                vss = convSize(long(stat[vssIdx]))
            except SystemExit:
                sys.exit(0)
            except:
                vss = "-"

            try:
                rss = convSize(long(stat[rssIdx]) << 12)
            except SystemExit:
                sys.exit(0)
            except:
                rss = "-"

            try:
                shm = convSize(long(statm[shrIdx]) << 12)
            except SystemExit:
                sys.exit(0)
            except:
                shm = "-"

            SysMgr.printPipe(
                (
                    "{0:>16}({1:>7}/{2:>7}) "
                    "{3:>8} {4:>8} {5:>8} {6:>12} {7:>20}\n"
                ).format(
                    comm,
                    pid,
                    ppid,
                    vss,
                    rss,
                    shm,
                    convNum(val["oomScore"]),
                    UtilMgr.convTime(runtime),
                )
            )

            cnt += 1

        if cnt == 0:
            SysMgr.printPipe("\tNone\n")

        SysMgr.printPipe(oneLine)

    @staticmethod
    def printProcLifecycle():
        if not TaskAnalyzer.lifecycleData:
            SysMgr.printPipe("\n\tNone")
            return

        SysMgr.printPipe(
            (
                "\n{0:1}\n{1:>16} {2:>15} {3:>15} {4:>15} "
                "{5:>15} {6:>15} {7:>15} {8:>15} {9:>15}\n{10:1}\n"
            ).format(
                twoLine,
                "Name",
                "Created",
                "Terminated",
                "Zombie",
                "Stopped",
                "Traced",
                "Waiting",
                "Waking",
                "Parked",
                oneLine,
            )
        )

        for comm, event in sorted(
            TaskAnalyzer.lifecycleData.items(),
            key=lambda e: e[1][0] + e[1][1],
            reverse=True,
        ):
            if comm == "^START" or comm == "^FINISH":
                continue

            # convert 0 to '-' #
            for idx, value in enumerate(event):
                if value == 0:
                    event[idx] = "-"

            SysMgr.printPipe(
                (
                    "{0:>16} {1:>15} {2:>15} {3:>15} {4:>15} "
                    "{5:>15} {6:>15} {7:>15} {8:>15}\n"
                ).format(
                    comm,
                    event[0],
                    event[1],
                    event[2],
                    event[3],
                    event[4],
                    event[5],
                    event[6],
                    event[7],
                )
            )

        SysMgr.printPipe(oneLine)

    @staticmethod
    def getDescendantList(pids, instance=None):
        taskList = []

        try:
            # convert to list #
            if UtilMgr.isNumber(pids):
                pids = [pids]

            # get minimum pid #
            minPid = min(list(map(long, pids)))

            # convert items to integer #
            pids = list(map(str, pids))
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to convert items to get descendants", reason=True
            )
            return taskList

        # get proc instance #
        if instance:
            obj = instance
        else:
            obj = TaskAnalyzer(onlyInstance=True)

            if SysMgr.isLinux:
                obj.saveSystemStat()
            else:
                obj.saveSystemStatGen()

        # check kernel thread #
        if "2" in pids:
            kernel = True
        else:
            kernel = False

        # get task tree #
        try:
            procTree = TaskAnalyzer.getProcTreeFromList(obj.procData, kernel)
        except SystemExit:
            sys.exit(0)
        except:
            return taskList

        # get nodes in tree #
        def _getTreeNodes(root, pids, enable, taskList):
            initStatus = enable
            for pid, children in sorted(
                root.items(), key=lambda x: long(x[0])
            ):
                enable = initStatus

                if enable:
                    taskList.append(pid)
                elif pid in pids:
                    enable = True

                _getTreeNodes(children, pids, enable, taskList)

        # get descendant list #
        _getTreeNodes(procTree, pids, False, taskList)

        return taskList

    @staticmethod
    def printProcTree(
        instance=None, title=False, printFunc=None, targets=None, color=True
    ):

        if not instance and SysMgr.procInstance:
            instance = SysMgr.procInstance

        if not printFunc:
            printFunc = SysMgr.printPipe

        if not instance:
            printFunc("\n\tNone")
            return

        # define index variables #
        commIdx = ConfigMgr.STAT_ATTR.index("COMM")
        startIdx = ConfigMgr.STAT_ATTR.index("STARTTIME")
        utimeIdx = ConfigMgr.STAT_ATTR.index("UTIME")
        stimeIdx = ConfigMgr.STAT_ATTR.index("STIME")

        # get task tree #
        try:
            procTree = TaskAnalyzer.getProcTreeFromList(instance)
        except SystemExit:
            sys.exit(0)
        except:
            printFunc("\n\tNone")
            return

        # set target #
        if SysMgr.processEnable:
            target = "Process"
        else:
            target = "Thread"

        # get network info #
        try:
            netinfo = " [%s/%s]" % (
                NetworkMgr.getHostName(),
                NetworkMgr.getPublicIp(),
            )
        except SystemExit:
            sys.exit(0)
        except:
            netinfo = ""

        # print title #
        printFunc(
            (
                "\n[%s Tree Info] [Uptime: %s]%s\n%s\n"
                "  %-24s %4s(%11s/%15s) <%s>\n%s"
            )
            % (
                target,
                UtilMgr.convTime(SysMgr.uptime),
                netinfo,
                twoLine,
                "Name(ID)",
                "Per",
                "CPUTIME",
                "RUNTIME",
                "SUB",
                oneLine,
            )
        )

        # print nodes in tree #
        def _printTreeNodes(root, depth, targets, enable):
            treestr = ""

            # check depth #
            if SysMgr.funcDepth > 0 and SysMgr.funcDepth <= depth:
                return treestr

            current = time.time()

            initStatus = enable
            for pid, children in sorted(
                root.items(), key=lambda x: long(x[0])
            ):
                enable = initStatus
                indent = ""

                # get comm #
                try:
                    comm = instance[pid]["comm"]
                    if SysMgr.filterGroup and UtilMgr.isValidStr(
                        comm, ignCap=True
                    ):
                        comm = UtilMgr.convColor(comm, "RED")
                except SystemExit:
                    sys.exit(0)
                except:
                    comm = "?"

                if not enable and targets:
                    if not str(pid) in targets and not UtilMgr.isValidStr(
                        comm, targets
                    ):
                        treestr += _printTreeNodes(
                            children, depth + 1, targets, enable
                        )
                        continue
                    else:
                        enable = True

                # get runtime #
                try:
                    if SysMgr.isLinux:
                        runtime = long(instance[pid]["stat"][startIdx]) / 100
                        runtime = SysMgr.uptime - runtime
                    else:
                        runtime = long(instance[pid]["starttime"])
                        runtime = current - runtime

                    runtimestr = UtilMgr.convTime(runtime, True)
                except SystemExit:
                    sys.exit(0)
                except:
                    runtime = "?"
                    runtimestr = "?"

                # get CPU time #
                try:
                    if SysMgr.isLinux:
                        utime = long(instance[pid]["stat"][utimeIdx])
                        stime = long(instance[pid]["stat"][stimeIdx])
                        ttime = (utime + stime) / 100
                    else:
                        utime = long(instance[pid]["utime"] * 100)
                        stime = long(instance[pid]["stime"] * 100)
                        ttime = utime + stime

                    ttimestr = UtilMgr.convTime(ttime, True)
                    if ttime > 0:
                        ttimestr = UtilMgr.convColor(ttimestr, "YELLOW")
                except SystemExit:
                    sys.exit(0)
                except:
                    ttime = "?"
                    ttimestr = "?"

                # get CPU time by runtime #
                try:
                    # ignore tasks used CPU lesser than 1% #
                    if ttime < 1:
                        raise Exception()

                    cpuPer = round(ttime / float(runtime) * 100, 1)
                    if cpuPer > 0:
                        cpuPer = "%5.1f" % cpuPer
                        cpuPer = UtilMgr.convColor(cpuPer, "GREEN", 5)
                    else:
                        cpuPer = "%5s" % 0
                except SystemExit:
                    sys.exit(0)
                except:
                    cpuPer = "%5s" % 0

                if depth == 0:
                    indent = "\n"

                # make indent #
                for _ in xrange(depth):
                    indent = "%s%s|" % (indent, " " * 5)

                # add proc info #
                procInfo = "%s(%s)" % (comm, pid)
                treestr += "%s- %-22s %3s%%(%s/%s) " % (
                    indent,
                    procInfo,
                    cpuPer,
                    ttimestr,
                    runtimestr,
                )

                # add child info #
                nrChild = len(children)
                if nrChild > 0:
                    treestr += "<%s>" % nrChild

                # add child nodes #
                treestr += "\n%s" % _printTreeNodes(
                    children, depth + 1, targets, enable
                )

            return treestr

        # set initial switch #
        if targets:
            enable = False
        else:
            enable = True

        # set color flag #
        origColor = SysMgr.colorEnable
        if not color and SysMgr.colorEnable:
            SysMgr.colorEnable = False

        # get string for tree #
        finalstr = _printTreeNodes(procTree, 0, targets, enable)
        if not finalstr:
            finalstr = "\tNone"

        # recover color flag #
        SysMgr.colorEnable = origColor

        # print tree #
        printFunc("%s\n%s" % (finalstr.strip("\n"), oneLine))

    @staticmethod
    def printMemAnalysis():
        if not SysMgr.isLinux or not SysMgr.procInstance:
            return

        statList = ConfigMgr.STAT_ATTR

        # set comm and pid size #
        pd = SysMgr.pidDigit
        cl = 26 - (pd * 2)

        SysMgr.printPipe(
            "\n[Top Memory Details] (Unit: MB/KB/NR)\n%s\n" % twoLine
        )

        if SysMgr.processEnable:
            idType = "PID"
            pidType = "PPID"
        else:
            idType = "TID"
            pidType = "PID"

        # Print menu #
        SysMgr.printPipe(
            (
                "{0:^{cl}} ({1:^{pd}}/{2:^{pd}}) | {3:^8} | "
                "{4:^5} | {5:^6} | {6:^6} | {7:^6} | {8:^6} | {9:^6} | "
                "{10:^10} | {11:^12} | {12:^12} | {13:^12} |\n{14}\n"
            ).format(
                "COMM",
                idType,
                pidType,
                "Type",
                "Cnt",
                "VSS/M",
                "RSS/M",
                "PSS/M",
                "SWAP/M",
                "HUGE/M",
                "LOCK/K",
                "PDRT/K",
                "SDRT/K",
                "NOPM/K",
                twoLine,
                cl=cl,
                pd=pd,
            )
        )

        cnt = 1
        limitProcCnt = 6
        commIdx = statList.index("COMM")
        ppidIdx = statList.index("PPID")

        try:
            sortedList = sorted(
                SysMgr.procInstance.items(),
                key=lambda e: long(e[1]["stat"][statList.index("RSS")]),
                reverse=True,
            )
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn(
                "failed to get memory details because of sort error"
            )
            SysMgr.printPipe("\tNone\n%s\n" % oneLine)
            return

        for key, value in sortedList:
            # check filter #
            if SysMgr.filterGroup:
                skip = True
                for item in SysMgr.filterGroup:
                    if key == item or item in value["stat"][commIdx]:
                        skip = False
                        break
                if skip:
                    continue

            # only print memory details of top 4 processes #
            if cnt > limitProcCnt:
                break

            # get memory details #
            value["maps"] = None
            TaskAnalyzer.saveProcSmapsData(value["taskPath"], key)
            if not value["maps"]:
                continue

            cnt += 1

            totalCnt = 0
            totalVmem = 0
            totalRss = 0
            totalPss = 0
            totalSwap = 0
            totalHuge = 0
            totalLock = 0
            totalPdirty = 0
            totalSdirty = 0
            totalRef = 0
            totalNone = 0

            procInfo = " "
            procDetails = ""

            if SysMgr.processEnable:
                ppid = value["stat"][ppidIdx]
            else:
                ppid = value["mainID"]

            for idx, item in sorted(value["maps"].items(), reverse=True):
                if not item:
                    continue

                totalCnt += item["count"]

                try:
                    vmem = item["Size:"] >> 10
                    totalVmem += vmem
                except SystemExit:
                    sys.exit(0)
                except:
                    vmem = 0

                try:
                    rss = item["Rss:"] >> 10
                    totalRss += rss
                except SystemExit:
                    sys.exit(0)
                except:
                    rss = 0

                try:
                    pss = item["Pss:"] >> 10
                    totalPss += pss
                except SystemExit:
                    sys.exit(0)
                except:
                    pss = 0

                try:
                    swap = item["Swap:"] >> 10
                    totalSwap += swap
                except SystemExit:
                    sys.exit(0)
                except:
                    swap = 0

                try:
                    huge = item["AnonHugePages:"] >> 10
                    totalHuge += huge
                except SystemExit:
                    sys.exit(0)
                except:
                    huge = 0

                try:
                    lock = item["Locked:"]
                    totalLock += lock
                except SystemExit:
                    sys.exit(0)
                except:
                    lock = 0

                try:
                    pdirty = item["Private_Dirty:"]
                    totalPdirty += pdirty
                except SystemExit:
                    sys.exit(0)
                except:
                    pdirty = 0

                try:
                    sdirty = item["Shared_Dirty:"]
                    totalSdirty += sdirty
                except SystemExit:
                    sys.exit(0)
                except:
                    sdirty = 0

                try:
                    ref = item["Referenced:"]
                    totalRef += ref
                except SystemExit:
                    sys.exit(0)
                except:
                    ref = 0

                try:
                    none = item["NOPM"]
                    totalNone += none
                except SystemExit:
                    sys.exit(0)
                except:
                    none = 0

                procDetails += (
                    "{0:>30} | {1:>8} | {2:>5} | {3:>6} | "
                    "{4:>6} | {5:>6} | {6:>6} | {7:>6} | {8:>10} | "
                    "{9:>12} | {10:>12} | {11:>12} |\n"
                ).format(
                    procInfo,
                    idx,
                    item["count"],
                    vmem,
                    rss,
                    pss,
                    swap,
                    huge,
                    lock,
                    pdirty,
                    sdirty,
                    none,
                )

            procInfo = "{0:>{cl}} ({1:>{pd}}/{2:>{pd}})".format(
                value["stat"][commIdx].strip("()")[:cl],
                key,
                ppid,
                cl=cl,
                pd=pd,
            )

            SysMgr.printPipe(
                (
                    "{0:>30} | {1:>8} | {2:>5} | {3:>6} | "
                    "{4:>6} | {5:>6} | {6:>6} | {7:>6} | {8:>10} | "
                    "{9:>12} | {10:>12} | {11:>12} |\n{12}"
                ).format(
                    procInfo,
                    "[TOTAL]",
                    totalCnt,
                    totalVmem,
                    totalRss,
                    totalPss,
                    totalSwap,
                    totalHuge,
                    totalLock,
                    totalPdirty,
                    totalSdirty,
                    totalNone,
                    procDetails,
                )
            )

            SysMgr.printPipe("%s\n" % oneLine)

        if cnt == 1:
            SysMgr.printPipe("\tNone\n%s\n" % oneLine)

    @staticmethod
    def getInitTime(fname):
        fd = None

        if SysMgr.isRecordMode():
            compressor = None
        else:
            try:
                fd = open(fname, "rb")
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenErr(fname)
                sys.exit(-1)

            # check compression #
            try:
                if UtilMgr.isCompressed(fd=fd):
                    compressor = SysMgr.getPkg("gzip")
                    fd = compressor.GzipFile(fileobj=fd)
                else:
                    SysMgr.compressEnable = False
                    compressor = None
                    fd.close()
                    fd = None
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.compressEnable = False
                compressor = None
                SysMgr.printErr("failed to decompress for '%s'" % fname, True)

        while 1:
            start = end = -1

            # make delay for some logs not written immediately #
            if SysMgr.isRecordMode():
                try:
                    time.sleep(0.1)
                except:
                    sys.exit(0)

                # check repeat count #
                if SysMgr.progressCnt >= SysMgr.repeatInterval:
                    return 0

            # update fd #
            try:
                if SysMgr.isRecordMode():
                    verb = False
                else:
                    verb = True

                if compressor and fd:
                    if verb:
                        # get output size #
                        fsize = UtilMgr.getFileSizeStr(fname)

                        SysMgr.printStat(
                            r"start checking '%s'%s..." % (fname, fsize)
                        )
                else:
                    try:
                        fd = UtilMgr.getTextLines(
                            fname, verb, retfd=True, load=False
                        )
                    except SystemExit:
                        sys.exit(0)
                    except:
                        SysMgr.printErr(
                            "failed to read '%s'\n" % fname, reason=True
                        )
                        sys.exit(-1)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenErr(fname)
                sys.exit(-1)

            # check decodable load #
            try:
                fd.read(1)
                fd.seek(0)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("failed to read '%s'\n" % fname)
                sys.exit(-1)

            # verify log buffer #
            buf = []
            for idx, line in enumerate(fd):
                # decode line #
                try:
                    line = line.decode("utf-8")
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

                # check system info #
                if end == -1:
                    buf.append(line)
                if not SysMgr.recordStatus:
                    if line.startswith(SysMgr.magicStr):
                        if start == -1:
                            start = idx
                        elif end == -1:
                            end = idx
                            SysMgr.systemInfoBuffer = "".join(
                                buf[start + 1 : end]
                            )
                        continue

                # print-tgid option #
                m = re.match(
                    (
                        r"^\s*(?P<comm>\S+)-(?P<thread>[0-9]+)\s+"
                        r"\(\s*(?P<tgid>\S+)\)\s+\[(?P<core>[0-9]+)\]\s+"
                        r"(?P<time>\S+):\s+(?P<func>\S+):(?P<etc>.+)"
                    ),
                    line,
                )
                if m:
                    d = m.groupdict()
                    SysMgr.startTime = d["time"]
                    return float(d["time"])

                # record-tgid option #
                m = re.match(
                    (
                        r"^\s*(?P<comm>\S+)-(?P<thread>[0-9]+)\s+"
                        r"\[(?P<core>[0-9]+)\]\s+\(\s*(?P<tgid>.+)\)\s+"
                        r"(?P<time>\S+):\s+(?P<func>\S+):(?P<etc>.+)"
                    ),
                    line,
                )
                if m:
                    d = m.groupdict()
                    SysMgr.startTime = d["time"]
                    return float(d["time"])

                # no tgid option #
                m = re.match(
                    (
                        r"^\s*(?P<comm>\S+)-(?P<thread>[0-9]+)\s+"
                        r"\[(?P<core>[0-9]+)\]\s+(?P<time>\S+):\s+"
                        r"(?P<func>\S+):(?P<etc>.+)"
                    ),
                    line,
                )
                if m:
                    d = m.groupdict()
                    SysMgr.tgidEnable = False
                    SysMgr.startTime = d["time"]
                    return float(d["time"])

                # check other mode #
                if line.startswith("[Top "):
                    return 0

            # check record status #
            if SysMgr.isDrawMode():
                return 0
            elif not SysMgr.recordStatus:
                SysMgr.printErr(
                    "failed to read '%s' because there is no log" % fname
                )
                sys.exit(-1)

    def saveBlkOpt(self, tid, comm, opt, major, minor, addr, size):
        def _getBlkOptSize(size):
            idx = size.bit_length() - 1
            return 1 << idx

        def _applyBlkOpt(targetTable, addr, size, blkSize, blkOffset, did):
            # per-device size stat #
            try:
                targetTable[did][0] += size
                targetTable[did][1] += 1

                # sequential operation #
                if targetTable[did][2] == addr:
                    targetTable[did][3] += size
                    targetTable[did][4] += 1

                targetTable[did][2] = blkOffset
            except SystemExit:
                sys.exit(0)
            except:
                sizeTable = {}
                targetTable[did] = [size, 1, blkOffset, size, 1, sizeTable]

            # per-operation size stat #
            try:
                targetTable[did][5][blkSize] += 1
            except:
                targetTable[did][5][blkSize] = 1

        # apply filter #
        if SysMgr.isExceptTarget(tid, self.threadData, comm):
            return

        # total block info #
        readTable = self.blockTable[0]
        writeTable = self.blockTable[1]
        taskTable = self.blockTable[2]
        # [totalSize, totalCnt, lastBlk, seqSize, seqCnt, sizeTable] #

        addr = long(addr)
        size = long(size)

        # get real block size for operation #
        if size > 1:
            blkOffset = addr + (size >> 9)
        else:
            # convert page to real size #
            size = SysMgr.PAGESIZE
            blkOffset = addr + 1

        blkSize = _getBlkOptSize(size)
        origid = did = "%s:%s" % (major, minor)

        # revise real minor number by address #
        mntTree = SysMgr.savedMountTree
        if not did in mntTree or minor == "0":
            for mid, val in mntTree.items():
                try:
                    if did == mid:
                        continue

                    if minor == "0" and did in mntTree:
                        devPath = mntTree[did]["dev"]
                        if (
                            mntTree[mid]["dev"].startswith(devPath)
                            and val["start"] <= addr <= val["end"]
                        ):
                            did = mid
                            break

                    if (
                        mid.split(":")[0] == major
                        and val["start"] <= addr <= val["end"]
                    ):
                        # update device ID #
                        minor = mid.split(":")[1]
                        did = "%s:%s" % (major, minor)
                        break
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

        # map data to total table #
        if opt == "R":
            targetTable = readTable
        elif opt == "W":
            targetTable = writeTable
        else:
            SysMgr.printWarn("failed to recognize block operation '%s'" % opt)
            return

        # apply total block info #
        _applyBlkOpt(targetTable, addr, size, blkSize, blkOffset, did)

        # init task stat #
        if tid not in taskTable:
            taskTable[tid] = [{}, {}, 0]

        # map data to task table #
        if opt == "R":
            targetTable = taskTable[tid][0]
        elif opt == "W":
            targetTable = taskTable[tid][1]
        else:
            SysMgr.printWarn("failed to recognize block operation '%s'" % opt)
            return

        # increase task I/O size #
        taskTable[tid][2] += size

        # apply thread block info #
        _applyBlkOpt(targetTable, addr, size, blkSize, blkOffset, did)

    def handleIntData(self, time):
        if SysMgr.intervalEnable == 0:
            return

        intervalEnable = SysMgr.intervalEnable

        intervalCnt = float(SysMgr.intervalNow + intervalEnable)
        elapsed = float(time) - float(SysMgr.startTime)

        if not elapsed > intervalCnt and self.finishTime == "0":
            return

        SysMgr.intervalNow += intervalEnable

        # check change of all threads #
        for key, value in sorted(
            self.threadData.items(), key=lambda e: e[1]["usage"], reverse=True
        ):
            index = long(SysMgr.intervalNow / intervalEnable) - 1
            nextIndex = long(SysMgr.intervalNow / intervalEnable)

            try:
                self.intData[index]
            except SystemExit:
                sys.exit(0)
            except:
                self.intData.append(dict())

            try:
                self.intData[index]["toTal"]
            except SystemExit:
                sys.exit(0)
            except:
                self.intData[index]["toTal"] = {
                    "totalBr": 0,
                    "totalBw": 0,
                    "totalMem": 0,
                    "totalKmem": 0,
                }

                # make total custom event list #
                if SysMgr.customEventList:
                    self.intData[index]["toTal"]["customEvent"] = {}
                    for evt in SysMgr.customEventList:
                        self.intData[index]["toTal"]["customEvent"][
                            evt
                        ] = dict(self.init_eventData)

                # make user event list #
                if SysMgr.userEventList:
                    self.intData[index]["toTal"]["userEvent"] = {}
                    for evt in SysMgr.userEventList:
                        self.intData[index]["toTal"]["userEvent"][evt] = dict(
                            self.init_eventData
                        )

                # make kernel event list #
                if SysMgr.kernelEventList:
                    self.intData[index]["toTal"]["kernelEvent"] = {}
                    for evt in SysMgr.kernelEventList:
                        self.intData[index]["toTal"]["kernelEvent"][
                            evt
                        ] = dict(self.init_eventData)

            # set thread in this interval #
            self.intData[index].setdefault(key, dict(self.init_intData))

            # define thread alias in this interval #
            curIntval = self.intData[index][key]

            # save start time in this interval #
            curIntval["firstLogTime"] = float(time)

            # make interval list #
            try:
                self.intData[nextIndex]
            except SystemExit:
                sys.exit(0)
            except:
                self.intData.append({})

            # set thread in next interval #
            self.intData[nextIndex].setdefault(key, dict(self.init_intData))

            # define shortcut variable for thread data #
            tdata = self.threadData[key]

            # save total usage in this interval #
            curIntval["totalUsage"] = float(tdata["usage"])
            curIntval["totalPreempted"] = float(tdata["cpuWait"])
            curIntval["totalCoreSchedCnt"] = long(tdata["coreSchedCnt"])
            curIntval["totalBrUsage"] = long(tdata["reqRdBlock"])
            curIntval["totalBwUsage"] = long(tdata["writeBlock"]) + (
                long(tdata["awriteBlock"]) << 3
            )
            curIntval["totalMemUsage"] = long(tdata["nrPages"])
            curIntval["totalKmemUsage"] = long(tdata["remainKmem"])

            # add core time not calculated yet in this interval #
            for idx, val in self.lastTidPerCore.items():
                if self.threadData[val]["lastStatus"] == "S":
                    # apply core off time #
                    coreId = "0[%s]" % idx
                    if self.threadData[coreId]["lastOff"] > 0:
                        diff = float(time) - self.threadData[coreId]["start"]
                        self.threadData[coreId]["usage"] += diff
                        self.intData[index][coreId]["totalUsage"] += diff
                        self.threadData[coreId]["start"] = float(time)
                    continue

                curIntval["totalUsage"] += float(time) - float(
                    self.threadData[val]["start"]
                )

            # mark life flag #
            if tdata["new"] != " ":
                curIntval["new"] = tdata["new"]
            if tdata["die"] != " ":
                curIntval["die"] = tdata["die"]

            # initialize custom event list #
            if SysMgr.customEventList:
                curIntval["customEvent"] = {}
                curIntval["totalCustomEvent"] = {}
                for evt in SysMgr.customEventList:
                    curIntval["customEvent"][evt] = dict(self.init_eventData)
                    curIntval["totalCustomEvent"][evt] = dict(
                        self.init_eventData
                    )
                    try:
                        curIntval["totalCustomEvent"][evt]["count"] = tdata[
                            "customEvent"
                        ][evt]["count"]
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass

            # initialize user event list #
            if SysMgr.userEventList:
                curIntval["userEvent"] = {}
                curIntval["totalUserEvent"] = {}
                for evt in SysMgr.userEventList:
                    curIntval["userEvent"][evt] = dict(self.init_eventData)
                    curIntval["totalUserEvent"][evt] = dict(
                        self.init_eventData
                    )
                    try:
                        curIntval["totalUserEvent"][evt]["count"] = tdata[
                            "userEvent"
                        ][evt]["count"]

                        curIntval["totalUserEvent"][evt]["usage"] = tdata[
                            "userEvent"
                        ][evt]["usage"]
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass

            # initialize kernel event list #
            if SysMgr.kernelEventList:
                curIntval["kernelEvent"] = {}
                curIntval["totalKernelEvent"] = {}
                for evt in SysMgr.kernelEventList:
                    curIntval["kernelEvent"][evt] = dict(self.init_eventData)
                    curIntval["totalKernelEvent"][evt] = dict(
                        self.init_eventData
                    )
                    try:
                        curIntval["totalKernelEvent"][evt]["count"] = tdata[
                            "kernelEvent"
                        ][evt]["count"]

                        curIntval["totalKernelEvent"][evt]["usage"] = tdata[
                            "kernelEvent"
                        ][evt]["usage"]
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass

            # first interval #
            if SysMgr.intervalNow == intervalEnable:
                curIntval["cpuUsage"] = float(tdata["usage"])
                curIntval["preempted"] = float(tdata["cpuWait"])
                curIntval["coreSchedCnt"] = float(tdata["coreSchedCnt"])
                curIntval["brUsage"] = long(tdata["reqRdBlock"])
                curIntval["bwUsage"] = long(tdata["writeBlock"]) + (
                    long(tdata["awriteBlock"]) << 3
                )
                curIntval["memUsage"] = long(tdata["nrPages"])
                curIntval["kmemUsage"] = long(tdata["remainKmem"])

            # later intervals #
            else:
                try:
                    self.intData[index - 1][key]
                except SystemExit:
                    sys.exit(0)
                except:
                    self.intData[index - 1][key] = dict(self.init_intData)

                # define thread alias in previous interval #
                prevIntval = self.intData[index - 1][key]

                # calculate resource usage in this interval #
                curIntval["cpuUsage"] += (
                    curIntval["totalUsage"] - prevIntval["totalUsage"]
                )
                curIntval["preempted"] += (
                    curIntval["totalPreempted"] - prevIntval["totalPreempted"]
                )
                curIntval["coreSchedCnt"] = (
                    curIntval["totalCoreSchedCnt"]
                    - prevIntval["totalCoreSchedCnt"]
                )
                curIntval["brUsage"] = (
                    curIntval["totalBrUsage"] - prevIntval["totalBrUsage"]
                )
                curIntval["bwUsage"] = (
                    curIntval["totalBwUsage"] - prevIntval["totalBwUsage"]
                )
                curIntval["memUsage"] = (
                    curIntval["totalMemUsage"] - prevIntval["totalMemUsage"]
                )
                curIntval["kmemUsage"] = (
                    curIntval["totalKmemUsage"] - prevIntval["totalKmemUsage"]
                )

            # calculate custom event usage in this interval #
            if "totalCustomEvent" in curIntval:
                for evt in list(curIntval["totalCustomEvent"]):
                    try:
                        curIntval["customEvent"][evt]["count"] = (
                            curIntval["totalCustomEvent"][evt]["count"]
                            - prevIntval["totalCustomEvent"][evt]["count"]
                        )
                    except SystemExit:
                        sys.exit(0)
                    except:
                        curIntval["customEvent"][evt]["count"] = curIntval[
                            "totalCustomEvent"
                        ][evt]["count"]

                    self.intData[index]["toTal"]["customEvent"][evt][
                        "count"
                    ] += curIntval["customEvent"][evt]["count"]

            # calculate user event usage in this interval #
            if "totalUserEvent" in curIntval:
                for evt in list(curIntval["totalUserEvent"]):
                    try:
                        curIntval["userEvent"][evt]["count"] = (
                            curIntval["totalUserEvent"][evt]["count"]
                            - prevIntval["totalUserEvent"][evt]["count"]
                        )

                        curIntval["userEvent"][evt]["usage"] = (
                            curIntval["totalUserEvent"][evt]["usage"]
                            - prevIntval["totalUserEvent"][evt]["usage"]
                        )
                    except SystemExit:
                        sys.exit(0)
                    except:
                        curIntval["userEvent"][evt]["count"] = curIntval[
                            "totalUserEvent"
                        ][evt]["count"]

                        curIntval["userEvent"][evt]["usage"] = curIntval[
                            "totalUserEvent"
                        ][evt]["usage"]

                    self.intData[index]["toTal"]["userEvent"][evt][
                        "count"
                    ] += curIntval["userEvent"][evt]["count"]

                    self.intData[index]["toTal"]["userEvent"][evt][
                        "usage"
                    ] += curIntval["userEvent"][evt]["usage"]

            # calculate kernel event usage in this interval #
            if "totalKernelEvent" in curIntval:
                for evt in list(curIntval["totalKernelEvent"]):
                    try:
                        curIntval["kernelEvent"][evt]["count"] = (
                            curIntval["totalKernelEvent"][evt]["count"]
                            - prevIntval["totalKernelEvent"][evt]["count"]
                        )

                        curIntval["kernelEvent"][evt]["usage"] = (
                            curIntval["totalKernelEvent"][evt]["usage"]
                            - prevIntval["totalKernelEvent"][evt]["usage"]
                        )
                    except SystemExit:
                        sys.exit(0)
                    except:
                        curIntval["kernelEvent"][evt]["count"] = curIntval[
                            "totalKernelEvent"
                        ][evt]["count"]

                        curIntval["kernelEvent"][evt]["usage"] = curIntval[
                            "totalKernelEvent"
                        ][evt]["usage"]

                    self.intData[index]["toTal"]["kernelEvent"][evt][
                        "count"
                    ] += curIntval["kernelEvent"][evt]["count"]

                    self.intData[index]["toTal"]["kernelEvent"][evt][
                        "usage"
                    ] += curIntval["kernelEvent"][evt]["usage"]

            # fix CPU usage exceed this interval #
            self.thisInterval = intervalEnable
            if (
                curIntval["cpuUsage"] > intervalEnable
                or self.finishTime != "0"
            ):
                ftime = float(self.intData[index - 1][key]["firstLogTime"])

                # first interval #
                if index == 0:
                    self.thisInterval = float(time) - float(SysMgr.startTime)
                # normal intervals #
                elif ftime > 0:
                    self.thisInterval = float(time) - ftime
                # long time running intervals #
                else:
                    for idx in xrange(index - 1, -1, -1):
                        if ftime > 0:
                            self.thisInterval = float(time) - ftime
                            break
                    if self.thisInterval != intervalEnable:
                        self.thisInterval = float(time) - float(
                            SysMgr.startTime
                        )

                # recalculate previous intervals if no context switching since profile start #
                remainTime = curIntval["cpuUsage"]
                if curIntval["cpuUsage"] > self.thisInterval:
                    for idx in xrange(
                        long(curIntval["cpuUsage"] / intervalEnable), -1, -1
                    ):
                        try:
                            self.intData[idx][key]
                        except SystemExit:
                            sys.exit(0)
                        except:
                            if not idx in self.intData:
                                continue
                            self.intData[idx][key] = dict(self.init_intData)
                        try:
                            self.intData[idx - 1][key]
                        except SystemExit:
                            sys.exit(0)
                        except:
                            if not idx - 1 in self.intData:
                                continue
                            self.intData[idx - 1][key] = dict(
                                self.init_intData
                            )
                        prevIntervalData = self.intData[idx - 1][key]

                        # make previous intervals of core there was no context switching #
                        longRunCore = tdata["longRunCore"]
                        if longRunCore >= 0:
                            longRunCoreId = "0[%s]" % longRunCore
                            try:
                                self.intData[idx][longRunCoreId]
                            except SystemExit:
                                sys.exit(0)
                            except:
                                self.intData[idx][longRunCoreId] = dict(
                                    self.init_intData
                                )

                        if remainTime >= intervalEnable:
                            remainTime = (
                                long(remainTime / intervalEnable)
                                * intervalEnable
                            )
                            prevIntervalData["cpuUsage"] = intervalEnable
                            prevIntervalData["cpuPer"] = 100
                        else:
                            if prevIntervalData["cpuUsage"] > remainTime:
                                remainTime = prevIntervalData["cpuUsage"]
                            else:
                                prevIntervalData["cpuUsage"] = remainTime
                            prevIntervalData["cpuPer"] = (
                                remainTime / intervalEnable * 100
                            )

                        remainTime -= intervalEnable

            # add remainter of CPU usage exceed interval in this interval to previous interval #
            if (
                SysMgr.intervalNow - intervalEnable > 0
                and self.thisInterval > intervalEnable
            ):
                diff = self.thisInterval - intervalEnable
                if prevIntval["cpuUsage"] + diff > intervalEnable:
                    diff = intervalEnable - prevIntval["cpuUsage"]

                prevIntval["cpuUsage"] += diff
                prevIntval["cpuPer"] = (
                    prevIntval["cpuUsage"] / intervalEnable * 100
                )

            # calculate percentage of CPU usage of this thread in this interval #
            if self.thisInterval > 0:
                curIntval["cpuPer"] = (
                    curIntval["cpuUsage"] / self.thisInterval * 100
                )
            else:
                curIntval["cpuPer"] = 0

            # revise thread interval usage in DVFS system #
            if curIntval["cpuPer"] > 100:
                curIntval["cpuPer"] = 100
            elif curIntval["cpuPer"] < 0:
                curIntval["cpuPer"] = 0

            # fix preempted time exceed this interval #
            if (
                curIntval["preempted"] > intervalEnable
                and curIntval["preempted"] > self.thisInterval
            ):
                # recalculate previous intervals if no context switching since profile start #
                remainTime = curIntval["preempted"]
                for idx in xrange(index + 1, -1, -1):
                    try:
                        self.intData[idx][key]
                    except SystemExit:
                        sys.exit(0)
                    except:
                        self.intData[idx][key] = dict(self.init_intData)

                    try:
                        self.intData[idx - 1][key]
                    except SystemExit:
                        sys.exit(0)
                    except:
                        self.intData[idx - 1][key] = dict(self.init_intData)

                    if remainTime >= intervalEnable:
                        self.intData[idx - 1][key][
                            "preempted"
                        ] = intervalEnable
                    else:
                        self.intData[idx - 1][key]["preempted"] += remainTime

                    remainTime -= intervalEnable
                    if remainTime <= 0:
                        break

            # calculate total block usage in this interval #
            self.intData[index]["toTal"]["totalBr"] += self.intData[index][
                key
            ]["brUsage"]
            self.intData[index]["toTal"]["totalBw"] += self.intData[index][
                key
            ]["bwUsage"]

            """
            calculate total memory usage in this interval \
            except for core(swapper) threads because its already calculated
            """
            if key.startswith("0["):
                continue

            self.intData[index]["toTal"]["totalMem"] += self.intData[index][
                key
            ]["memUsage"]
            self.intData[index]["toTal"]["totalKmem"] += self.intData[index][
                key
            ]["kmemUsage"]

    def initThreadData(self):
        self.threadData = {}
        self.irqData = {}
        self.wqData = {}
        self.ioData = {}
        self.reclaimData = {}
        self.pageTable = {}
        self.kmemTable = {}
        self.blockTable = [{}, {}, {}]
        self.fsTable = [{}, {}, {}]
        self.fsData = [[], []]
        self.moduleData = []
        self.intData = []
        self.depData = []
        self.sigData = []
        self.lmkData = []
        self.lockTable = {}
        self.flockData = []
        self.futexData = []
        self.customEventData = []
        self.userEventData = []
        self.kernelEventData = []
        self.syscallData = []
        self.binderData = []
        self.lastJob = {}
        self.preemptData = []
        self.suspendData = []
        self.markData = []
        self.consoleData = []
        self.statData = {}
        self.binderTranData = {}
        self.binderServerData = {}
        self.binderCliData = {}
        self.openData = []

        self.customEventInfo = {}
        self.userEventInfo = {}
        self.kernelEventInfo = {}

        self.customInfo = {}
        self.userInfo = {}
        self.kernelInfo = {}

        self.stopFlag = False
        self.totalTime = 0
        self.totalTimeOld = 0
        self.cxtSwitch = 0
        self.nrNewTask = 0
        self.thisInterval = 0

        self.finishTime = "0"
        self.lastCore = "0"
        self.lastTidPerCore = {}
        self.lastEvent = "0"

        # check custom interval #
        if (
            not "TRIM" in SysMgr.environList
            or hasattr(self, "trimStart")
            or hasattr(self, "trimStop")
        ):
            return

        # set custom interval #
        try:
            start, end = SysMgr.environList["TRIM"][0].split(":")
            if start.strip():
                self.trimStart = float(start.strip())
            if end.strip():
                self.trimStop = float(end.strip())
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to parse TRIM variable", True)
            sys.exit(-1)

    def handleUserEvent(self, event, time):
        # initialize TaskAnalyzer data #
        if event == "START":
            self.initThreadData()

            SysMgr.startTime = time

            # initialize preempt thread list #
            for index in SysMgr.preemptGroup:
                self.preemptData.append([False, {}, 0.0, 0, 0.0])
        # finish data processing #
        elif event == "STOP":
            SysMgr.totalLine = SysMgr.curLine
            self.finishTime = time
            self.stopFlag = True
        # restart data processing #
        elif event == "RESTART":
            # backup data #
            for item in dir(self):
                # skip some objects #
                if (
                    item.startswith("_")
                    or item.startswith("init_")
                    or item.startswith("backupData")
                ):
                    continue

                # skip callable objects #
                obj = getattr(self, item)
                if hasattr(obj, "__call__"):
                    continue

                self.backupData[item] = obj

            self.totalTimeOld = round(float(time) - float(SysMgr.startTime), 7)

            self.initThreadData()

            SysMgr.startTime = time
        # save mark event #
        elif event == "MARK":
            self.markData.append(time)

        # add event #
        EventAnalyzer.addEvent(time, event)

    def addTimelineData(self, group, text, task, state, start, end):
        # convert group id from core to task #
        if "PERTASK" in SysMgr.environList:
            if not task in self.timelineIdx:
                self.timelineIdx[task] = task
            group = self.timelineIdx[task]

        # add timeline data #
        self.timelineData["segments"].append(
            {
                "group": group,
                "text": text,
                "id": task,
                "state": state,
                "time_start": start,
                "time_end": end,
            }
        )

    def parse(self, string):
        def _printEventWarning(func):
            SysMgr.printWarn(
                "failed to recognize '%s' event at line %d"
                % (func, SysMgr.curLine)
            )

        SysMgr.curLine += 1

        m = SysMgr.getTraceItem(string)
        if not m:
            # handle modified type of event #
            m = SysMgr.getTraceItem(string)
            if m:
                d = m.groupdict()
                comm = d["comm"]
                core = str(long(d["core"]))
                func = d["func"]
                etc = d["etc"]
                time = d["time"]

                if "tracing_mark_write" in func:
                    m = re.match(r"^.+EVENT_(?P<event>\S+)", etc)
                    if m:
                        d = m.groupdict()

                        self.handleUserEvent(d["event"], time)
            return

        # get thread info #
        d = m.groupdict()
        comm = d["comm"]
        core = str(long(d["core"]))
        if d["func"][-1] == ":":
            func = d["func"][:-1]
        else:
            func = d["func"]
        etc = d["etc"]
        time = d["time"]
        ftime = float(time)
        stime = float(SysMgr.startTime)
        allTime = ftime - stime

        SysMgr.logSize += len(string)

        # set time for trim #
        if "ABSTIME" in SysMgr.environList:
            checkTime = ftime
        else:
            checkTime = allTime

        # check trim range #
        if (
            hasattr(self, "trimStart")
            and self.trimStart > 0
            and checkTime < self.trimStart
        ):
            return time
        elif (
            hasattr(self, "trimStop")
            and self.trimStop > 0
            and checkTime > self.trimStop
        ):
            return time

        # check skip condition #
        if (
            SysMgr.perCoreList
            and long(core) not in SysMgr.perCoreList
            and (func != "console" and func != "tracing_mark_write")
        ):
            return time
        elif (
            SysMgr.countEnable
            and SysMgr.repeatCount * SysMgr.intervalEnable <= allTime
        ):
            self.stopFlag = True
            return time

        self.lastCore = core
        self.lastEvent = func

        if SysMgr.maxCore < long(core):
            SysMgr.maxCore = long(core)

        # make core ID #
        coreId = "0[%s]" % core
        if long(d["thread"]) == 0:
            thread = coreId
            comm = comm.replace("<idle>", "swapper/" + core)
        else:
            thread = d["thread"]

        # update comm #
        if comm == "<...>":
            if thread in SysMgr.commCache:
                comm = SysMgr.commCache[thread]
            elif thread in self.threadData and self.threadData[thread]["comm"]:
                comm = self.threadData[thread]["comm"]

        # make core thread entity in advance for total irq per core #
        try:
            self.threadData[coreId]
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.nrCore += 1
            self.threadData[coreId] = dict(self.init_threadData)
            self.threadData[coreId]["comm"] = "swapper/%s" % core

        # make thread entity #
        self.threadData.setdefault(thread, dict(self.init_threadData))
        if comm[0] != "<":
            self.threadData[thread]["comm"] = comm

        # update last core #
        self.threadData[thread]["lastCore"] = core

        # define shortcut variable #
        threadData = self.threadData[thread]

        # set tgid #
        tgid = d["tgid"]
        try:
            if tgid == "0" or tgid.startswith("-"):
                raise Exception("no tgid")
            tgid = threadData["tgid"] = tgid
        except:
            try:
                tgid = threadData["tgid"] = SysMgr.savedProcTree[thread]
            except:
                tgid = "N/A"

        # calculate usage of threads had been running longer than periodic interval #
        if SysMgr.intervalEnable > 0:
            for key, value in sorted(self.lastTidPerCore.items()):
                try:
                    coreId = "0[%s]" % key
                    tid = self.lastTidPerCore[key]

                    # check CPU idle status #
                    if self.threadData[coreId]["lastStatus"] == "R":
                        self.threadData[coreId]["usage"] += (
                            ftime - self.threadData[coreId]["start"]
                        )
                        self.threadData[coreId]["start"] = ftime
                        continue

                    # check status of thread running on this core #
                    if self.threadData[tid]["lastStatus"] != "R":
                        continue

                    usage = ftime - float(self.threadData[tid]["start"])
                    if usage > allTime:
                        usage = allTime

                    self.threadData[tid]["usage"] += usage
                    self.threadData[tid]["start"] = ftime
                except SystemExit:
                    sys.exit(0)
                except:
                    continue

        # calculate usage of threads in interval #
        self.handleIntData(time)

        # define flag for special events #
        handleSpecialEvents = False

        if func == "sched_switch":
            m = re.match(
                (
                    r"^\s*prev_comm=(?P<prev_comm>.*)\s+"
                    r"prev_pid=(?P<prev_pid>[0-9]+)\s+"
                    r"prev_prio=(?P<prev_prio>\S+)\s+"
                    r"prev_state=(?P<prev_state>\S+)\s+==>\s+"
                    r"next_comm=(?P<next_comm>.*)\s+"
                    r"next_pid=(?P<next_pid>[0-9]+)\s+"
                    r"next_prio=(?P<next_prio>\S+)"
                ),
                etc,
            )
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            SysMgr.cpuEnable = True

            self.cxtSwitch += 1

            """
            # proc states in TASK_REPORT #
            R: running",      /* 0x00 */
            S: sleeping",     /* 0x01 */
            D: disk sleep",   /* 0x02 */
            T: stopped",      /* 0x04 */
            t: tracing stop", /* 0x08 */
            X: dead",     /* 0x10 */
            Z: zombie",       /* 0x20 */
            P: parked",       /* 0x40 */
            I: idle",     /* 0x80 */

            # kernel states #
            R: Runnable
            S: Sleeping
            D: Uninterruptible Sleep
            T: Stopped
            t: Traced
            X: Exit (Dead)
            Z: Exit (Zombie)
            x: Task Dead
            I: Task Dead
            K: Wake Kill
            W: Waking
            P: Parked
            N: No Load
            +: (Preempted)
            """

            prev_comm = d["prev_comm"]
            prev_pid = d["prev_pid"]
            prev_id = prev_pid

            # update prev comm #
            if prev_comm == "<...>" and prev_id in SysMgr.commCache:
                prev_comm = SysMgr.commCache[prev_id]

            coreId = "0[%s]" % core

            if long(d["prev_pid"]) == 0:
                prev_id = coreId
            else:
                prev_id = prev_pid

            next_comm = d["next_comm"]
            next_pid = d["next_pid"]

            if long(d["next_pid"]) == 0:
                next_id = coreId
            else:
                next_id = next_pid

            # check missed sched data #
            if (
                core in self.lastTidPerCore
                and self.lastTidPerCore[core] != prev_id
            ):
                SysMgr.printWarn(
                    "no context for %s(%s) on Core/%s"
                    % (prev_comm, prev_id, core)
                )
                self.nrSchedLoss += 1

            self.lastTidPerCore[core] = next_id

            # update prev comm #
            if next_comm == "<...>" and next_id in SysMgr.commCache:
                next_comm = SysMgr.commCache[next_id]

            # check CPU wakeup #
            if self.threadData[coreId]["lastOff"] > 0:
                diff = ftime - self.threadData[coreId]["lastOff"]
                self.threadData[coreId]["offTime"] += diff
                self.threadData[coreId]["lastOff"] = 0

            # initialize thread data #
            self.threadData.setdefault(prev_id, dict(self.init_threadData))
            self.threadData.setdefault(next_id, dict(self.init_threadData))

            # initialize core data #
            try:
                self.threadData[coreId]
            except:
                self.threadData[coreId] = dict(self.init_threadData)
                self.threadData[coreId]["comm"] = "swapper/%s" % core

            if (
                self.wakeupData["valid"] > 0
                and self.wakeupData["tid"] == prev_id
            ):
                self.wakeupData["valid"] -= 1

            # update comm #
            self.threadData[prev_id]["comm"] = prev_comm
            self.threadData[next_id]["comm"] = next_comm

            # update anonymous comm #
            if self.threadData[prev_id]["comm"] == "<...>":
                self.threadData[prev_id]["comm"] = prev_comm
            if self.threadData[next_id]["comm"] == "<...>":
                self.threadData[next_id]["comm"] = next_comm

            # update status #
            prev_state = d["prev_state"][0]

            # check event loss #
            if (
                self.threadData[prev_id]["lastStatus"] != "R"
                and self.threadData[coreId]["coreSchedCnt"] > 0
            ):
                self.threadData[prev_id]["start"] = ftime

            # write current time #
            self.threadData[prev_id]["stop"] = ftime
            self.threadData[next_id]["start"] = ftime
            self.threadData[next_id]["waitStartAsParent"] = 0.0

            # define time #
            prev_start = self.threadData[prev_id]["start"]
            prev_stop = self.threadData[prev_id]["stop"]
            next_start = self.threadData[next_id]["start"]
            next_stop = self.threadData[next_id]["stop"]

            # update the CPU scheduling priority for thread to highest one #
            if self.threadData[prev_id]["pri"] == "?" or long(
                self.threadData[prev_id]["pri"]
            ) > long(d["prev_prio"]):
                self.threadData[prev_id]["pri"] = d["prev_prio"]
            if self.threadData[next_id]["pri"] == "?" or long(
                self.threadData[next_id]["pri"]
            ) > long(d["next_prio"]):
                self.threadData[next_id]["pri"] = d["next_prio"]

            # update CPU time by futex #
            if self.threadData[prev_id]["ftxEnter"] > 0:
                fstart = self.threadData[prev_id]["ftxEnter"]

                if prev_start > fstart:
                    tstart = prev_start
                else:
                    tstart = fstart

                fstime = ftime - tstart
                self.threadData[prev_id]["ftxProcess"] += fstime
                self.threadData[prev_id]["ftxBlock"] = ftime
                self.threadData[prev_id]["ftxBlockCnt"] += 1

                opt = "{0:^24}".format("BLOCK")
                otype = "{0:<10}".format("ENT")
                fstime = "%.6f" % fstime
                self.futexData.append(
                    [prev_id, time, core, opt, otype, fstime, "", "", ""]
                )

            # save block time with lock by futex #
            try:
                if self.threadData[prev_id]["futexObj"]:
                    self.threadData[prev_id]["ftxLBlock"] = ftime
                    self.threadData[prev_id]["ftxLSwitch"] += 1

                    # remove previous BLOCK enter event #
                    if self.futexData and self.futexData[-1][1] == time:
                        del self.futexData[-1]

                    opt = "{0:^24}".format("LOCK_BLOCK")
                    otype = "{0:<10}".format("ENT")
                    locks = ", ".join(self.threadData[prev_id]["futexObj"])
                    self.futexData.append(
                        [prev_id, time, core, opt, otype, "", locks, "", ""]
                    )
            except SystemExit:
                sys.exit(0)
            except:
                pass

            # update total block time with lock by futex #
            if self.threadData[next_id]["ftxLBlock"] > 0:
                cstop = self.threadData[next_id]["ftxLBlock"]
                btime = ftime - cstop
                self.threadData[next_id]["ftxLBlockTotal"] += btime
                self.threadData[next_id]["ftxLBlock"] = 0

                opt = "{0:^24}".format("LOCK_BLOCK")
                otype = "{0:>10}".format("RET")
                try:
                    locks = ", ".join(self.threadData[next_id]["futexObj"])
                except:
                    locks = ""
                btime = "%.6f" % btime
                self.futexData.append(
                    [next_id, time, core, opt, otype, btime, locks, "", ""]
                )

            # save block time by futex #
            if self.threadData[next_id]["ftxBlock"] > 0:
                cstop = self.threadData[next_id]["ftxBlock"]
                btime = ftime - cstop
                self.threadData[next_id]["ftxBlockTotal"] += btime
                self.threadData[next_id]["ftxBlock"] = 0

                opt = "{0:^24}".format("BLOCK")
                otype = "{0:>10}".format("RET")
                btime = "%.6f" % btime
                self.futexData.append(
                    [next_id, time, core, opt, otype, btime, "", "", ""]
                )

            # calculate running time of previous thread #
            diff = 0
            if prev_start == 0:
                """calculate runtime of previous thread started
                before starting to profile"""
                if self.threadData[coreId]["coreSchedCnt"] == 0:
                    diff = allTime
                    self.threadData[prev_id]["usage"] = diff
                # it is possible that log was loss #
                else:
                    pass
            else:
                diff = prev_stop - prev_start
                if diff >= 0:
                    self.threadData[prev_id]["usage"] += diff

                    if self.threadData[prev_id]["maxRuntime"] < diff:
                        self.threadData[prev_id]["maxRuntime"] = diff
                else:
                    SysMgr.printWarn(
                        "usage time of %s(%s) is negative(%f) at line %d"
                        % (prev_comm, prev_id, diff, SysMgr.curLine)
                    )

            # add timeline stats #
            isValidStr = UtilMgr.isValidStr
            if not prev_id.startswith("0["):
                # add runtime to list for histogram #
                self.statData.setdefault("runtime", [])
                self.statData["runtime"].append(diff)

                # add timestamps to list for timeline #
                if prev_start == 0:
                    start_delta = 0
                else:
                    start_delta = long((float(prev_start) - stime) * 1000000)

                stop_delta = long((float(prev_stop) - stime) * 1000000)

                # update comm #
                if prev_comm == "<...>":
                    tcomm = "??"
                else:
                    tcomm = prev_comm

                # add timeline data #
                self.addTimelineData(
                    long(core),
                    "%s(%s)" % (tcomm, prev_id),
                    prev_id,
                    prev_state,
                    start_delta,
                    stop_delta,
                )

            if diff > long(SysMgr.intervalEnable):
                self.threadData[prev_id]["longRunCore"] = long(core)

            # update core info #
            self.threadData[coreId]["coreSchedCnt"] += 1
            self.lastTidPerCore[core] = next_id

            # calculate preempted time of threads blocked #
            if SysMgr.preemptGroup:
                for value in SysMgr.preemptGroup:
                    index = SysMgr.preemptGroup.index(value)
                    if (
                        self.preemptData[index][0]
                        and self.preemptData[index][3] == core
                    ):
                        try:
                            self.preemptData[index][1][prev_id]
                        except:
                            self.preemptData[index][1][prev_id] = dict(
                                self.init_preemptData
                            )

                        self.preemptData[index][1][prev_id]["usage"] += diff
                        self.preemptData[index][4] += diff

            # set sched status #
            if prev_state == "R":
                # except for core sched event #
                if prev_id != coreId:
                    self.threadData[prev_id]["preempted"] += 1
                    self.threadData[coreId]["preempted"] += 1

                # except for core sched event #
                if next_id != coreId:
                    self.threadData[next_id]["preemption"] += 1
                    self.threadData[coreId]["preemption"] += 1

                self.threadData[prev_id]["lastStatus"] = "P"

                if SysMgr.preemptGroup:
                    # enable preempted bit #
                    try:
                        index = SysMgr.preemptGroup.index(prev_id)
                    except:
                        index = -1

                    if index >= 0:
                        self.preemptData[index][0] = True
                        try:
                            self.preemptData[index][1][next_id]
                        except:
                            self.preemptData[index][1][next_id] = dict(
                                self.init_preemptData
                            )

                        self.preemptData[index][2] = ftime
                        self.preemptData[index][3] = core

            elif prev_state in ("S", "D", "t", "T", "I", "x", "X", "Z"):
                # increase yield count except for core sched event #
                if prev_id != coreId:
                    self.threadData[prev_id]["yield"] += 1
                    self.threadData[coreId]["yield"] += 1

                # update status #
                if prev_state == "D":
                    self.threadData[prev_id]["lastStatus"] = "D"
                else:
                    self.threadData[prev_id]["stop"] = 0
                    self.threadData[prev_id]["lastStatus"] = "S"

            else:
                self.threadData[prev_id]["stop"] = 0
                self.threadData[prev_id]["lastStatus"] = prev_state

                SysMgr.printWarn(
                    "%s(%s)'s sched state is '%s' at line %d"
                    % (prev_comm, prev_id, prev_state, SysMgr.curLine)
                )

            # calculate sched latency of next thread #
            if (
                not next_id.startswith("0[")
                and self.threadData[next_id]["schedReady"] > 0
            ):
                schedLat = ftime - self.threadData[next_id]["schedReady"]
                self.threadData[next_id]["schedLatency"] += schedLat
                self.threadData[coreId]["schedLatency"] += schedLat
                self.threadData[next_id]["schedReady"] = 0

                self.statData.setdefault("schedlat", [])
                self.statData["schedlat"].append(schedLat)

            # calculate preempted time of next thread #
            if next_stop == 0:
                # no stop time of next thread because of some reasons #
                pass
            # set sched status of next thread #
            elif self.threadData[next_id]["lastStatus"] == "D":
                blockTime = next_start - next_stop
                self.threadData[next_id]["schedBlock"] += blockTime
                self.threadData[coreId]["schedBlock"] += blockTime

                # calculate sched block of next thread #
                if not next_id.startswith("0["):
                    self.statData.setdefault("schedblock", [])
                    self.statData["schedblock"].append(blockTime)

            # set sched status of next thread #
            elif self.threadData[next_id]["lastStatus"] == "P":
                preemptedTime = next_start - next_stop

                if preemptedTime >= 0:
                    self.threadData[next_id]["cpuWait"] += preemptedTime
                else:
                    SysMgr.printWarn(
                        "preempted time of %s(%s) is %f at line %s"
                        % (
                            next_comm,
                            next_id,
                            preemptedTime,
                            UtilMgr.convNum(SysMgr.curLine),
                        )
                    )

                if preemptedTime > self.threadData[next_id]["maxPreempted"]:
                    self.threadData[next_id]["maxPreempted"] = preemptedTime

                try:
                    nextIdx = SysMgr.preemptGroup.index(next_id)
                    self.preemptData[nextIdx][0] = False
                except:
                    pass

                # add preempted time to list for histogram #
                if not next_id.startswith("0["):
                    self.statData.setdefault("prttime", [])
                    self.statData["prttime"].append(preemptedTime)

            self.threadData[next_id]["lastStatus"] = "R"

        elif func == "irq_handler_entry":
            m = re.match(r"^\s*irq=(?P<irq>[0-9]+)\s+name=(?P<name>\S+)", etc)
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            irqId = "irq/%s" % (d["irq"])

            # make irq list #
            try:
                self.irqData[irqId]
            except:
                self.irqData[irqId] = dict(self.init_irqData)
                self.irqData[irqId]["name"] = {}

            self.irqData[irqId]["name"].setdefault(d["name"], 0)

            # make per-thread irq list #
            threadData.setdefault("irqList", {})
            threadData["irqList"].setdefault(irqId, dict(self.init_irqData))
            threadData["irqList"][irqId]["name"] = d["name"]

            # update period per thread #
            if threadData["irqList"][irqId]["start"] > 0:
                diff = ftime - threadData["irqList"][irqId]["start"]
                if (
                    diff > threadData["irqList"][irqId]["maxPeriod"]
                    or threadData["irqList"][irqId]["maxPeriod"] <= 0
                ):
                    threadData["irqList"][irqId]["maxPeriod"] = diff
                if (
                    diff < threadData["irqList"][irqId]["minPeriod"]
                    or threadData["irqList"][irqId]["minPeriod"] <= 0
                ):
                    threadData["irqList"][irqId]["minPeriod"] = diff

            # update period #
            if self.irqData[irqId]["start"] > 0:
                diff = ftime - self.irqData[irqId]["start"]
                if (
                    diff > self.irqData[irqId]["maxPeriod"]
                    or self.irqData[irqId]["maxPeriod"] <= 0
                ):
                    self.irqData[irqId]["maxPeriod"] = diff
                if (
                    diff < self.irqData[irqId]["minPeriod"]
                    or self.irqData[irqId]["minPeriod"] <= 0
                ):
                    self.irqData[irqId]["minPeriod"] = diff

            self.irqData[irqId]["start"] = ftime
            self.irqData[irqId]["count"] += 1
            threadData["irqList"][irqId]["start"] = ftime
            threadData["irqList"][irqId]["count"] += 1

        elif func == "irq_handler_exit":
            m = re.match(r"^\s*irq=(?P<irq>[0-9]+)\s+ret=(?P<return>\S+)", etc)
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            irqId = "irq/%s" % (d["irq"])

            # make list #
            try:
                self.irqData[irqId]
                threadData["irqList"][irqId]
            except:
                return time

            # update usage #
            if threadData["irqList"][irqId]["start"] > 0:
                diff = ftime - threadData["irqList"][irqId]["start"]
                threadData["irqList"][irqId]["usage"] += diff
                threadData["irq"] += diff
                self.irqData[irqId]["usage"] += diff

                # add CPU usage of this thread to core usage #
                if coreId != thread:
                    self.threadData[coreId]["irq"] += diff

                # update period per thread #
                if (
                    diff > threadData["irqList"][irqId]["max"]
                    or threadData["irqList"][irqId]["max"] <= 0
                ):
                    threadData["irqList"][irqId]["max"] = diff
                if (
                    diff < threadData["irqList"][irqId]["min"]
                    or threadData["irqList"][irqId]["min"] <= 0
                ):
                    threadData["irqList"][irqId]["min"] = diff

                threadData["irqList"][irqId]["start"] = 0

            # update period #
            if self.irqData[irqId]["start"] > 0:
                diff = ftime - self.irqData[irqId]["start"]
                if (
                    diff > self.irqData[irqId]["max"]
                    or self.irqData[irqId]["max"] <= 0
                ):
                    self.irqData[irqId]["max"] = diff
                if (
                    diff < self.irqData[irqId]["min"]
                    or self.irqData[irqId]["min"] <= 0
                ):
                    self.irqData[irqId]["min"] = diff

                self.irqData[irqId]["start"] = 0

        elif func == "softirq_entry":
            m = re.match(
                r"^\s*vec=(?P<vector>[0-9]+)\s+\[action=(?P<action>\S+)\]", etc
            )
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            irqId = "softirq/%s" % (d["vector"])

            # make irq list #
            try:
                self.irqData[irqId]
            except:
                self.irqData[irqId] = dict(self.init_irqData)
                self.irqData[irqId]["name"] = {}

            self.irqData[irqId]["name"].setdefault(d["action"], 0)

            # make per-thread irq list #
            try:
                threadData["irqList"][irqId]
            except:
                threadData["irqList"] = {}
            try:
                threadData["irqList"][irqId]
            except:
                threadData["irqList"][irqId] = dict(self.init_irqData)
                threadData["irqList"][irqId]["name"] = d["action"]

            # update period per thread #
            if threadData["irqList"][irqId]["start"] > 0:
                diff = ftime - threadData["irqList"][irqId]["start"]
                if (
                    diff > threadData["irqList"][irqId]["maxPeriod"]
                    or threadData["irqList"][irqId]["maxPeriod"] <= 0
                ):
                    threadData["irqList"][irqId]["maxPeriod"] = diff
                if (
                    diff < threadData["irqList"][irqId]["minPeriod"]
                    or threadData["irqList"][irqId]["minPeriod"] <= 0
                ):
                    threadData["irqList"][irqId]["minPeriod"] = diff

            # update period #
            if self.irqData[irqId]["start"] > 0:
                diff = ftime - self.irqData[irqId]["start"]
                if (
                    diff > self.irqData[irqId]["maxPeriod"]
                    or self.irqData[irqId]["maxPeriod"] <= 0
                ):
                    self.irqData[irqId]["maxPeriod"] = diff
                if (
                    diff < self.irqData[irqId]["minPeriod"]
                    or self.irqData[irqId]["minPeriod"] <= 0
                ):
                    self.irqData[irqId]["minPeriod"] = diff

            self.irqData[irqId]["start"] = ftime
            self.irqData[irqId]["count"] += 1
            threadData["irqList"][irqId]["start"] = ftime
            threadData["irqList"][irqId]["count"] += 1

        elif func == "softirq_exit":
            m = re.match(
                r"^\s*vec=(?P<vector>[0-9]+)\s+\[action=(?P<action>\S+)\]", etc
            )
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            irqId = "softirq/%s" % (d["vector"])

            # make list #
            try:
                self.irqData[irqId]
                threadData["irqList"][irqId]
            except:
                return time

            # update usage #
            if threadData["irqList"][irqId]["start"] > 0:
                diff = ftime - threadData["irqList"][irqId]["start"]
                threadData["irqList"][irqId]["usage"] += diff
                threadData["irq"] += diff
                self.irqData[irqId]["usage"] += diff

                # add CPU usage of this thread to core usage #
                if coreId != thread:
                    self.threadData[coreId]["irq"] += diff

                # update period per thread #
                if (
                    diff > threadData["irqList"][irqId]["max"]
                    or threadData["irqList"][irqId]["max"] <= 0
                ):
                    threadData["irqList"][irqId]["max"] = diff
                if (
                    diff < threadData["irqList"][irqId]["min"]
                    or threadData["irqList"][irqId]["min"] <= 0
                ):
                    threadData["irqList"][irqId]["min"] = diff

                threadData["irqList"][irqId]["start"] = 0

            # update period #
            if self.irqData[irqId]["start"] > 0:
                diff = ftime - self.irqData[irqId]["start"]
                if (
                    diff > self.irqData[irqId]["max"]
                    or self.irqData[irqId]["max"] <= 0
                ):
                    self.irqData[irqId]["max"] = diff
                if (
                    diff < self.irqData[irqId]["min"]
                    or self.irqData[irqId]["min"] <= 0
                ):
                    self.irqData[irqId]["min"] = diff

                self.irqData[irqId]["start"] = 0

        elif func == "sched_migrate_task":
            m = re.match(
                (
                    r"^\s*comm=(?P<comm>.*)\s+pid=(?P<pid>[0-9]+)\s+"
                    r"prio=(?P<prio>[0-9]+)\s+orig_cpu=(?P<orig_cpu>[0-9]+)\s+"
                    r"dest_cpu=(?P<dest_cpu>[0-9]+)"
                ),
                etc,
            )
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            pid = d["pid"]

            self.threadData.setdefault(pid, dict(self.init_threadData))
            self.threadData[pid]["comm"] = d["comm"]
            self.threadData[pid]["migrate"] += 1

            self.threadData.setdefault(coreId, dict(self.init_threadData))
            self.threadData[coreId]["migrate"] += 1

            # update core data for preempted info #
            if SysMgr.preemptGroup:
                try:
                    index = SysMgr.preemptGroup.index(thread)
                except:
                    index = -1

                if index >= 0:
                    self.preemptData[index][3] = core

        elif func == "mm_page_alloc":
            m = re.match(
                (
                    r"^\s*page=\s*(?P<page>\S+)\s+pfn=(?P<pfn>[0-9]+)\s+"
                    r"order=(?P<order>[0-9]+)\s+"
                    r"migratetype=(?P<mt>[0-9]+)\s+gfp_flags=(?P<flags>\S+)"
                ),
                etc,
            )
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            SysMgr.memEnable = True

            # check whether it is huge page #
            if d["page"] == "(null)":
                page = "huge"
            else:
                page = d["page"]

            pfn = long(d["pfn"])
            flags = d["flags"]
            order = long(d["order"])
            nr = pow(2, order)

            # register page order #
            threadData.setdefault("orderPages", {})
            threadData["orderPages"].setdefault(order, 0)
            threadData["orderPages"][order] += 1
            self.allocPageData.setdefault(order, 0)
            self.allocPageData[order] += 1

            # accumulate pages allocated #
            threadData["nrAllocPages"] += nr
            self.threadData[coreId]["nrAllocPages"] += nr
            threadData["nrPages"] += nr
            self.threadData[coreId]["nrPages"] += nr

            if "NOFS" in flags or "GFP_WRITE" in flags or "0x1000000" in flags:
                pageType = "CACHE"
                threadData["cachePages"] += nr
                self.threadData[coreId]["cachePages"] += nr
            elif "USER" in flags:
                pageType = "USER"
                threadData["userPages"] += nr
                self.threadData[coreId]["userPages"] += nr
            else:
                pageType = "KERNEL"
                threadData["kernelPages"] += nr
                self.threadData[coreId]["kernelPages"] += nr

            # make PTE in page table #
            for cnt in xrange(nr):
                pfnv = pfn + cnt

                try:
                    # this allocated page is not freed #
                    if self.pageTable[pfnv] == {}:
                        raise Exception("double page allocation")
                    else:
                        threadData["nrPages"] -= 1
                        self.threadData[coreId]["nrPages"] -= 1
                except:
                    self.pageTable[pfnv] = dict(self.init_pageData)

                self.pageTable[pfnv]["tid"] = thread
                self.pageTable[pfnv]["page"] = page
                self.pageTable[pfnv]["flags"] = flags
                self.pageTable[pfnv]["type"] = pageType
                self.pageTable[pfnv]["time"] = time

        elif func == "mm_page_free" or func == "mm_page_free_direct":
            m = re.match(
                (
                    r"^\s*page=(?P<page>\S+)\s+pfn=(?P<pfn>[0-9]+)"
                    r"\s+order=(?P<order>[0-9]+)"
                ),
                etc,
            )
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            SysMgr.memEnable = True

            page = d["page"]
            pfn = long(d["pfn"])
            order = long(d["order"])
            nr = pow(2, order)

            for cnt in xrange(nr):
                pfnv = pfn + cnt

                try:
                    owner = self.pageTable[pfnv]["tid"]
                    self.threadData[owner]["nrPages"] -= 1
                    self.threadData[coreId]["nrPages"] -= 1

                    if thread != owner:
                        self.threadData[owner]["reclaimedPages"] += 1
                        self.threadData[coreId]["reclaimedPages"] += 1

                    if self.pageTable[pfnv]["type"] == "CACHE":
                        self.threadData[owner]["cachePages"] -= 1
                        self.threadData[coreId]["cachePages"] -= 1
                    elif self.pageTable[pfnv]["type"] == "USER":
                        self.threadData[owner]["userPages"] -= 1
                        self.threadData[coreId]["userPages"] -= 1
                    elif self.pageTable[pfnv]["type"] == "KERNEL":
                        self.threadData[owner]["kernelPages"] -= 1
                        self.threadData[coreId]["kernelPages"] -= 1

                    self.pageTable.pop(pfnv)
                except:
                    # this page is allocated before starting profile #
                    threadData["anonReclaimedPages"] += 1
                    self.threadData[coreId]["anonReclaimedPages"] += 1

        elif func == "mm_filemap_delete_from_page_cache":
            m = re.match(
                (
                    r"^\s*dev (?P<major>[0-9]+):(?P<minor>[0-9]+) .+"
                    r"page=(?P<page>\S+)\s+pfn=(?P<pfn>[0-9]+)"
                ),
                etc,
            )
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            SysMgr.memEnable = True

            pfn = long(d["pfn"])

            try:
                owner = self.pageTable[pfn]["tid"]

                # attribute of page is changed to file #
                if self.pageTable[pfn]["type"] == "USER":
                    self.threadData[owner]["userPages"] -= 1
                    self.threadData[coreId]["userPages"] -= 1
                    self.threadData[owner]["cachePages"] += 1
                    self.threadData[coreId]["cachePages"] += 1
                elif self.pageTable[pfn]["type"] == "KERNEL":
                    self.threadData[owner]["kernelPages"] -= 1
                    self.threadData[coreId]["kernelPages"] -= 1
                    self.threadData[owner]["cachePages"] += 1
                    self.threadData[coreId]["cachePages"] += 1

                self.pageTable[pfn]["type"] = "CACHE"
            except:
                return time

        elif func == "kmalloc":
            m = re.match(
                (
                    r"^\s*call_site=(?P<caller>\S+).*ptr=(?P<ptr>\S+)\s+"
                    r"bytes_req=(?P<req>[0-9]+)\s+"
                    r"bytes_alloc=(?P<alloc>[0-9]+)\s+"
                    r"gfp_flags=(?P<flags>\S+)"
                ),
                etc,
            )
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            SysMgr.memEnable = True

            caller = d["caller"]
            ptr = d["ptr"]
            req = long(d["req"])
            alloc = long(d["alloc"])

            self.kmemTable.setdefault(ptr, dict(self.init_kmallocData))

            self.kmemTable[ptr]["tid"] = thread
            self.kmemTable[ptr]["caller"] = caller
            self.kmemTable[ptr]["req"] = req
            self.kmemTable[ptr]["alloc"] = alloc
            self.kmemTable[ptr]["waste"] = alloc - req
            self.kmemTable[ptr]["core"] = coreId

            threadData["remainKmem"] += alloc
            threadData["wasteKmem"] += alloc - req
            self.threadData[coreId]["remainKmem"] += alloc
            self.threadData[coreId]["wasteKmem"] += alloc - req

        elif func == "kfree":
            m = re.match(
                r"^\s*call_site=(?P<caller>\S+)\s+ptr=\s*(?P<ptr>\S+)", etc
            )
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            SysMgr.memEnable = True

            caller = d["caller"]
            ptr = d["ptr"]

            try:
                pageObj = self.kmemTable[ptr]
                self.threadData[pageObj["tid"]]["remainKmem"] -= pageObj[
                    "alloc"
                ]

                self.threadData[pageObj["core"]]["remainKmem"] -= pageObj[
                    "alloc"
                ]

                self.threadData[pageObj["tid"]]["wasteKmem"] -= pageObj[
                    "waste"
                ]

                self.threadData[pageObj["core"]]["wasteKmem"] -= pageObj[
                    "waste"
                ]

                self.kmemTable.pop(ptr)
            except:
                """
                this allocated object is not logged or \
                this object is allocated before starting profile
                """
                return time

        elif func == "sched_wakeup" or func == "sched_wakeup_new":
            m = re.match(
                (
                    r"^\s*comm=(?P<comm>.*)\s+pid=(?P<pid>[0-9]+)\s+"
                    r"prio=(?P<prio>[0-9]+)\s+"
                ),
                etc,
            )
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            target_comm = d["comm"]
            pid = d["pid"]

            # update prev comm #
            if target_comm == "<...>" and pid in SysMgr.commCache:
                target_comm = SysMgr.commCache[pid]

            # skip self-wakeup #
            if thread == pid:
                return time

            self.threadData.setdefault(pid, dict(self.init_threadData))
            self.threadData[pid]["comm"] = target_comm
            self.threadData[pid]["schedReady"] = ftime

            if self.wakeupData["tid"] == "0":
                self.wakeupData["time"] = allTime
            elif thread[0] == "0" or pid == "0":
                return time
            elif self.wakeupData["valid"] > 0 and (
                self.wakeupData["from"] != self.wakeupData["tid"]
                or self.wakeupData["to"] != pid
            ):
                if (
                    self.wakeupData["valid"] == 1
                    and self.wakeupData["corrupt"] == "0"
                ):
                    try:
                        kicker = self.threadData[self.wakeupData["tid"]][
                            "comm"
                        ]
                    except:
                        kicker = "NULL"

                    kicker_pid = self.wakeupData["tid"]
                else:
                    kicker = threadData["comm"]
                    kicker_pid = thread

                ntime = round(allTime, 7)
                self.depData.append(
                    "\t%.3f/%.3f \t%40s(%7s) -> %40s(%7s) \t%s"
                    % (
                        ntime,
                        round(ntime - float(self.wakeupData["time"]), 7),
                        kicker,
                        kicker_pid,
                        target_comm,
                        pid,
                        "kick",
                    )
                )

                self.wakeupData["time"] = allTime
                self.wakeupData["from"] = self.wakeupData["tid"]
                self.wakeupData["to"] = pid

        elif func == "do_sys_open":
            m = re.match(r'^\s*"(?P<path>.*)" (?P<flags>.+) (?P<mode>.+)', etc)
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            self.openData.append(
                [allTime, thread, d["path"], d["flags"], d["mode"]]
            )

        elif func == "sys_enter":
            m = re.match(r"^\s*NR (?P<nr>[0-9]+) (?P<args>.+)", etc)
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            nr = long(d["nr"])
            nrstr = str(nr)
            args = d["args"]
            td = threadData

            # update futex lock stat #
            if nr == SysMgr.getNrSyscall("sys_futex"):
                n = re.match(
                    (
                        r"^\s*(?P<uaddr>\S+), (?P<op>\S+), "
                        r"(?P<val>\S+), (?P<timer>\S+),"
                    ),
                    d["args"],
                )
                if n:
                    l = n.groupdict()

                    FUTEX_CMD_MASK = ~(128 | 256)
                    # FUTEX_PRIVATE_FLAG: 128, FUTEX_CLOCK_REALTIME: 256 #
                    maskedOp = long(l["op"], base=16) & FUTEX_CMD_MASK

                    addr = l["uaddr"][1:]
                    flist = ConfigMgr.FUTEX_TYPE

                    try:
                        op = flist[maskedOp]
                    except:
                        op = l["op"]

                    # check recursive entry caused by log loss #
                    if td["ftxEnter"] > 0:
                        SysMgr.printWarn(
                            (
                                "failed to find return of %s for thread %s "
                                "at %s\n\tso report the results "
                                "may differ from actual"
                            )
                            % (td["ftxEnt"], thread, SysMgr.curLine)
                        )

                    # futex operation #
                    td["ftxEnt"] = op

                    # futex object address #
                    td["futexCandObj"] = addr

                    # try to lock #
                    if maskedOp == flist.index(
                        "FUTEX_LOCK_PI"
                    ) or maskedOp == flist.index("FUTEX_TRYLOCK_PI"):
                        td["ftxStat"] = "L"
                        td["ftxLockCnt"] += 1

                        # remove already unlocked futex #
                        try:
                            td["futexObj"].pop(addr, None)
                        except:
                            pass
                    # wait #
                    elif (
                        maskedOp == flist.index("FUTEX_WAIT")
                        or maskedOp == flist.index("FUTEX_WAIT_REQUEUE_PI")
                        or maskedOp == flist.index("FUTEX_WAIT_BITSET")
                    ):
                        td["ftxStat"] = "W"
                        td["ftxWaitCnt"] += 1
                    # try to unlock #
                    elif maskedOp == flist.index("FUTEX_UNLOCK_PI"):
                        td["ftxStat"] = "U"
                    else:
                        td["ftxStat"] = "?"

                    td["ftxEnter"] = ftime
                    otype = "{0:<10}".format("ENT")
                    self.futexData.append(
                        [
                            thread,
                            time,
                            core,
                            op,
                            otype,
                            "",
                            addr,
                            l["val"],
                            l["timer"],
                        ]
                    )

            if self.wakeupData["tid"] == "0":
                self.wakeupData["time"] = allTime

            # write syscall #
            if nr == SysMgr.getNrSyscall("sys_write"):
                self.wakeupData["tid"] = thread
                self.wakeupData["nr"] = nrstr
                self.wakeupData["args"] = args

                if not (
                    self.wakeupData["valid"] > 0
                    and (
                        self.wakeupData["tid"] == thread
                        and self.wakeupData["from"] == comm
                    )
                ):
                    self.wakeupData["valid"] += 1

                    if self.wakeupData["valid"] > 1:
                        self.wakeupData["corrupt"] = "1"
                    else:
                        self.wakeupData["corrupt"] = "0"

            # register syscall #
            try:
                td["syscallInfo"]
            except:
                td["syscallInfo"] = {}
            try:
                td["syscallInfo"][nrstr]
            except:
                td["syscallInfo"][nrstr] = dict(self.init_syscallInfo)

            # save syscall info #
            td["nrSyscall"] += 1
            td["lastNrSyscall"] = nr
            td["syscallInfo"][nrstr]["count"] += 1
            td["syscallInfo"][nrstr]["last"] = ftime

            # save syscall history #
            if SysMgr.syscallList:
                try:
                    idx = SysMgr.syscallList.index(nr)

                    self.syscallData.append(
                        ["ENT", time, thread, core, nrstr, args]
                    )
                except SystemExit:
                    sys.exit(0)
                except:
                    pass
            else:
                self.syscallData.append(
                    ["ENT", time, thread, core, nrstr, args]
                )

        elif func == "sys_exit":
            m = re.match(r"^\s*NR (?P<nr>\S+) = (?P<ret>.+)", etc)
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            nr = long(d["nr"])
            nrstr = str(nr)
            ret = d["ret"]
            td = threadData

            # handle wrong syscall number #
            if nr < 0 and td["lastNrSyscall"] >= 0:
                nr = td["lastNrSyscall"]

            # update futex lock stat #
            if nr == SysMgr.getNrSyscall("sys_futex"):
                lockEnter = td["ftxEnter"]
                lockStat = td["ftxStat"]

                # futex call status #
                if lockEnter > 0:
                    # elapsed time #
                    futexTime = ftime - lockEnter

                    if futexTime > td["ftxMax"]:
                        td["ftxMax"] = futexTime

                    td["ftxTotal"] += futexTime
                    td["ftxEnter"] = 0

                    # update CPU time by futex #
                    if td["start"] > lockEnter:
                        ctime = ftime - td["start"]
                        td["ftxProcess"] += ctime
                    elif td["ftxBlock"] == 0 and td["ftxLBlock"] == 0:
                        ctime = ftime - lockEnter
                        td["ftxProcess"] += ctime

                    # handle lock object #
                    if (lockStat == "L" or lockStat == "U") and ret[0] == "0":
                        # target object #
                        try:
                            candObj = td["futexCandObj"]
                        except:
                            candObj = None

                        # lock context #
                        if lockStat == "L":
                            # register lock object #
                            try:
                                td["futexObj"][candObj] = ftime
                            except:
                                td["futexObj"] = {}
                                td["futexObj"][candObj] = ftime
                        # unlock context #
                        elif lockStat == "U":
                            # remove lock object #
                            try:
                                lockStart = td["futexObj"][candObj]
                                td["futexObj"].pop(candObj, None)
                            except:
                                lockStart = 0

                            # calculate lock time #
                            if lockStart > 0:
                                ltime = ftime - lockStart
                                td["ftxLock"] += ltime
                                if td["ftxLockMax"] < ltime:
                                    td["ftxLockMax"] = ltime

                    futexTime = "%.6f" % futexTime
                else:
                    td["ftxStat"] = "?"
                    futexTime = ""

                if td["ftxEnt"]:
                    op = td["ftxEnt"]
                    td["ftxEnt"] = None
                else:
                    op = ""

                otype = "{0:>10}".format("RET")

                # add futex data #
                self.futexData.append(
                    [
                        thread,
                        time,
                        core,
                        op,
                        otype,
                        futexTime,
                        "",
                        d["ret"],
                        "",
                    ]
                )

            try:
                if not SysMgr.depEnable:
                    raise Exception("skip dependency analysis")
                elif (
                    nr == SysMgr.getNrSyscall("sys_write")
                    and self.wakeupData["valid"] > 0
                ):
                    self.wakeupData["valid"] -= 1
                elif SysMgr.arch != "aarch64" and (
                    nr == SysMgr.getNrSyscall("sys_poll")
                    or nr == SysMgr.getNrSyscall("sys_select")
                    or nr == SysMgr.getNrSyscall("sys_epoll_wait")
                ):
                    if (
                        self.lastJob[core]["job"] == "sched_switch"
                        or self.lastJob[core]["job"] == "sched_wakeup"
                        or self.lastJob[core]["job"] == "sched_wakeup_new"
                    ) and self.lastJob[core]["prevWakeupTid"] != thread:
                        ttime = allTime
                        itime = ttime - float(self.wakeupData["time"])
                        self.depData.append(
                            "\t%.3f/%.3f \t%40s %7s     %40s(%7s) \t%s"
                            % (
                                round(ttime, 7),
                                round(itime, 7),
                                " ",
                                " ",
                                td["comm"],
                                thread,
                                "wakeup",
                            )
                        )

                        self.wakeupData["time"] = allTime
                        self.lastJob[core]["prevWakeupTid"] = thread
                elif (
                    (
                        SysMgr.arch == "arm"
                        and nr == SysMgr.getNrSyscall("sys_recv")
                    )
                    or nr == SysMgr.getNrSyscall("sys_recvfrom")
                    or nr == SysMgr.getNrSyscall("sys_recvmsg")
                    or nr == SysMgr.getNrSyscall("sys_recvmmsg")
                ):
                    if self.lastJob[core]["prevWakeupTid"] != thread:
                        ttime = allTime
                        itime = ttime - float(self.wakeupData["time"])
                        self.depData.append(
                            "\t%.3f/%.3f \t%40s %7s     %40s(%7s) \t%s"
                            % (
                                round(ttime, 7),
                                round(itime, 7),
                                " ",
                                " ",
                                td["comm"],
                                thread,
                                "recv",
                            )
                        )

                        self.wakeupData["time"] = allTime
                        self.lastJob[core]["prevWakeupTid"] = thread
            except SystemExit:
                sys.exit(0)
            except:
                pass

            # register syscall #
            try:
                td["syscallInfo"]
            except:
                td["syscallInfo"] = {}
            try:
                td["syscallInfo"][nrstr]
            except:
                td["syscallInfo"][nrstr] = dict(self.init_syscallInfo)

            # save syscall usage #
            diff = ""
            hasTimeline = True
            sysItem = td["syscallInfo"][nrstr]
            if "NOSYSCALL" in SysMgr.environList:
                hasTimeline = False
            elif sysItem["last"] > 0:
                start_delta = long((float(sysItem["last"]) - stime) * 1000000)
                stop_delta = long((float(ftime) - stime) * 1000000)

                try:
                    text = "%s(%s)_%s" % (comm, thread, ConfigMgr.sysList[nr])
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printWarn("wrong syscall number %s" % nr)
                    return time
            else:
                # start_delta = 0
                stop_delta = long((float(ftime) - stime) * 1000000)
                start_delta = long((float(ftime) - stime) * 1000000)
                text = "%s(%s)_%s" % (comm, thread, ConfigMgr.sysList[nr])

            # add timeline data #
            if hasTimeline:
                self.addTimelineData(
                    long(core),
                    text,
                    thread,
                    "SYSCALL",
                    start_delta,
                    stop_delta,
                )

            # update syscall stat #
            if sysItem["last"] > 0:
                diff = ftime - sysItem["last"]
                td["syscallInfo"][nrstr]["usage"] += diff
                td["syscallInfo"][nrstr]["last"] = 0

                if sysItem["max"] == 0 or sysItem["max"] < diff:
                    td["syscallInfo"][nrstr]["max"] = diff
                if sysItem["min"] <= 0 or sysItem["min"] > diff:
                    td["syscallInfo"][nrstr]["min"] = diff

                if ret[0] == "-":
                    td["syscallInfo"][nrstr]["err"] += 1

            # save syscall history #
            if SysMgr.syscallList:
                try:
                    self.syscallData.append(
                        ["RET", time, thread, core, nrstr, ret, diff]
                    )
                except:
                    pass
            else:
                self.syscallData.append(
                    ["RET", time, thread, core, nrstr, ret, diff]
                )

        elif func == "signal_generate":
            m = re.match(
                (
                    r"^\s*sig=(?P<sig>[0-9]+) errno=(?P<err>[0-9]+) "
                    r"code=(?P<code>.*) comm=(?P<comm>.*) "
                    r"pid=(?P<pid>[0-9]+)"
                ),
                etc,
            )
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            sig = d["sig"]
            target_comm = d["comm"]
            pid = d["pid"]
            ttime = allTime

            # update prev comm #
            if target_comm == "<...>" and pid in SysMgr.commCache:
                target_comm = SysMgr.commCache[pid]

            self.depData.append(
                "\t%.3f/%.3f \t%40s(%7s) -> %40s(%7s) \t%s(%s)"
                % (
                    round(ttime, 7),
                    round(ttime - float(self.wakeupData["time"]), 7),
                    threadData["comm"],
                    thread,
                    target_comm,
                    pid,
                    "sigsend",
                    sig,
                )
            )

            self.sigData.append(("SEND", ttime, thread, pid, sig))

            self.wakeupData["time"] = ttime

            try:
                # SIGCHLD #
                std = self.threadData[pid]
                if sig == str(signal.SIGCHLD):
                    if std["waitStartAsParent"] > 0:
                        if std["waitPid"] == 0 or std["waitPid"] == long(
                            thread
                        ):
                            diff = ftime - std["waitStartAsParent"]
                            threadData["waitParent"] = diff
                            std["waitChild"] += diff
                elif sig == str(signal.SIGSEGV):
                    std["die"] = "F"
            except:
                return time

        elif func == "signal_deliver":
            m = re.match(
                (
                    r"^\s*sig=(?P<sig>[0-9]+) errno=(?P<err>[0-9]+) "
                    r"code=(?P<code>.*) sa_handler=(?P<handler>.*) "
                    r"sa_flags=(?P<flags>.*)"
                ),
                etc,
            )
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            sig = d["sig"]
            flags = d["flags"]

            ttime = allTime
            itime = ttime - float(self.wakeupData["time"])
            self.depData.append(
                "\t%.3f/%.3f \t%40s %7s     %40s(%7s) \t%s(%s)"
                % (
                    round(ttime, 7),
                    round(itime, 7),
                    "",
                    "",
                    threadData["comm"],
                    thread,
                    "sigrecv",
                    sig,
                )
            )

            self.sigData.append(("RECV", ttime, None, thread, sig))

            self.wakeupData["time"] = ttime

        elif func == "block_bio_queue" or func == "block_bio_remap":
            m = re.match(
                (
                    r"^\s*(?P<major>[0-9]+),(?P<minor>[0-9]+)\s*"
                    r"(?P<operation>\S+)\s*(?P<address>\S+)\s+\+\s+"
                    r"(?P<size>[0-9]+)"
                ),
                etc,
            )
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            SysMgr.blockEnable = True

            opt = d["operation"]
            bio = "%s/%s/%s/%s" % (
                d["major"],
                d["minor"],
                d["operation"][0],
                d["address"],
            )
            bsize = long(d["size"])

            # skip redundant operation #
            if func == "block_bio_queue" and bio in self.ioData:
                return time

            self.ioData[bio] = {
                "thread": thread,
                "time": ftime,
                "major": d["major"],
                "minor": d["minor"],
                "address": long(d["address"]),
                "size": bsize,
            }

            self.saveBlkOpt(
                thread,
                comm,
                opt[0],
                d["major"],
                d["minor"],
                d["address"],
                SysMgr.blockSize * bsize,
            )

            # read operations #
            if opt[0] == "R":
                threadData["reqRdBlock"] += bsize
                threadData["readQueueCnt"] += 1
                threadData["readBlockCnt"] += 1
                threadData["blkCore"] = coreId
                self.threadData[coreId]["readBlockCnt"] += 1

                if threadData["readStart"] == 0:
                    threadData["readStart"] = ftime
            # synchronous write operation #
            elif opt == "WS":
                threadData["reqWrBlock"] += bsize
                threadData["writeQueueCnt"] += 1
                threadData["writeBlockCnt"] += 1
                threadData["blkCore"] = coreId
                self.threadData[coreId]["writeBlockCnt"] += 1

                if threadData["writeStart"] == 0:
                    threadData["writeStart"] = ftime

        elif func == "block_rq_complete":
            m = re.match(
                (
                    r"^\s*(?P<major>[0-9]+),(?P<minor>[0-9]+)\s*"
                    r"(?P<operation>\S+)\s*\(.*\)\s*(?P<address>\S+)\s+\+\s+"
                    r"(?P<size>[0-9]+)"
                ),
                etc,
            )
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            address = d["address"]
            size = d["size"]
            opt = d["operation"]

            bio = "%s/%s/%s/%s" % (
                d["major"],
                d["minor"],
                opt[0],
                d["address"],
            )

            bioStart = long(address)
            bioEnd = long(address) + long(size)

            for key, request in sorted(
                self.ioData.items(),
                key=lambda e: e[1]["address"],
                reverse=False,
            ):

                # skip different requests with device number #
                if (
                    request["major"] != d["major"]
                    or request["minor"] != d["minor"]
                ):
                    continue

                rBioEnd = request["address"] + request["size"]

                # skip irrelevant requests #
                if not (
                    bioStart <= request["address"] < bioEnd
                    or bioStart < rBioEnd <= bioEnd
                ):
                    continue

                # remove bio request in table #
                self.ioData.pop(key, None)

                matchBlock = 0

                if bioStart < request["address"]:
                    matchStart = request["address"]
                else:
                    matchStart = bioStart

                if bioEnd > rBioEnd:
                    matchEnd = rBioEnd
                else:
                    matchEnd = bioEnd

                # simple case #
                if matchStart == request["address"]:
                    matchBlock = matchEnd - request["address"]
                    request["size"] = rBioEnd - matchEnd
                    request["address"] = matchEnd

                    if request["size"] > 0:
                        try:
                            mbio = "%s/%s/%s/%s" % (
                                request["major"],
                                request["minor"],
                                opt[0],
                                request["address"] + request["size"],
                            )

                            request["size"] += self.ioData[mbio]["size"]

                            # remove bio request in table #
                            self.ioData.pop(mbio, None)
                        except:
                            pass

                        # recreate partial ioData uncompleted #
                        bio = "%s/%s/%s/%s" % (
                            request["major"],
                            request["minor"],
                            opt[0],
                            request["address"],
                        )
                        self.ioData[bio] = request
                # complex case #
                elif matchStart > request["address"]:
                    if matchEnd == request["address"] + request["size"]:
                        matchBlock = matchEnd - matchStart
                        request["size"] = matchStart - request["address"]

                        # recreate partial ioData uncompleted #
                        bio = "%s/%s/%s/%s" % (
                            request["major"],
                            request["minor"],
                            opt[0],
                            request["address"],
                        )
                        self.ioData[bio] = request
                    else:
                        continue
                else:
                    continue

                # just ignore error ;( #
                if bioEnd < request["address"] + request["size"]:
                    pass

                reqThd = request["thread"]
                tcomm = self.threadData[reqThd]["comm"]
                lastCore = long(self.threadData[reqThd]["lastCore"])

                # READ #
                if opt[0] == "R":
                    self.threadData[reqThd]["readBlock"] += matchBlock
                    self.threadData[coreId]["readBlock"] += matchBlock

                    if request["size"] != 0:
                        continue

                    if self.threadData[reqThd]["readQueueCnt"] > 0:
                        self.threadData[reqThd]["readQueueCnt"] -= 1

                    """
                    if error of size and time of block read is big then \
                    consider inserting below conditions
                    # self.threadData[reqThd]['readQueueCnt'] == 0 #
                    """
                    if self.threadData[reqThd]["readStart"] > 0:
                        startTime = self.threadData[reqThd]["readStart"]
                        waitTime = ftime - startTime
                        self.threadData[coreId]["ioRdWait"] += waitTime
                        self.threadData[reqThd]["ioRdWait"] += waitTime
                        self.threadData[reqThd]["readStart"] = 0
                        workload = UtilMgr.convSize2Unit(
                            matchBlock * SysMgr.blockSize, True
                        )

                        start_delta = long(
                            (float(startTime) - stime) * 1000000
                        )
                        stop_delta = long((float(ftime) - stime) * 1000000)
                        text = "%s(%s) | RD[%s]" % (tcomm, reqThd, workload)

                        # add timeline data #
                        self.addTimelineData(
                            long(lastCore),
                            text,
                            reqThd,
                            "RD",
                            start_delta,
                            stop_delta,
                        )

                # WRITE #
                elif opt == "WS":
                    self.threadData[reqThd]["writeBlock"] += matchBlock
                    self.threadData[coreId]["writeBlock"] += matchBlock

                    if thread != reqThd or request["size"] != 0:
                        continue

                    if self.threadData[reqThd]["writeQueueCnt"] > 0:
                        self.threadData[reqThd]["writeQueueCnt"] -= 1

                    """
                    if error of size and time of block read is big then \
                    consider inserting below conditions
                    # self.threadData[reqThd]['writeQueueCnt'] == 0 #
                    """
                    if self.threadData[reqThd]["writeStart"] > 0:
                        startTime = self.threadData[reqThd]["writeStart"]
                        waitTime = ftime - startTime
                        self.threadData[coreId]["ioWrWait"] += waitTime
                        self.threadData[reqThd]["ioWrWait"] += waitTime
                        self.threadData[reqThd]["writeStart"] = 0
                        workload = UtilMgr.convSize2Unit(
                            matchBlock * SysMgr.blockSize, True
                        )

                        start_delta = long(
                            (float(startTime) - stime) * 1000000
                        )
                        stop_delta = long((float(ftime) - stime) * 1000000)
                        text = "%s(%s) | WR[%s]" % (tcomm, reqThd, workload)

                        # add timeline data #
                        self.addTimelineData(
                            long(lastCore),
                            text,
                            reqThd,
                            "WR",
                            start_delta,
                            stop_delta,
                        )

        elif func == "mm_filemap_add_to_page_cache":
            m = re.match(
                (
                    r"^\s*dev\s+(?P<major>[0-9]+):(?P<minor>[0-9]+)\s*"
                    r"ino (?P<ino>\S+)\s+page=(?P<page>.+)\s+"
                    r"pfn=(?P<pfn>.+)\s+ofs=(?P<ofs>.+)"
                ),
                etc,
            )
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            SysMgr.blockEnable = True

            inode = str(long(d["ino"], 16))
            did = "%s:%s" % (d["major"], d["minor"])
            ofs = long(d["ofs"])
            ops = "READ"

            # total read #
            self.fsTable[0].setdefault(ops, {})
            self.fsTable[0][ops].setdefault(did, {})
            self.fsTable[0][ops][did].setdefault(inode, 0)
            self.fsTable[0][ops][did][inode] += 1

            # thread read #
            self.fsTable[1].setdefault(thread, {})
            self.fsTable[1][thread].setdefault(ops, {})
            self.fsTable[1][thread][ops].setdefault(did, {})
            self.fsTable[1][thread][ops][did].setdefault(inode, 0)
            self.fsTable[1][thread][ops][did][inode] += 1

            # thread total #
            self.fsTable[2].setdefault(thread, 0)
            self.fsTable[2][thread] += 1

            # add history #
            if SysMgr.showAll or "RALIST" in SysMgr.environList:
                access = "%.3f" % allTime

                # merge with previous event #
                if self.fsData[0]:
                    lastData = self.fsData[0][-1]
                    if (
                        lastData[0] == thread
                        and lastData[1] == access
                        and lastData[2] == did
                        and lastData[3] == inode
                        and lastData[4] + lastData[5] == ofs
                    ):
                        lastData[5] += SysMgr.PAGESIZE
                        return time

                # append new event #
                self.fsData[0].append(
                    [thread, access, did, inode, ofs, SysMgr.PAGESIZE]
                )

        elif func == "writeback_dirty_page":
            m = re.match(
                (
                    r"^\s*bdi\s+(?P<major>[0-9]+):(?P<minor>[0-9]+):\s*"
                    r"ino=(?P<ino>\S+)\s+index=(?P<index>\S+)"
                ),
                etc,
            )
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            SysMgr.blockEnable = True

            inode = d["ino"]
            idx = d["index"]
            did = "%s:%s" % (d["major"], d["minor"])
            bid = inode + idx
            ops = "WRITE"

            threadData["awriteBlock"] += 1
            threadData["awriteBlockCnt"] += 1
            self.threadData[coreId]["awriteBlock"] += 1
            self.threadData[coreId]["awriteBlockCnt"] += 1

            # total write #
            self.fsTable[0].setdefault(ops, {})
            self.fsTable[0][ops].setdefault(did, {})
            self.fsTable[0][ops][did].setdefault(inode, 0)
            self.fsTable[0][ops][did][inode] += 1

            # thread write #
            self.fsTable[1].setdefault(thread, {})
            self.fsTable[1][thread].setdefault(ops, {})
            self.fsTable[1][thread][ops].setdefault(did, {})
            self.fsTable[1][thread][ops][did].setdefault(inode, 0)
            self.fsTable[1][thread][ops][did][inode] += 1

            # thread total #
            self.fsTable[2].setdefault(thread, 0)
            self.fsTable[2][thread] += 1

            self.saveBlkOpt(thread, comm, "W", d["major"], d["minor"], bid, 1)

        elif func == "wbc_writepage":
            m = re.match(
                (
                    r"^\s*bdi\s+(?P<major>[0-9]+):(?P<minor>[0-9]+):\s*"
                    r"towrt=(?P<towrt>\S+)\s+skip=(?P<skip>\S+)"
                ),
                etc,
            )
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            if d["skip"] == "0":
                SysMgr.blockEnable = True

                threadData["awriteBlock"] += 1
                threadData["awriteBlockCnt"] += 1
                self.threadData[coreId]["awriteBlock"] += 1
                self.threadData[coreId]["awriteBlockCnt"] += 1

                self.saveBlkOpt(
                    thread, comm, "W", d["major"], d["minor"], d["towrt"], 1
                )

        elif func == "mm_vmscan_wakeup_kswapd":
            try:
                self.reclaimData[thread]
            except:
                self.reclaimData[thread] = {"start": 0.0}

            if self.reclaimData[thread]["start"] <= 0:
                self.reclaimData[thread]["start"] = ftime

            threadData["reclaimCnt"] += 1

        elif func == "mm_vmscan_kswapd_sleep":
            popList = []

            for key, value in self.reclaimData.items():
                self.threadData.setdefault(key, dict(self.init_threadData))
                self.threadData[key]["comm"] = comm

                self.threadData[key]["reclaimWait"] += ftime - float(
                    value["start"]
                )

                popList.append(key)

            for key in popList:
                self.reclaimData.pop(key, None)

        elif func == "mm_vmscan_direct_reclaim_begin":
            if threadData["dReclaimStart"] <= 0:
                threadData["dReclaimStart"] = ftime

            threadData["dReclaimCnt"] += 1
            self.threadData[coreId]["dReclaimCnt"] += 1

        elif func == "mm_vmscan_direct_reclaim_end":
            m = re.match(r"^\s*nr_reclaimed=(?P<nr>[0-9]+)", etc)
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            if threadData["dReclaimStart"] > 0:
                threadData["dReclaimWait"] += (
                    ftime - threadData["dReclaimStart"]
                )
                self.threadData[coreId]["dReclaimWait"] += (
                    ftime - threadData["dReclaimStart"]
                )

            threadData["dReclaimStart"] = 0

        elif func == "lowmemory_kill":
            m = re.match(
                (
                    r"^\s*(?P<comm>.+) \((?P<pid>[0-9]+)\), "
                    r"page cache (?P<other_file>.+) \(limit (?P<minfree>.+)\), "
                    r"free (?P<other_free>.+)"
                ),
                etc,
            )
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            """
            other_free: NR_FREE_PAGES - totalreserve_pages
            other_file: NR_FILE_PAGES - NR_SHMEM
            minfree: threshold condition (other_free < minfree && other_file < minfree)
            """

            convNum = UtilMgr.convNum
            other_free = convNum(d["other_free"].upper().rstrip("KB"))
            other_file = convNum(d["other_file"].upper().rstrip("KB"))
            minfree = convNum(d["minfree"].upper().rstrip("KB"))

            self.lmkData.append(
                [time, d["comm"], d["pid"], other_free, other_file, minfree]
            )

        elif func == "task_newtask":
            m = re.match(r"^\s*pid=(?P<pid>[0-9]+)\s+comm=(?P<comm>\S+)", etc)
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            pid = d["pid"]

            try:
                data = self.threadData[pid]
                SysMgr.printWarn(
                    (
                        "failed to handle a new task %s(%s) "
                        "because it is already exist"
                    )
                    % (data["comm"], pid)
                )
            except SystemExit:
                sys.exit(0)
            except:
                self.threadData[pid] = dict(self.init_threadData)
                self.threadData[pid]["comm"] = d["comm"]
                self.threadData[pid]["ptid"] = thread
                self.threadData[pid]["new"] = "N"
                self.threadData[pid]["createdTime"] = ftime

                if not threadData["childList"]:
                    threadData["childList"] = []

                threadData["childList"].append(pid)
                self.nrNewTask += 1

        elif func == "sched_process_fork":
            m = re.match(
                (
                    r"^\s*comm=(?P<comm>.*)\s+pid=(?P<pid>[0-9]+)\s+"
                    r"child_comm=(?P<child_comm>.*)\s+"
                    r"child_pid=(?P<child_pid>[0-9]+)"
                ),
                etc,
            )
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            cpid = d["child_pid"]
            ccomm = d["child_comm"]

            if not cpid in self.threadData:
                self.threadData[cpid] = dict(self.init_threadData)
                self.threadData[cpid]["comm"] = ccomm
                self.threadData[cpid]["ptid"] = thread
                self.threadData[cpid]["new"] = "N"
                self.threadData[cpid]["createdTime"] = ftime

                if not threadData["childList"]:
                    threadData["childList"] = []

                threadData["childList"].append(cpid)
                self.nrNewTask += 1

        elif func == "task_rename":
            m = re.match(
                (
                    r"^\s*pid=(?P<pid>[0-9]+)\s+oldcomm=(?P<oldcomm>.*)\s+"
                    r"newcomm=(?P<newcomm>.*)\s+oom_score_adj"
                ),
                etc,
            )
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            pid = d["pid"]
            newcomm = d["newcomm"]

            try:
                self.threadData[pid]
            except:
                self.threadData[pid] = dict(self.init_threadData)
                self.threadData[pid]["comm"] = newcomm
                self.threadData[pid]["ptid"] = thread

            self.threadData[pid]["comm"] = newcomm

        elif func == "locks_get_lock_context":
            m = re.match(
                (
                    r"^\s*dev=(?P<dev>.+)\s+ino=(?P<ino>.+)"
                    r"\s+type=(?P<type>.+)\s+ctx=(?P<ctx>.+)"
                ),
                etc,
            )
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            fid = "%s%s" % (d["dev"], d["ino"])
            ltype = d["type"]
            ctx = d["ctx"]

            # save lock data #
            self.flockData.append([thread, time, core, ltype, fid, ctx])

            # unlock #
            if ltype == "F_UNLCK":
                try:
                    if self.lockTable[fid]["owner"] == thread:
                        threadData["lockTime"] += (
                            ftime - self.lockTable[fid]["time"]
                        )
                        threadData["lockCnt"] += 1
                except:
                    self.lockTable[fid] = {}
                    threadData["lockCnt"] += 1

                # initialize lock data #
                self.lockTable[fid]["owner"] = None
                self.lockTable[fid]["time"] = 0
                self.lockTable[fid]["type"] = None
            # try to lock #
            else:
                threadData["tryLockCnt"] += 1

                try:
                    # get lock #
                    if not self.lockTable[fid]["owner"]:
                        self.lockTable[fid]["owner"] = thread
                        self.lockTable[fid]["time"] = ftime
                        self.lockTable[fid]["type"] = ltype
                        threadData["lastLockTime"] = ftime

                        # add wait time to get lock #
                        if threadData["lastLockWait"] > 0:
                            llw = threadData["lastLockWait"]
                            threadData["lockWait"] += ftime - llw

                            threadData["lastLockWait"] = 0
                    # wait lock #
                    else:
                        # add wait time to get lock #
                        if threadData["lastLockWait"] > 0:
                            llw = threadData["lastLockWait"]
                            threadData["lockWait"] += ftime - llw

                        threadData["lastLockWait"] = ftime
                except:
                    # no lock #
                    self.lockTable[fid] = {}
                    self.lockTable[fid]["owner"] = thread
                    self.lockTable[fid]["time"] = ftime
                    self.lockTable[fid]["type"] = ltype
                    threadData["lastLockTime"] = ftime

        elif func == "sched_process_exit":
            m = re.match(r"^\s*comm=(?P<comm>.*)\s+pid=(?P<pid>[0-9]+)", etc)
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            pid = d["pid"]

            try:
                self.threadData[pid]
            except:
                self.threadData[pid] = dict(self.init_threadData)
                self.threadData[pid]["comm"] = d["comm"]
                self.threadData[pid]["die"] = "D"

            if self.threadData[pid]["die"] != "F":
                self.threadData[pid]["die"] = "D"

        elif func == "sched_process_wait":
            m = re.match(r"^\s*comm=(?P<comm>.*)\s+pid=(?P<pid>[0-9]+)", etc)
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            threadData["waitStartAsParent"] = ftime
            threadData["waitPid"] = long(d["pid"])

        elif func == "suspend_resume":
            SysMgr.powerEnable = True

            state = None

            if "suspend_enter" in etc and "begin" in etc:
                state = "S"
            elif "machine_suspend" in etc and "end" in etc:
                state = "F"
            # Complete a PM transition for all non-sysdev devices #
            elif "dpm_resume_user" in etc and "end" in etc:
                state = "R"

            if state:
                self.suspendData.append([time, state])

        elif func == "net_dev_xmit":
            m = re.match(
                (
                    r"^\s*dev=(?P<dev>.*)\s+skbaddr=(?P<addr>.*)"
                    r"\s+len=(?P<len>.*)\s+rc=(?P<rc>.*)"
                ),
                etc,
            )
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

        elif func == "module_load":
            m = re.match(r"^\s*(?P<module>.*)\s+(?P<address>.*)", etc)
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            module = d["module"]
            address = d["address"]

            self.moduleData.append(["load", thread, time, module, address])

        elif func == "module_free":
            m = re.match(r"^\s*(?P<module>.*)", etc)
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            module = d["module"]

            self.moduleData.append(["free", thread, time, module, None])

        elif func == "module_put":
            m = re.match(
                (
                    r"^\s*(?P<module>.*)\s+call_site=(?P<site>.*)\s+"
                    r"refcnt=(?P<refcnt>[0-9]+)"
                ),
                etc,
            )
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            module = d["module"]
            refcnt = long(d["refcnt"])

            self.moduleData.append(["put", thread, time, module, refcnt])

        elif func == "module_get":
            m = re.match(
                (
                    r"^\s*(?P<module>.*)\s+call_site=(?P<site>.*)\s+"
                    r"refcnt=(?P<refcnt>[0-9]+)"
                ),
                etc,
            )
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            module = d["module"]
            refcnt = long(d["refcnt"])

            self.moduleData.append(["get", thread, time, module, refcnt])

        elif func == "binder_transaction_received":
            m = re.match(r"^\s*transaction=(?P<tranid>[0-9]+)", etc)
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            tranid = d["tranid"]
            if tranid in self.binderTranData:
                self.threadData[thread]["binderTranId"] = tranid

        elif func == "binder_transaction":
            m = re.match(
                (
                    r"^\s*transaction=(?P<tranid>[0-9]+)\s+"
                    r"dest_node=(?P<dnode>[0-9]+)\s+"
                    r"dest_proc=(?P<dproc>[0-9]+)\s+"
                    r"dest_thread=(?P<dthread>[0-9]+)\s+"
                    r"reply=(?P<reply>[0-9]+)\s+"
                    r"flags=(?P<flags>.*)\s+"
                    r"code=(?P<code>.*)"
                ),
                etc,
            )
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            # get info #
            commCache = SysMgr.commCache
            tranid = d["tranid"]
            reply = d["reply"]
            flags = d["flags"]
            code = d["code"]

            # convert index string to number for method #
            try:
                code = long(code, 16)
            except:
                code = code

            # convert flags string to number for call type #
            try:
                oneway = 0
                flags = long(flags, 16)
                oneway = 0x1 & flags
                flags = hex(flags)
            except:
                pass

            # sender thread #
            sthr = "%s(%s)" % (comm, thread)

            # sender process #
            if tgid in SysMgr.commCache:
                sproc = "%s(%s)" % (commCache[tgid], tgid)
            else:
                sproc = "??(%s)" % tgid

            # sender #
            if sthr == sproc:
                sender = sthr
            else:
                sender = "%s@%s" % (sthr, sproc)

            # receiver thread #
            dthread = d["dthread"]
            if dthread == "0":
                rthr = ""
            elif dthread in SysMgr.commCache:
                rthr = "%s(%s)" % (commCache[dthread], dthread)
            else:
                rthr = "??(%s)" % dthread

            # receiver process #
            dproc = d["dproc"]
            if dproc in SysMgr.commCache:
                rproc = "%s(%s)" % (commCache[dproc], dproc)
            else:
                rproc = "??(%s)" % dproc

            # receiver #
            if rthr == rproc:
                receiver = rthr
            elif not rthr:
                receiver = rproc
            else:
                receiver = "%s@%s" % (rthr, rproc)

            err = False
            reason = ""

            # sub stat update function #
            def _updateBinderStat(binderStat, ctask, code):
                binderStat.setdefault("others", {})
                binderStat["others"].setdefault(ctask, {})
                binderStat["others"][ctask].setdefault("count", 0)
                binderStat["others"][ctask]["count"] += 1
                binderStat["others"][ctask].setdefault("call", {})
                binderStat["others"][ctask]["call"].setdefault(code, 0)
                binderStat["others"][ctask]["call"][code] += 1

            # request #
            if reply == "0":
                self.binderTranData.setdefault(
                    tranid,
                    {
                        "reqtime": ftime,
                        "receiver": dproc,
                        "sender": sproc,
                        "code": code,
                    },
                )

                # handle oneway calls that have no reply #
                if oneway:
                    # update stats #
                    types = ["Server", "Client"]
                    for item in types:
                        if item == "Server":
                            dataList = self.binderServerData
                            task = sproc
                            ctask = rproc
                        else:
                            dataList = self.binderCliData
                            task = rproc
                            ctask = sproc

                        # update my stats #
                        dataList.setdefault(task, dict(self.init_binderInfo))
                        binderStat = dataList[task]
                        binderStat["count"] += 1
                        binderStat["last"] = ftime

                        # update sub stats #
                        _updateBinderStat(binderStat, ctask, code)

                # add to history #
                if SysMgr.showAll:
                    self.binderData.append(
                        [
                            allTime,
                            False,
                            tranid,
                            sender,
                            receiver,
                            flags,
                            code,
                            None,
                            oneway,
                        ]
                    )
            # response #
            elif "binderTranId" in self.threadData[thread]:
                reqTranId = self.threadData[thread]["binderTranId"]
                if reqTranId in self.binderTranData:
                    reqTime = self.binderTranData[reqTranId]["reqtime"]
                    origCode = self.binderTranData[reqTranId]["code"]
                    diff = ftime - reqTime
                    self.binderTranData[reqTranId]["diff"] = diff

                    # update stats #
                    types = ["Server", "Client"]
                    for item in types:
                        if item == "Server":
                            dataList = self.binderServerData
                            task = sproc
                            ctask = rproc
                        else:
                            dataList = self.binderCliData
                            task = rproc
                            ctask = sproc

                        # update my stats #
                        dataList.setdefault(task, dict(self.init_binderInfo))
                        binderStat = dataList[task]
                        binderStat["count"] += 1
                        binderStat["usage"] += diff
                        binderStat["last"] = ftime
                        if binderStat["max"] == 0 or binderStat["max"] < diff:
                            dataList[task]["max"] = diff
                        if binderStat["min"] <= 0 or binderStat["min"] > diff:
                            dataList[task]["min"] = diff

                        # update sub stats #
                        _updateBinderStat(binderStat, ctask, origCode)
                else:
                    err = True
                    diff = None

                # add to history #
                if SysMgr.showAll:
                    self.binderData.append(
                        [
                            allTime,
                            True,
                            tranid,
                            sender,
                            receiver,
                            "",
                            "",
                            diff,
                            None,
                        ]
                    )
            else:
                err = True

            # print error line #
            if err:
                reason = " because of no transaction ID for request"
                SysMgr.printWarn(
                    (
                        "failed to recognize binder transaction "
                        "for the below line%s\n%s"
                    )
                    % (reason, string.strip())
                )

        elif func == "cpu_idle":
            m = re.match(
                r"^\s*state=(?P<state>[0-9]+)\s+cpu_id=(?P<cpu_id>[0-9]+)", etc
            )
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            SysMgr.powerEnable = True
            tid = "0[%s]" % d["cpu_id"]
            state = long(d["state"])

            # no change #
            if self.threadData[tid]["lastIdleStatus"] == state:
                return time

            # update status #
            self.threadData[tid]["lastIdleStatus"] = state

            # check wakeup state #
            isWakeuped = state == 4294967295 or state == -1

            # wakeup #
            if isWakeuped:
                # update off time from start #
                if (
                    self.threadData[tid]["coreSchedCnt"] == 0
                    and self.threadData[tid]["offTime"] == 0
                ):
                    self.threadData[tid]["offTime"] = allTime
                    start_delta = 0
                # start to sleep #
                elif self.threadData[tid]["lastOff"] > 0:
                    startTime = self.threadData[tid]["lastOff"]
                    start_delta = long((float(startTime) - stime) * 1000000)
                    self.threadData[tid]["offTime"] += (
                        ftime - self.threadData[tid]["lastOff"]
                    )
                    self.threadData[tid]["lastOff"] = 0.0
                # undefined #
                else:
                    return time

                stop_delta = long((float(ftime) - stime) * 1000000)

                # add timeline data #
                self.addTimelineData(
                    long(core), "OFF", thread, "OFF", start_delta, stop_delta
                )

            # sleep #
            else:
                self.threadData[tid]["offCnt"] += 1
                self.threadData[tid]["lastOff"] = ftime

        elif func == "cpu_frequency":
            # TODO: calculate power consumption for DVFS system #
            SysMgr.powerEnable = True
            return time

        elif func == "workqueue_queue_work":
            m = re.match(
                (
                    r"^\s*work struct=(?P<struct>.+) "
                    r"function=(?P<function>.+) workqueue=(?P<wq>.+) "
                    r"req_cpu=(?P<rcpu>.+) cpu=(?P<ecpu>.+)"
                ),
                etc,
            )
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()
            struct = d["struct"]
            function = d["function"]
            wq = d["wq"]
            rcpu = d["rcpu"]
            ecpu = d["ecpu"]

            # register workqueue #
            try:
                self.wqData[struct]
            except:
                self.wqData[struct] = dict(self.init_wqData)
                self.wqData[struct]["name"] = function
                self.wqData[struct]["task"] = {}

        elif func == "workqueue_execute_start":
            m = re.match(
                (
                    r"^\s*work struct (?P<struct>.+): "
                    r"function (?P<function>.+)"
                ),
                etc,
            )
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()
            struct = d["struct"]
            function = d["function"]

            if not struct in self.wqData:
                return time

            # update period #
            if self.wqData[struct]["start"] > 0:
                diff = ftime - self.wqData[struct]["start"]
                if (
                    diff > self.wqData[struct]["maxPeriod"]
                    or self.wqData[struct]["maxPeriod"] < 0
                ):
                    self.wqData[struct]["maxPeriod"] = diff
                if (
                    diff < self.wqData[struct]["minPeriod"]
                    or self.wqData[struct]["minPeriod"] < 0
                ):
                    self.wqData[struct]["minPeriod"] = diff

            self.wqData[struct]["start"] = ftime
            self.wqData[struct]["scount"] += 1
            self.wqData[struct]["task"].setdefault(thread, None)

        elif func == "workqueue_execute_end":
            m = re.match(r"^\s*work struct (?P<struct>.+)", etc)
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()
            struct = d["struct"]

            if not struct in self.wqData:
                return time
            elif self.wqData[struct]["start"] == 0:
                return

            # update usage #
            diff = ftime - self.wqData[struct]["start"]
            self.wqData[struct]["usage"] += diff

            # update stat #
            diff = ftime - self.wqData[struct]["start"]
            if (
                diff > self.wqData[struct]["max"]
                or self.wqData[struct]["max"] < 0
            ):
                self.wqData[struct]["max"] = diff
            if (
                diff < self.wqData[struct]["min"]
                or self.wqData[struct]["min"] < 0
            ):
                self.wqData[struct]["min"] = diff

            self.wqData[struct]["rcount"] += 1

        elif func == "console":
            m = re.match(
                r"^\s*\[\s*(?P<time>\S+)\s*\]\s+EVENT_(?P<event>\S+)", etc
            )
            if m:
                d = m.groupdict()

                self.handleUserEvent(d["event"], time)

                return time

            # process CPU shutdown event #
            m = re.match(
                (
                    r"^\s*\[\s*(?P<time>\S+)\s*\]\s+"
                    r"CPU(?P<core>[0-9]+)\: shutdown"
                ),
                etc,
            )
            if m:
                ed = m.groupdict()

                try:
                    # set status of thread #
                    lastTid = self.lastTidPerCore[ed["core"]]
                    self.threadData[lastTid]["stop"] = float(ed["time"])
                    self.threadData[lastTid]["lastStatus"] = "S"

                    # set status of core #
                    scoreId = "0[%s]" % ed["core"]
                    self.threadData[scoreId]["offCnt"] += 1
                    self.threadData[scoreId]["lastOff"] = float(ed["time"])
                    self.threadData[scoreId]["start"] = float(ed["time"])
                    self.threadData[scoreId]["lastStatus"] = "R"
                except:
                    pass

            # save console log #
            self.consoleData.append([d["thread"], core, time, etc])

        elif func == "tracing_mark_write" or func == "0":
            m = re.match(r"^.+EVENT_(?P<event>\S+)", etc)
            if not m:
                _printEventWarning(func)
                return time

            d = m.groupdict()

            self.handleUserEvent(d["event"], time)

            start_delta = stop_delta = long((float(ftime) - stime) * 1000000)

            # add timeline data #
            self.addTimelineData(
                long(core),
                d["event"],
                thread,
                "EVENT_MARK",
                start_delta,
                stop_delta,
            )

        else:
            handleSpecialEvents = True

        # custom event #
        if any(
            [
                True
                for event in SysMgr.customEventList
                if func.startswith(event)
            ]
        ):
            self.customEventData.append(
                [func, comm, thread, allTime, etc.strip()]
            )

            # make event list #
            if not threadData["customEvent"]:
                threadData["customEvent"] = {}

            threadData["customEvent"].setdefault(
                func, dict(self.init_eventData)
            )

            self.customEventInfo.setdefault(func, dict(self.init_eventData))

            threadData["customEvent"][func]["count"] += 1
            self.customEventInfo[func]["count"] += 1

            # define eventObj #
            eventObj = threadData["customEvent"][func]

            # get interval #
            interDiff = 0
            if eventObj["start"] > 0:
                interDiff = ftime - eventObj["start"]

            # update period of thread #
            if interDiff > eventObj["maxPeriod"] or eventObj["maxPeriod"] == 0:
                threadData["customEvent"][func]["maxPeriod"] = interDiff
            if interDiff < eventObj["minPeriod"] or eventObj == 0:
                threadData["customEvent"][func]["minPeriod"] = interDiff

            # update period of system #
            if (
                interDiff > self.customEventInfo[func]["maxPeriod"]
                or self.customEventInfo[func]["maxPeriod"] == 0
            ):
                self.customEventInfo[func]["maxPeriod"] = interDiff
            if (
                interDiff < self.customEventInfo[func]["minPeriod"]
                or self.customEventInfo[func]["minPeriod"] == 0
            ):
                self.customEventInfo[func]["minPeriod"] = interDiff

            threadData["customEvent"][func]["start"] = ftime

            handleSpecialEvents = True

        # check special event flag #
        if not handleSpecialEvents:
            return time

        # user event #
        for name in SysMgr.userEventList:
            if not func.startswith(name):
                continue

            if not threadData["userEvent"]:
                threadData["userEvent"] = {}

            threadData["userEvent"].setdefault(name, dict(self.init_eventData))

            self.userEventInfo.setdefault(name, dict(self.init_eventData))

            # define eventObj #
            eventObj = threadData["userEvent"][name]

            if func == "%s_enter" % name:
                self.userEventData.append(
                    ["ENTER", name, comm, thread, allTime, ""]
                )

                # get interval #
                interDiff = 0
                if eventObj["start"] > 0:
                    interDiff = ftime - eventObj["start"]

                threadData["userEvent"][name]["count"] += 1
                threadData["userEvent"][name]["start"] = ftime

                # update period of thread #
                if (
                    interDiff > eventObj["maxPeriod"]
                    or eventObj["maxPeriod"] == 0
                ):
                    threadData["userEvent"][name]["maxPeriod"] = interDiff
                if (
                    interDiff < eventObj["minPeriod"]
                    or eventObj["minPeriod"] == 0
                ):
                    threadData["userEvent"][name]["minPeriod"] = interDiff

                self.userEventInfo[name]["count"] += 1

                # update period of system #
                if (
                    interDiff > self.userEventInfo[name]["maxPeriod"]
                    or self.userEventInfo[name]["maxPeriod"] == 0
                ):
                    self.userEventInfo[name]["maxPeriod"] = interDiff
                if (
                    interDiff < self.userEventInfo[name]["minPeriod"]
                    or self.userEventInfo[name]["minPeriod"] == 0
                ):
                    self.userEventInfo[name]["minPeriod"] = interDiff

            elif func == "%s_exit" % name:
                self.userEventData.append(
                    [
                        "EXIT",
                        name,
                        comm,
                        thread,
                        allTime,
                        etc[etc.find("(") + 1 : etc.rfind("<-")],
                    ]
                )

                # get usage #
                usage = 0
                if eventObj["start"] > 0:
                    usage = ftime - eventObj["start"]
                    threadData["userEvent"][name]["usage"] += usage
                    self.userEventInfo[name]["usage"] += usage

                    # update usage of thread #
                    if usage > eventObj["max"] or eventObj["max"] == 0:
                        threadData["userEvent"][name]["max"] = usage
                    if usage < eventObj["min"] or eventObj["min"] == 0:
                        threadData["userEvent"][name]["min"] = usage

                    # update usage of system #
                    if (
                        usage > self.userEventInfo[name]["max"]
                        or self.userEventInfo[name]["max"] == 0
                    ):
                        self.userEventInfo[name]["max"] = usage
                    if (
                        usage < self.userEventInfo[name]["min"]
                        or self.userEventInfo[name]["min"] == 0
                    ):
                        self.userEventInfo[name]["min"] = usage

        # kernel event #
        for name in SysMgr.kernelEventList:
            if not func.startswith(name):
                continue

            if not threadData["kernelEvent"]:
                threadData["kernelEvent"] = {}

            threadData["kernelEvent"].setdefault(
                name, dict(self.init_eventData)
            )

            self.kernelEventInfo.setdefault(name, dict(self.init_eventData))

            # define eventObj #
            eventObj = threadData["kernelEvent"][name]

            if func == "%s_enter" % name:
                isSaved = True
                m = re.match(
                    (
                        r"^\s*\((?P<name>.+)\+(?P<offset>.+) "
                        r"<(?P<addr>.+)>\)(?P<args>.*)"
                    ),
                    etc,
                )
                if m:
                    d = m.groupdict()
                    self.kernelEventData.append(
                        [
                            "ENTER",
                            name,
                            d["addr"],
                            comm,
                            thread,
                            allTime,
                            "",
                            d["args"],
                        ]
                    )
                else:
                    m = re.match(
                        r"^\s*\((?P<name>.+)\+(?P<offset>.+)\)(?P<args>.*)",
                        etc,
                    )
                    if m:
                        d = m.groupdict()
                        self.kernelEventData.append(
                            [
                                "ENTER",
                                name,
                                "",
                                comm,
                                thread,
                                allTime,
                                "",
                                d["args"],
                            ]
                        )
                    else:
                        isSaved = False
                        SysMgr.printWarn(
                            "failed to recognize '%s' kernel event" % etc
                        )

                if not isSaved:
                    continue

                # get interval #
                interDiff = 0
                if eventObj["start"] > 0:
                    interDiff = ftime - eventObj["start"]

                threadData["kernelEvent"][name]["count"] += 1
                threadData["kernelEvent"][name]["start"] = ftime

                # update period of thread #
                if (
                    interDiff > eventObj["maxPeriod"]
                    or eventObj["maxPeriod"] == 0
                ):
                    threadData["kernelEvent"][name]["maxPeriod"] = interDiff
                if (
                    interDiff < eventObj["minPeriod"]
                    or eventObj["minPeriod"] == 0
                ):
                    threadData["kernelEvent"][name]["minPeriod"] = interDiff

                self.kernelEventInfo[name]["count"] += 1

                # update period of system #
                if (
                    interDiff > self.kernelEventInfo[name]["maxPeriod"]
                    or self.kernelEventInfo[name]["maxPeriod"] == 0
                ):
                    self.kernelEventInfo[name]["maxPeriod"] = interDiff
                if (
                    interDiff < self.kernelEventInfo[name]["minPeriod"]
                    or self.kernelEventInfo[name]["minPeriod"] == 0
                ):
                    self.kernelEventInfo[name]["minPeriod"] = interDiff

            elif func == "%s_exit" % name:
                isSaved = True
                m = re.match(
                    (
                        r"^\s*\((?P<caller>.+)\+(?P<offset>.+) <(?P<caddr>.+)> <- "
                        r"(?P<name>.+) <(?P<addr>.+)>\)(?P<args>.*)"
                    ),
                    etc,
                )
                if m:
                    d = m.groupdict()
                    self.kernelEventData.append(
                        [
                            "EXIT",
                            name,
                            d["addr"],
                            comm,
                            thread,
                            allTime,
                            d["caller"],
                            d["args"],
                            d["caddr"],
                        ]
                    )
                else:
                    m = re.match(
                        (
                            r"^\s*\((?P<caller>.+)\+(?P<offset>.+) <- "
                            r"(?P<name>.+)\)(?P<args>.*)"
                        ),
                        etc,
                    )
                    if m:
                        d = m.groupdict()
                        self.kernelEventData.append(
                            [
                                "EXIT",
                                name,
                                "",
                                comm,
                                thread,
                                allTime,
                                d["caller"],
                                d["args"],
                                "",
                            ]
                        )
                    else:
                        isSaved = False
                        SysMgr.printWarn(
                            "failed to recognize '%s' kernel event" % etc
                        )

                if not isSaved:
                    continue

                # get usage #
                if eventObj["start"] <= 0:
                    continue

                usage = ftime - eventObj["start"]
                threadData["kernelEvent"][name]["usage"] += usage
                self.kernelEventInfo[name]["usage"] += usage

                # update usage of thread #
                if usage > eventObj["max"] or eventObj["max"] == 0:
                    threadData["kernelEvent"][name]["max"] = usage
                if usage < eventObj["min"] or eventObj["min"] == 0:
                    threadData["kernelEvent"][name]["min"] = usage

                # update usage of system #
                if (
                    usage > self.kernelEventInfo[name]["max"]
                    or self.kernelEventInfo[name]["max"] == 0
                ):
                    self.kernelEventInfo[name]["max"] = usage
                if (
                    usage < self.kernelEventInfo[name]["min"]
                    or self.kernelEventInfo[name]["min"] == 0
                ):
                    self.kernelEventInfo[name]["min"] = usage

        # return time #
        return time

    def compareThreadData(self):
        # TODO: compare stats with items in self.backupData #
        for key, value in sorted(
            self.threadData.items(), key=lambda e: e[1]["usage"], reverse=True
        ):
            pass

    def printFileStat(self, filters):
        # update uptime #
        SysMgr.updateUptime()

        convNum = UtilMgr.convNum
        convSize = UtilMgr.convSize2Unit
        convColor = UtilMgr.convColor

        # print CPU usage #
        if SysMgr.isLinux:
            # get diff #
            diff = SysMgr.uptimeDiff
            if diff == 0:
                diff = 0.01

            # get CPU usage for myself #
            if diff >= 1:
                cpuUsage = TaskAnalyzer.dbgObj.getCpuUsage(system=True)
            else:
                cpuUsage = [0, 0, 0, 100]
            ttime = cpuUsage[0] / diff
            utime = cpuUsage[1] / diff
            stime = cpuUsage[2] / diff
            mcpu = "%d%%" % ttime
            mcpuStr = "%s(U%d%%+S%d%%)" % (mcpu, utime, stime)

            # get CPU usage for system #
            ctime = 100 - (cpuUsage[3] / diff)
            ctime = ctime if ctime > 0 else 0
            sysCpuStr = "%d%%" % ctime

            # get available memory for system #
            sysMemStr = SysMgr.getAvailMemInfo()
        else:
            cpuStr = mcpuStr = sysCpuStr = sysMemStr = "?"

        # get system fd handle stats #
        sysFds = SysMgr.getNrSysFdHandle()
        try:
            curFd = sysFds[0]
            maxFd = sysFds[2]
            fdUsage = "%d" % (curFd / float(maxFd) * 100)
            sysFdStr = "%s(%s%%/%s)" % (
                convNum(curFd),
                fdUsage,
                convSize(maxFd, True),
            )
        except SystemExit:
            sys.exit(0)
        except:
            curFd = maxFd = 0
            sysFdStr = "?"

        # get the number of sockets #
        SysMgr.getSocketAddrList([])
        SysMgr.getUdsList([])

        # print menu #
        if SysMgr.jsonEnable:
            SysMgr.jsonData = {
                "uptime": SysMgr.uptime,
                "uptimeDiff": SysMgr.uptimeDiff,
                "nrProcess": self.nrProcess,
                "nrOpenFd": self.nrFd,
                "nrCurFdHandle": curFd,
                "nrMaxFdHandle": maxFd,
                "nrUDPSock": SysMgr.nrUDPSock,
                "nrTCPSock": SysMgr.nrTCPSock,
                "nrTCPConn": SysMgr.nrTCPConn,
                "nrUDSSock": SysMgr.nrUDSSock,
                "nrFile": len(self.fileData),
                "comm": SysMgr.comm,
                "pid": SysMgr.pid,
                "procs": {},
            }
        else:
            SysMgr.addPrint(
                convColor(
                    (
                        "[Top File Info] [Time: %7.3f] [Inter: %.3f]"
                        " [Proc: %s] [SYS: %s/%s] [%s(%s): %s]\n"
                    )
                    % (
                        SysMgr.uptime,
                        SysMgr.uptimeDiff,
                        convNum(self.nrProcess),
                        sysCpuStr,
                        sysMemStr,
                        SysMgr.comm,
                        SysMgr.pid,
                        mcpuStr,
                    ),
                    "BOLD",
                )
            )

            SysMgr.addPrint(
                convColor(
                    (
                        "%s[Handle: %s] [FD: %s] [File: %s] [UDP: %s] "
                        "[TCP: %s] [TCP(ESTABLISHED): %s] [UDS: %s]\n"
                    )
                    % (
                        " " * 16,
                        sysFdStr,
                        convNum(self.nrFd),
                        convNum(len(self.fileData)),
                        convNum(SysMgr.nrUDPSock),
                        convNum(SysMgr.nrTCPSock),
                        convNum(SysMgr.nrTCPConn),
                        convNum(SysMgr.nrUDSSock),
                    ),
                    "BOLD",
                )
            )

            SysMgr.addPrint(
                "%s\n" % twoLine
                + (
                    "{0:>16} ({1:^7}/{2:^7}/{3:^4}/{4:>4})|{5:^6}|"
                    "{6:^101}|\n{7:1}\n"
                ).format(
                    "Process", "ID", "PID", "Nr", "Pri", "FD", "Path", oneLine
                ),
                newline=3,
            )

        # set sort value #
        if SysMgr.sort == "p":
            sortedProcData = sorted(
                self.procData.items(), key=lambda e: long(e[0])
            )
        else:
            # set the number of files opened as default #
            sortedProcData = sorted(
                self.procData.items(),
                key=lambda e: len(e[1]["fdList"]),
                reverse=True,
            )

        # get filters #
        procFilter, fileFilter = filters

        # print process info #
        procCnt = 0
        for idx, value in sortedProcData:
            # linux #
            if SysMgr.isLinux:
                stat = value["stat"]
                comm = stat[self.commIdx].strip("()")
                pid = stat[self.ppidIdx]
                nrThread = stat[self.nrthreadIdx]

                # get sched info #
                schedPolicy = ConfigMgr.SCHED_POLICY[int(stat[self.policyIdx])]
                if schedPolicy == "C":
                    schedValue = "%3d" % (long(stat[self.prioIdx]) - 20)
                else:
                    schedValue = "%3d" % (abs(long(stat[self.prioIdx]) + 1))
                sched = schedPolicy + schedValue
            # other OS #
            else:
                comm = value["comm"]
                pid = value["ppid"]
                nrThread = value["nrThread"]
                sched = str(value["nice"])

            procInfo = ("{0:>16} ({1:>7}/{2:>7}/{3:>4}/{4:>4})").format(
                comm[:16], idx, pid, nrThread, sched
            )

            procInfoLen = len(procInfo)

            # summary info #
            if "fdInfo" in value:
                details = "   ".join(
                    [
                        "%6s: %5s" % (fd, path)
                        for fd, path in sorted(
                            value["fdInfo"].items(),
                            key=lambda e: long(e[1]),
                            reverse=True,
                        )
                    ]
                )
            else:
                details = " "

            # convert the number of fds #
            nrFd = len(value["fdList"])
            if nrFd > SysMgr.fdHighThreshold:
                nrFd = convColor(nrFd, "RED", 6)
            elif nrFd == 0:
                break

            procInfo = "%s|%s\n" % (
                procInfo,
                "{0:>6}| {1:<100}|".format(nrFd, details),
            )

            # print only per-process summary #
            fdCnt = 0
            if not SysMgr.showAll and not SysMgr.filterGroup:
                if procInfo != "":
                    if SysMgr.jsonEnable:
                        ret = True
                        SysMgr.jsonData["procs"][idx] = {
                            "comm": comm,
                            "pid": pid,
                            "nrThread": nrThread,
                            "nrFd": len(value["fdList"]),
                        }
                    else:
                        ret = SysMgr.addPrint(procInfo)

                    procInfo = ""
                    if not ret:
                        break

                fdCnt += 1
                procCnt += 1

                continue

            # print fd info #
            for fd, path in sorted(
                value["fdList"].items(), key=lambda e: long(e[0]), reverse=True
            ):
                # get additional info #
                try:
                    if path.startswith("socket"):
                        obj = path.split("[")[1][:-1]

                        addr = SysMgr.getSocketAddrList([obj])
                        if addr:
                            path = "%s (%s)" % (path, addr[0])
                            raise Exception("skip UDS socket")

                        uds = SysMgr.getUdsList([obj])
                        if uds:
                            path = "%s (%s)" % (path, uds[0])
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

                # apply filter #
                if fileFilter:
                    if not UtilMgr.isValidStr(path, fileFilter):
                        continue

                if procInfo != "":
                    if SysMgr.jsonEnable:
                        ret = True
                        SysMgr.jsonData["procs"][idx] = {
                            "comm": comm,
                            "pid": pid,
                            "nrThread": nrThread,
                            "nrFd": len(value["fdList"]),
                            "fdList": value["fdList"],
                        }
                    else:
                        ret = SysMgr.addPrint(procInfo)

                    # save cmdline #
                    if SysMgr.isLinux:
                        # save cmdline #
                        self.saveCmdlineData(None, idx)

                    # print cmdline #
                    if "cmdline" in value:
                        if SysMgr.jsonEnable:
                            SysMgr.jsonData["procs"][idx]["cmdline"] = value[
                                "cmdline"
                            ]
                        else:
                            # print stat #
                            SysMgr.addPrint(
                                ("{0:>1}|{1:>6}| {2:<100}|\n").format(
                                    " " * procInfoLen, "CMD", value["cmdline"]
                                )
                            )

                    procInfo = ""
                    if not ret:
                        break

                # read pos and permission #
                try:
                    if SysMgr.isLinux:
                        assert path.startswith("/")
                    else:
                        assert False

                    attr = ""
                    fdinfoPath = "%s/%s/fdinfo/%s" % (SysMgr.procPath, idx, fd)
                    with open(fdinfoPath, "r") as infofd:
                        for item in infofd.readlines():
                            if item.startswith("pos"):
                                attr += "%s" % item.split(":")[1].strip()
                            elif item.startswith("flags"):
                                perm = long(item.split(":")[1].strip(), 8)
                                perm = UtilMgr.getFlagString(
                                    perm, ConfigMgr.OPEN_TYPE, num="oct"
                                )
                                attr += ", %s" % perm

                    # append attributes #
                    if attr:
                        path = "%s (%s)" % (path, attr)
                except AssertionError:
                    pass
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printWarn(
                        "failed to read attributes from %s" % fdinfoPath,
                        reason=True,
                    )

                # print stat #
                if not SysMgr.jsonEnable:
                    SysMgr.addPrint(
                        ("{0:>1}|{1:>6}| {2:<100}|\n").format(
                            " " * procInfoLen, fd, path
                        )
                    )

                fdCnt += 1

            if fdCnt > 0:
                procCnt += 1
                if SysMgr.jsonEnable:
                    ret = True
                else:
                    ret = SysMgr.addPrint("%s\n" % oneLine)
                if not ret:
                    break

        # print total stats #
        if SysMgr.jsonEnable:
            pass
        elif procCnt == 0:
            text = "{0:^16}".format("None")
            frame = "%s%s|" % (text, " " * (SysMgr.lineLength - len(text) - 1))

            SysMgr.addPrint("{0:1}\n{1:1}\n".format(frame, oneLine))
        elif not SysMgr.showAll and not SysMgr.filterGroup:
            SysMgr.addPrint("{0:1}\n".format(oneLine))

        # print buffer #
        SysMgr.printTopStats()

    def saveFileStat(self, filters):
        # save proc and file instance #
        SysMgr.topInstance = self
        SysMgr.procInstance = self.procData
        SysMgr.fileInstance = self.fileData

        procFilter = filters[0]

        # get process list #
        if procFilter:
            pids = SysMgr.convTaskList(procFilter, isThread=True, inc=True)
            newPids = []
            if SysMgr.isLinux:
                for pid in pids:
                    ret = SysMgr.getTgid(pid)
                    if ret:
                        newPids.append(ret)
            else:
                self.saveProcStatGen(["open_files"], list(map(str, pids)))
                newPids += pids
            pids = list(set(newPids))
        else:
            if SysMgr.isLinux:
                pids = SysMgr.getPidList()
            else:
                self.saveProcStatGen(["open_files"])
                pids = list(self.procData)

        # remove myself info #
        try:
            pids.remove(str(SysMgr.pid))
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # get psutil object #
        if SysMgr.isLinux:
            psutil = None
        else:
            psutil = SysMgr.getPkg("psutil")

        # get thread list #
        for pid in pids:
            try:
                long(pid)
                self.nrProcess += 1
            except:
                continue

            if SysMgr.isLinux:
                # save stat of process #
                procPath = "%s/%s" % (SysMgr.procPath, pid)
                self.saveProcData(procPath, pid)

                # save file info per process #
                try:
                    fdlistPath = "%s/fd" % (procPath)
                    fdlist = os.listdir(fdlistPath)
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printOpenWarn(fdlistPath)
                    continue
            else:
                try:
                    fdlist = self.procData[pid]["open_files"]
                except SystemExit:
                    sys.exit(0)
                except:
                    continue

            # save fd info of process #
            for fd in fdlist:
                try:
                    if SysMgr.isLinux:
                        long(fd)
                    else:
                        filename, fd = fd
                        fdPath = "N/A"
                except SystemExit:
                    sys.exit(0)
                except:
                    continue

                try:
                    self.nrFd += 1

                    if SysMgr.isLinux:
                        # add file info into fdList #
                        fdPath = "%s/%s" % (fdlistPath, fd)
                        filename = os.readlink(fdPath)

                    self.procData[pid]["fdList"][fd] = filename

                    # increase reference count of file #
                    try:
                        self.fileData[filename] += 1
                    except:
                        self.fileData[filename] = 1

                    # initialize fdinfo per process #
                    try:
                        self.procData[pid]["fdInfo"]
                    except:
                        self.procData[pid]["fdInfo"] = {}
                        self.procData[pid]["fdInfo"]["EVENT"] = 0
                        self.procData[pid]["fdInfo"]["SOCKET"] = 0
                        self.procData[pid]["fdInfo"]["DEVICE"] = 0
                        self.procData[pid]["fdInfo"]["PIPE"] = 0
                        self.procData[pid]["fdInfo"]["NORMAL"] = 0
                        self.procData[pid]["fdInfo"]["PROC"] = 0

                    # increase type count per process #
                    if SysMgr.isLinux:
                        if filename.startswith("anon"):
                            self.procData[pid]["fdInfo"]["EVENT"] += 1
                        elif filename.startswith("socket"):
                            self.procData[pid]["fdInfo"]["SOCKET"] += 1
                        elif filename.startswith("/dev"):
                            self.procData[pid]["fdInfo"]["DEVICE"] += 1
                        elif filename.startswith("pipe"):
                            self.procData[pid]["fdInfo"]["PIPE"] += 1
                        elif filename.startswith(SysMgr.procPath):
                            self.procData[pid]["fdInfo"]["PROC"] += 1
                        else:
                            self.procData[pid]["fdInfo"]["NORMAL"] += 1
                except SystemExit:
                    sys.exit(0)
                except:
                    self.nrFd -= 1
                    SysMgr.printOpenWarn(fdPath)

    def saveVmallocInfo(self):
        self.vmallocData = {}

        # read slab buf #
        vmBuf = SysMgr.readProcStat(
            SysMgr.vmallocFd, "vmallocinfo", SysMgr, "vmallocFd"
        )
        if not vmBuf:
            return

        # parse slab items #
        for line in vmBuf[2:]:
            try:
                # get items #
                items = line.strip().split()
                addr, size, alloc = items[:3]
                alloc = alloc.split("+", 1)[0]
                others = items[2:]

                # get type #
                if "vmalloc" in others:
                    mtype = "vmalloc"
                elif "ioremap" in others:
                    mtype = "ioremap"
                else:
                    mtype = others[-1]

                # add chunk size #
                name = "%s [%s]" % (alloc, mtype.strip("()"))
                self.vmallocData.setdefault(name, {"size": 0})
                self.vmallocData[name]["size"] += long(size)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn("failed to parse vmalloc info", reason=True)

    def saveSlabInfo(self):
        self.slabData = {}

        # read slab buf #
        slabBuf = SysMgr.readProcStat(
            SysMgr.slabFd, "slabinfo", SysMgr, "slabFd"
        )
        if not slabBuf:
            return

        # parse slab items #
        for line in slabBuf[2:]:
            try:
                items = line.strip().split()[:6]
                name = items[0]
                actobj, totobj, objsize, objperslab, pageperslab = list(
                    map(long, items[1:])
                )

                self.slabData[name] = {
                    "size": objsize,
                    "active": actobj,
                    "actsize": actobj * objsize,
                    "total": totobj,
                    "totsize": totobj * objsize,
                    "ops": objperslab,
                    "pps": pageperslab,
                }
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn("failed to parse slab info", reason=True)

    def saveVmInfo(self):
        # read swappiness #
        try:
            SysMgr.swappiness = long(
                SysMgr.readProcStat(
                    SysMgr.swappinessFd,
                    "sys/vm/swappiness",
                    SysMgr,
                    "swappinessFd",
                )[0].rstrip()
            )
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # read vmpressure #
        try:
            SysMgr.vmpressure = long(
                SysMgr.readProcStat(
                    SysMgr.vmpressureFd,
                    "sys/vm/vfs_cache_pressure",
                    SysMgr,
                    "vmpressureFd",
                )[0].rstrip()
            )
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # read overcommit_memory #
        try:
            SysMgr.overcommit = long(
                SysMgr.readProcStat(
                    SysMgr.overcommitFd,
                    "sys/vm/overcommit_memory",
                    SysMgr,
                    "overcommitFd",
                )[0].rstrip()
            )
        except SystemExit:
            sys.exit(0)
        except:
            pass

    def saveZoneInfo(self):
        # read zone buf #
        memBuf = SysMgr.readProcStat(
            SysMgr.zoneFd, "zoneinfo", SysMgr, "zoneFd"
        )
        if not memBuf:
            return

        self.prevZoneData = self.zoneData
        self.zoneData = {}

        zone = None
        for line in memBuf:
            zl = line.split()
            item = zl[0]
            if item == "Node":
                zone = "%s-%s" % (zl[1][:-1], zl[3])
                self.zoneData[zone] = {}
            elif item == "pages" and zl[1] == "free":
                self.zoneData[zone]["free"] = long(zl[2])
            elif item in (
                "min",
                "low",
                "high",
                "spanned",
                "present",
                "managed",
            ):
                self.zoneData[zone][item] = long(zl[1])
            else:
                continue

    def saveIrqs(self):
        # read irq buf #
        irqBuf = SysMgr.readProcStat(
            SysMgr.irqFd, "interrupts", SysMgr, "irqFd"
        )

        # read softirq buf #
        try:
            sirqBuf = SysMgr.readProcStat(
                SysMgr.softirqFd, "softirqs", SysMgr, "softirqFd"
            )
            irqBuf += sirqBuf[1:]
        except SystemExit:
            sys.exit(0)
        except:
            pass

        if irqBuf:
            self.prevIrqData = self.irqData
            self.irqData = {}
            cpuCnt = len(irqBuf.pop(0).split())

            for line in irqBuf:
                irqList = line.split()
                try:
                    irqSum = sum(list(map(long, irqList[1:cpuCnt])))
                    if irqSum > 0:
                        self.irqData[irqList[0][:-1]] = irqSum
                except:
                    pass

    def saveCgroupStat(self):
        def _getStats(root, path, sub):
            # convert subsystem #
            origSub = sub
            if "cpuacct" in sub:
                sub = "cpuacct"

            # check subsystem #
            if sub in root:
                return

            # register subsystem #
            root.setdefault(sub, {})
            cgroupPath = SysMgr.cgroupPath

            for dirpath, subdirs, subfiles in path:
                # update subfiles #
                for item in subfiles:
                    # check file #
                    if not item in ConfigMgr.CGROUP_STAT:
                        continue

                    # save stat #
                    try:
                        # convert name #
                        stripLen = len(os.path.join(cgroupPath, origSub))
                        dpath = dirpath[stripLen:]
                        if dpath:
                            dpath = dpath[1:]

                        # check depth #
                        if (
                            SysMgr.funcDepth > 0
                            and dpath.count("/") >= SysMgr.funcDepth
                        ):
                            continue

                        if not dpath:
                            dpath = "/"

                        subfile = os.path.join(dirpath, item)

                        # read stat #
                        fd = SysMgr.getFd(subfile, "r")
                        fd.seek(0)
                        stat = fd.read()

                        # save stat #
                        root[sub].setdefault(dpath, {})
                        root[sub][dpath][item] = stat
                    except SystemExit:
                        sys.exit(0)
                    except:
                        SysMgr.printWarn(
                            "failed to read stat from %s" % subfile, True, True
                        )

        # reset and save cgroup instance #
        self.saveCgroupInstance()

        # get cgroup list #
        try:
            systems = os.listdir(SysMgr.cgroupPath)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenErr(SysMgr.cgroupPath)
            sys.exit(-1)

        # save stats #
        for sub in systems:
            # check subsystem #
            if sub in self.cgroupData:
                continue
            elif "cpuacct" in sub or "memory" in sub or "blkio" in sub:
                pass
            else:
                continue

            # build path #
            path = os.path.join(SysMgr.cgroupPath, sub)

            # gather stats #
            _getStats(self.cgroupData, os.walk(path), sub)

    def saveProcStat(self):
        if SysMgr.fixedProcList:
            pids = list(SysMgr.fixedProcList)
        else:
            # get process list #
            pids = SysMgr.getPidList()

        # reset and save proc instance #
        self.saveProcInstance()

        # get thread list #
        for pid in pids:
            try:
                nrPid = long(pid)
            except SystemExit:
                sys.exit(0)
            except:
                continue

            if self.maxPid < nrPid:
                self.maxPid = nrPid

            self.nrProcess += 1

            # set process path #
            procPath = "%s/%s" % (SysMgr.procPath, pid)

            # save info per process #
            if SysMgr.processEnable:
                if SysMgr.exceptCommFilter and not pid in SysMgr.filterGroup:
                    continue

                # save stat of process #
                ret = self.saveProcData(procPath, pid)

                # calculate number of threads #
                if pid in self.procData:
                    self.nrThread += long(
                        self.procData[pid]["stat"][self.nrthreadIdx]
                    )

                continue

            # set thread group path #
            taskPath = "%s/task" % procPath

            # save info per thread #
            try:
                tids = os.listdir(taskPath)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenWarn(taskPath)
                continue

            for tid in tids:
                try:
                    nrTid = long(tid)
                except SystemExit:
                    sys.exit(0)
                except:
                    continue

                if self.maxPid < nrTid:
                    self.maxPid = nrTid

                if SysMgr.exceptCommFilter and not tid in SysMgr.filterGroup:
                    continue

                self.nrThread += 1

                # set thread path #
                threadPath = "%s/%s" % (taskPath, tid)

                # save stat of thread #
                ret = self.saveProcData(threadPath, tid, pid)
                if not ret:
                    if tid in self.procData:
                        self.procData.pop(tid, None)
                    continue

                # main thread #
                if pid == tid:
                    self.procData[tid]["isMain"] = True
                    self.procData[tid]["tids"] = []
                    continue

                # sibling thread #
                try:
                    self.procData[pid]["tids"].append(tid)
                except:
                    self.procData[pid] = dict(self.init_procData)
                    self.procData[pid]["tids"] = []
                    self.procData[pid]["tids"].append(tid)

    def saveSystemStatGen(self):
        # get psutil object #
        psutil = SysMgr.getPkg("psutil")

        """
        python psutil APIs
        refer to https://psutil.readthedocs.io/en/latest
        """

        # update uptime #
        SysMgr.updateUptime()

        # CPU total #
        cpuStat = psutil.cpu_times(percpu=False)
        if cpuStat:
            self.cpuData["all"] = {
                "user": cpuStat[0],
                "nice": cpuStat[1],
                "system": cpuStat[2],
                "idle": cpuStat[3],
                "iowait": 0,
                "irq": 0,
                "softirq": 0,
            }

        # CPU cores #
        if SysMgr.nrCore == 0:
            nrCore = psutil.cpu_count(logical=True)
            if nrCore:
                SysMgr.nrCore = psutil.cpu_count(logical=True)
        cpuStat = psutil.cpu_times(percpu=True)
        if not cpuStat:
            cpuStat = []
        for idx, cpu in enumerate(cpuStat):
            self.cpuData[idx] = {}
            # linux #
            if SysMgr.isLinux:
                self.cpuData[idx]["user"] = cpu[0] * 100
                self.cpuData[idx]["nice"] = cpu[1] * 100
                self.cpuData[idx]["system"] = cpu[2] * 100
                self.cpuData[idx]["idle"] = cpu[3] * 100
                self.cpuData[idx]["iowait"] = cpu[4] * 100
                self.cpuData[idx]["irq"] = cpu[5] * 100
                self.cpuData[idx]["softirq"] = cpu[6] * 100
            # MacOS #
            elif SysMgr.isDarwin:
                self.cpuData[idx]["user"] = cpu[0] * 100
                self.cpuData[idx]["nice"] = cpu[1] * 100
                self.cpuData[idx]["system"] = cpu[2] * 100
                self.cpuData[idx]["idle"] = cpu[3] * 100
                self.cpuData[idx]["iowait"] = 0
                self.cpuData[idx]["irq"] = 0
                self.cpuData[idx]["softirq"] = 0
            # windows #
            else:
                self.cpuData[idx]["user"] = cpu[0] * 100
                self.cpuData[idx]["nice"] = 0
                self.cpuData[idx]["system"] = cpu[1] * 100
                self.cpuData[idx]["idle"] = cpu[2] * 100
                self.cpuData[idx]["iowait"] = 0
                self.cpuData[idx]["irq"] = cpu[3] * 100
                self.cpuData[idx]["softirq"] = 0

        # CPU events #
        cpuEvents = psutil.cpu_stats()
        self.cpuData["ctxt"] = {"ctxt": cpuEvents[0]}
        self.cpuData["intr"] = {"intr": cpuEvents[1]}
        self.cpuData["softirq"] = {"softirq": cpuEvents[2]}
        self.cpuData["syscall"] = {"syscall": cpuEvents[3]}

        # load #
        try:
            SysMgr.loadavg = psutil.getloadavg()
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # memory #
        try:
            self.prevVmData = self.vmData
            self.vmData = {}
            self.prevMemData = self.memData
            self.memData = {}

            mem = psutil.virtual_memory()
            self.memData["MemTotal"] = self.vmData["total"] = mem[0] >> 10
            self.memData["MemAvailable"] = self.vmData["available"] = (
                mem[1] >> 10
            )
            self.vmData["percent"] = mem[2]
            self.vmData["used"] = mem[3]
            self.memData["MemFree"] = self.vmData["free"] = mem[4] >> 10
            self.vmData["active"] = mem[5]
            self.vmData["inactive"] = mem[6]
            self.vmData["wired"] = mem[7]
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # swap #
        try:
            swap = psutil.swap_memory()
            self.memData["SwapTotal"] = self.vmData["swapTotal"] = (
                swap[0] >> 10
            )
            self.vmData["swapUsed"] = swap[1] >> 10
            self.vmData["swapFree"] = swap[2] >> 10
            self.vmData["swapPer"] = swap[3]
            self.vmData["pswpin"] = swap[4] >> 10
            self.vmData["pswpout"] = swap[5] >> 10
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # disk #
        if SysMgr.diskEnable:
            SysMgr.sysInstance.updateStorageInfoGen()

        # network #
        SysMgr.prevNetstat = SysMgr.netstat
        netStat = psutil.net_io_counters(pernic=False, nowrap=True)
        if netStat:
            SysMgr.netstat = [netStat[1], netStat[0]]
        if SysMgr.networkEnable:
            SysMgr.sysInstance.updateNetworkInfoGen()

        # temperature #
        try:
            raise Exception()
            temp = psutil.sensors_temperatures(fahrenheit=False)
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # fan #
        try:
            raise Exception()
            fan = psutil.sensors_fans()
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # battery #
        try:
            battery = psutil.sensors_battery()
            if battery:
                SysMgr.battery = battery
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # users #
        try:
            raise Exception()
            user = psutil.users()
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # process #
        self.saveProcStatGen()

    def saveProcStatGen(self, addList=[], filterList=None):
        # get psutil object #
        psutil = SysMgr.getPkg("psutil")

        # get the number of processes #
        pidList = sorted(psutil.pids())
        self.cpuData["processes"] = {"processes": 0}
        self.cpuData["processes"]["processes"] = len(pidList)
        self.nrProcess = len(pidList)
        SysMgr.maxPid = pidList[-1]

        # get current time #
        current = time.time()

        # reset and save proc instance #
        self.saveProcInstance()

        attrs = [
            "pid",
            "name",
            "ppid",
            "exe",
            "nice",
            "num_threads",
            "cpu_times",
            "memory_info",
            "num_ctx_switches",
            "cmdline",
            "create_time",
            "username",
        ] + addList

        # append num_fds field #
        if SysMgr.isLinux or SysMgr.isDarwin:
            attrs.append("num_fds")

        if filterList is None:
            pass
        else:
            filterList = SysMgr.filterGroup

        # define shortcut #
        now = self.procData
        prev = self.prevProcData

        # psutil.Process(pid=os.getpid())
        # psutil.pid_exists(pid=os.getpid())
        procs = psutil.process_iter(attrs=attrs, ad_value=None)
        for proc in procs:
            procInfo = proc.info
            pid = procInfo["pid"]
            comm = procInfo["name"]

            # check skip condition #
            if pid == 0:
                continue
            elif filterList:
                if not str(pid) in filterList and not UtilMgr.isValidStr(
                    comm, filterList
                ):
                    # increase total thread count #
                    if "num_threads" in procInfo and procInfo["num_threads"]:
                        self.nrThread += procInfo["num_threads"]
                    continue

            # info #
            now[pid] = dict(self.init_procData)
            now[pid]["mainID"] = pid
            now[pid]["comm"] = comm
            now[pid]["ppid"] = procInfo["ppid"]
            now[pid]["exe"] = procInfo["exe"]
            now[pid]["starttime"] = procInfo["create_time"]
            now[pid]["runtime"] = current - procInfo["create_time"]
            now[pid]["fdList"] = {}

            # cmdline #
            if procInfo["cmdline"]:
                now[pid]["cmdline"] = " ".join(procInfo["cmdline"])
            else:
                now[pid]["cmdline"] = None

            # priority #
            if not procInfo["nice"]:
                now[pid]["nice"] = " "
            else:
                if SysMgr.isWindows:
                    try:
                        pri = str(  # pylint: disable=bad-str-strip-call
                            procInfo["nice"]
                        ).strip("Priority.")
                        now[pid]["nice"] = ConfigMgr.SCHED_POLICY_WINDOWS[pri]
                    except SystemExit:
                        sys.exit(0)
                    except:
                        now[pid]["nice"] = " "
                else:
                    now[pid]["nice"] = procInfo["nice"]

            # thread count #
            if "num_threads" in procInfo and procInfo["num_threads"]:
                now[pid]["nrThread"] = procInfo["num_threads"]
                self.nrThread += procInfo["num_threads"]
            else:
                now[pid]["nrThread"] = 1
                self.nrThread += 1

            # file count #
            if "num_fds" in procInfo and procInfo["num_fds"]:
                now[pid]["nrFds"] = procInfo["num_fds"]
            else:
                now[pid]["nrFds"] = 0

            # user #
            if "username" in procInfo:
                now[pid]["user"] = procInfo["username"]
            else:
                now[pid]["user"] = ""

            # CPU #
            if "cpu_times" in procInfo and procInfo["cpu_times"]:
                utime = now[pid]["utime"] = procInfo["cpu_times"][0]
                if not utime:
                    utime = 0
                stime = now[pid]["stime"] = procInfo["cpu_times"][1]
                if not stime:
                    stime = 0
                ttime = now[pid]["ttime"] = utime + stime

                if pid in prev:
                    now[pid]["utimeDiff"] = utime - prev[pid]["utime"]
                    now[pid]["stimeDiff"] = stime - prev[pid]["stime"]
                    now[pid]["ttimeDiff"] = (
                        now[pid]["utimeDiff"] + now[pid]["stimeDiff"]
                    )
                else:
                    now[pid]["utimeDiff"] = utime
                    now[pid]["stimeDiff"] = stime
                    now[pid]["ttimeDiff"] = utime + stime
            else:
                now[pid]["utime"] = now[pid]["utimeDiff"] = 0
                now[pid]["stime"] = now[pid]["stimeDiff"] = 0
                now[pid]["ttime"] = now[pid]["ttimeDiff"] = 0

            # Memory #
            if "memory_info" in procInfo and procInfo["memory_info"]:
                now[pid]["rss"] = procInfo["memory_info"][0] >> 20  # MB #
                now[pid]["vss"] = procInfo["memory_info"][1] >> 30  # GB #
                nrpgflt = now[pid]["nrpgflt"] = procInfo["memory_info"][2]
                if pid in prev:
                    now[pid]["nrpgfltDiff"] = nrpgflt - prev[pid]["nrpgflt"]
                else:
                    now[pid]["nrpgfltDiff"] = nrpgflt
            else:
                now[pid]["rss"] = 0
                now[pid]["vss"] = 0
                now[pid]["nrpgfltDiff"] = now[pid]["nrpgflt"] = 0

            # Context switch #
            if "num_ctx_switches" in procInfo and procInfo["num_ctx_switches"]:
                nryield = now[pid]["yield"] = procInfo["num_ctx_switches"][0]
                nrpreempted = now[pid]["preempted"] = procInfo[
                    "num_ctx_switches"
                ][1]

                if pid in prev:
                    now[pid]["yieldDiff"] = nryield - prev[pid]["yield"]
                    now[pid]["preemptedDiff"] = (
                        nrpreempted - prev[pid]["preempted"]
                    )
                else:
                    now[pid]["yieldDiff"] = nryield
                    now[pid]["preemptedDiff"] = nrpreempted
            else:
                now[pid]["yield"] = now[pid]["yieldDiff"] = 0
                now[pid]["preempted"] = now[pid]["preemptedDiff"] = 0

            if "open_files" in attrs and procInfo["open_files"]:
                now[pid]["open_files"] = procInfo["open_files"]

            # TODO: proc.io_counters() on windows #

            continue

            # control #
            proc.is_running()
            proc.send_signal(0)
            proc.suspend()
            proc.resume()
            proc.terminate()
            proc.kill()
            proc.wait()

    def saveSystemStat(self, target="task"):
        # update uptime #
        SysMgr.updateUptime()

        # read CPU buf #
        cpuBuf = SysMgr.readProcStat(
            SysMgr.statFd, "stat", SysMgr, "statFd", True
        )

        # stat list from http://man7.org/linux/man-pages/man5/proc.5.html #
        if cpuBuf:
            for line in cpuBuf:
                statList = line.split()
                cpuId = statList[0]
                if cpuId == "cpu":
                    if not "all" in self.cpuData:
                        self.cpuData["all"] = {
                            "user": long(statList[1]),
                            "nice": long(statList[2]),
                            "system": long(statList[3]),
                            "idle": long(statList[4]),
                            "iowait": long(statList[5]),
                            "irq": long(statList[6]),
                            "softirq": long(statList[7]),
                        }
                elif cpuId.startswith("cpu"):
                    if not long(cpuId[3:]) in self.cpuData:
                        self.cpuData[int(cpuId[3:])] = {
                            "user": long(statList[1]),
                            "nice": long(statList[2]),
                            "system": long(statList[3]),
                            "idle": long(statList[4]),
                            "iowait": long(statList[5]),
                            "irq": long(statList[6]),
                            "softirq": long(statList[7]),
                        }
                elif not cpuId in self.cpuData:
                    self.cpuData[cpuId] = {cpuId: long(statList[1])}

            # set the number of core #
            SysMgr.nrCore = 0
            for idx in list(self.cpuData):
                try:
                    SysMgr.maxCore = long(idx)
                    SysMgr.nrCore += 1
                except SystemExit:
                    sys.exit(0)
                except:
                    continue

        # save mem info #
        memBuf = SysMgr.getMemInfo()
        if memBuf:
            self.prevMemData = self.memData
            self.memData = {}

            for line in memBuf:
                memList = line.split()
                self.memData[memList[0][:-1]] = long(memList[1])

        # save irq info #
        if SysMgr.irqEnable:
            self.saveIrqs()

        # save memory info #
        if SysMgr.memEnable:
            self.saveSlabInfo()
            self.saveZoneInfo()
            self.saveVmInfo()

        # save GPU memory info #
        self.gpuMemData = SysMgr.getGpuMem()

        # read vmstat buf #
        # vmstat list from https://access.redhat.com/solutions/406773 #
        self.prevVmData = self.vmData
        self.vmData = {}
        vmBuf = SysMgr.readProcStat(
            SysMgr.vmstatFd, "vmstat", SysMgr, "vmstatFd"
        )
        if vmBuf:
            for line in vmBuf:
                vmList = line.split()
                self.vmData[vmList[0]] = long(vmList[1])

        # read swap buf #
        swapBuf = SysMgr.readProcStat(SysMgr.swapFd, "swaps", SysMgr, "swapFd")
        # get swap usage if it changed #
        if self.prevSwaps != swapBuf and swapBuf:
            swapTotal = 0
            swapUsed = 0

            for line in swapBuf:
                swapList = line.split()
                # swapList = [Filename, Type, Size, Used, Priority] #
                try:
                    swapTotal += long(swapList[2])
                    swapUsed += long(swapList[3])
                except:
                    continue

            self.vmData["swapTotal"] = swapTotal
            self.vmData["swapUsed"] = swapUsed

            self.prevSwaps = swapBuf
        else:
            try:
                self.vmData["swapTotal"] = self.prevVmData["swapTotal"]
                self.vmData["swapUsed"] = self.prevVmData["swapUsed"]
            except:
                self.vmData["swapTotal"] = 0
                self.vmData["swapUsed"] = 0

        # save diskstats #
        SysMgr.updateDiskStats()

        # save netstat #
        try:
            SysMgr.netstatFd.seek(0)
            SysMgr.prevNetstat = SysMgr.netstat
            SysMgr.netstat = SysMgr.netstatFd.readlines()
        except SystemExit:
            sys.exit(0)
        except:
            try:
                netstatPath = "%s/%s" % (SysMgr.procPath, "net/netstat")
                SysMgr.netstatFd = open(netstatPath, "r")
                SysMgr.netstat = SysMgr.netstatFd.readlines()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenWarn(netstatPath)

        # read loadavg buf #
        try:
            SysMgr.loadavg = SysMgr.readProcStat(
                SysMgr.loadavgFd, "loadavg", SysMgr, "loadavgFd"
            )[0]
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # save battery #
        try:
            # TODO: save left percent, left second, charge status #
            """
            SysMgr.batteryFd.seek(0)
            battery = SysMgr.batteryFd.readlines()[0]
            SysMgr.battery = {}
            """
            pass
        except SystemExit:
            sys.exit(0)
        except:
            try:
                batteryPath = "/sys/class/power_supply/?/capacity"
                SysMgr.batteryFd = open(batteryPath, "r")
                battery = SysMgr.batteryFd.readlines()[0]
                SysMgr.battery = {}
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenWarn(batteryPath)

        # collect perf data #
        if SysMgr.perfEnable:
            SysMgr.collectSystemPerfData()

        # save GPU stat #
        self.saveGpuData()

        # check system-only monitoring #
        if not SysMgr.taskEnable:
            return

        # save proc stats #
        if target == "task":
            self.saveProcStat()
        elif target == "cgroup":
            self.saveCgroupStat()
        else:
            SysMgr.printErr("wrong monitor target for '%s'" % target)
            sys.exit(-1)

    @staticmethod
    def getProcTreeFromList(procInstance, kernel=True):
        procTree = {}
        ppidIdx = ConfigMgr.STAT_ATTR.index("PPID")

        # get a relation list to track ancestors of process #
        def _getRelationList(item, procInstance):
            tmpid = item
            relationList = []

            while 1:
                try:
                    if not tmpid in relationList:
                        relationList.insert(0, tmpid)

                    # add main thread ID #
                    if not procInstance[item]["isMain"]:
                        mainid = procInstance[item]["mainID"]
                        if not mainid in relationList:
                            relationList.insert(0, mainid)

                    # add parent process ID #
                    orig = tmpid
                    if SysMgr.isLinux:
                        tmpid = procInstance[tmpid]["stat"][ppidIdx]
                    else:
                        tmpid = procInstance[tmpid]["ppid"]

                    if long(tmpid) == 0 or orig == tmpid:
                        return relationList
                except SystemExit:
                    sys.exit(0)
                except:
                    return relationList

        # add items in relation list to tree #
        def _addItemsToList(relationList, procTree):
            nodePointer = procTree
            for item in relationList:
                try:
                    nodePointer[item]
                except:
                    nodePointer[item] = {}
                nodePointer = nodePointer[item]

        # make dictionary for tree #
        if SysMgr.isLinux:
            startIdx = ConfigMgr.STAT_ATTR.index("STARTTIME")
            for pid, item in sorted(
                procInstance.items(),
                key=lambda e: long(e[1]["stat"][startIdx]),
            ):
                # get parent ID #
                ppid = procInstance[pid]["stat"][ppidIdx]

                # check kernel thread #
                if not kernel and ppid == "2":
                    continue

                # add task #
                if ppid == "0":
                    procTree[pid] = {}
                else:
                    relationList = _getRelationList(pid, procInstance)
                    _addItemsToList(relationList, procTree)
        else:
            for pid, item in sorted(
                procInstance.items(), key=lambda e: long(e[1]["starttime"])
            ):
                ppid = procInstance[pid]["ppid"]

                # add task #
                if ppid == "0":
                    procTree[pid] = {}
                else:
                    relationList = _getRelationList(pid, procInstance)
                    _addItemsToList(relationList, procTree)

        return procTree

    @staticmethod
    def readProcMemStats(path, tid, retPss=True, retShr=False):
        # check root permission #
        if not SysMgr.isRoot():
            return 0, 0

        buf = ""
        fpath = "%s/%s" % (path, "smaps")

        try:
            with open(fpath, "r") as fd:
                buf = fd.readlines()
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenWarn(fpath)
            return 0, 0

        # check buf #
        if not buf:
            return 0, 0

        # get PSS #
        pss = 0
        shared = 0
        for line in buf:
            try:
                if retPss and line.startswith("Pss:"):
                    val = line.split()[1]
                    if val != "0":
                        pss += long(val)
                elif retShr and (
                    line.startswith("Shared_Clean:")
                    or line.startswith("Shared_Dirty:")
                ):
                    val = line.split()[1]
                    if val != "0":
                        shared += long(val)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn(
                    (
                        "failed to get memory stats "
                        "for the task having TID %s"
                    )
                    % tid,
                    reason=True,
                )

        return pss, shared

    @staticmethod
    def saveProcSmapsData(path, tid, mini=False):
        # check root permission #
        if not SysMgr.isRoot():
            return
        elif "NOSMAPS" in SysMgr.environList:
            return

        buf = ""
        mtype = ""
        stable = {}
        ftable = {}
        isInaccessible = False
        fpath = "%s/%s" % (path, "smaps")
        ptable = {"ANON": {}, "FILE": {}, "STACK": {}, "ETC": {}, "SHM": {}}

        if mini:
            checklist = (
                "Size:",
                "Rss:",
                "Pss:",
                "Shared_Clean:",
                "Shared_Dirty:",
            )
        else:
            checklist = (
                "Size:",
                "Rss:",
                "Pss:",
                "Shared_Clean:",
                "Shared_Dirty:",
                "Private_Dirty:",
                "Referenced:",
                "AnonHugePages:",
                "Swap:",
                "Locked:",
            )

        procData = SysMgr.procInstance

        # share the map table for main thread #
        try:
            ppid = procData[tid]["mainID"]
            if procData[ppid]["maps"]:
                procData[tid]["maps"] = procData[ppid]["maps"]
                return
        except SystemExit:
            sys.exit(0)
        except:
            pass

        try:
            procData[tid]["maps"] = ptable
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("failed to find the process with PID %s" % tid)
            return

        try:
            with open(fpath, "r") as fd:
                buf = fd.readlines()
        except SystemExit:
            sys.exit(0)
        except:
            procData[tid]["maps"] = None
            SysMgr.printOpenWarn(fpath)
            return

        # check buf #
        if not buf:
            return

        for line in buf:
            d = {}
            tmplist = line.split()

            # memory map info #
            if not line[0].isupper():
                perm = tmplist[1]

                """
                range = tmplist[0]
                offset = tmplist[2]
                devid = tmplist[3]
                inode = tmplist[4]
                """

                if len(tmplist) > 5:
                    ptype = tmplist[5]
                else:
                    ptype = ""

                # shared memory #
                if perm[3] == "s":
                    mtype = "SHM"
                    stable[ptype] = 0
                # file-mapped memory #
                elif ptype.startswith("/"):
                    mtype = "FILE"
                    ftable[ptype] = 0
                # anonymous memory #
                elif (
                    ptype == ""
                    or ptype.startswith("[heap]")
                    or ptype.startswith("[anon")
                ):
                    mtype = "ANON"
                # stack memory #
                elif ptype.startswith("[stack"):
                    mtype = "STACK"
                else:
                    mtype = "ETC"

                # check inaccessible area #
                isInaccessible = perm.startswith("---")

                try:
                    ptable[mtype]["count"] += 1
                except:
                    ptable[mtype]["count"] = 1
            # memory detail info #
            else:
                # skip 0 size attributes #
                if tmplist[-2] == "0":
                    continue

                # skip useless attributes #
                prop = tmplist[0]
                if not prop in checklist:
                    continue

                try:
                    val = long(tmplist[1])
                    try:
                        ptable[mtype][prop] += val
                    except:
                        ptable[mtype][prop] = val

                    if isInaccessible:
                        try:
                            ptable[mtype]["NOPM"] += val
                        except:
                            ptable[mtype]["NOPM"] = val
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

        # save the number of mapping #
        ptable["FILE"]["count"] = len(ftable)
        ptable["SHM"]["count"] = len(stable)

        # share the map table for main thread #
        try:
            ppid = procData[tid]["mainID"]
            procData[ppid]["maps"] = procData[tid]["maps"]
        except:
            pass

    def saveProcWchanData(self, path, tid):
        if not SysMgr.isRoot():
            self.procData[tid]["wchan"] = "EPERM"
            return

        wchanBuf = self.saveTaskData(path, tid, "wchan")

        try:
            if wchanBuf[0] == "0":
                self.procData[tid]["wchan"] = "RUNNING"
            else:
                self.procData[tid]["wchan"] = wchanBuf[0]
        except SystemExit:
            sys.exit(0)
        except:
            self.procData[tid]["wchan"] = ""

    def saveGpuData(self):
        try:
            if not SysMgr.gpuEnable or not self.gpuCoreList:
                return
        except:
            self.gpuCoreList = {}
            self.gpuNameList = {}

        devList = ["/sys/devices", "/sys/class"]

        # initialize candidates for GPU devices #
        if not self.gpuCoreList:
            candList = self.gpuCoreList
            for devPath in devList:
                # check permission #
                if not os.access(devPath, os.R_OK) or not os.path.isdir(
                    devPath
                ):
                    continue

                for targetDir in os.listdir(devPath):
                    path = "%s/%s" % (devPath, targetDir)
                    if path in candList:
                        continue

                    # get node list #
                    if os.access(path, os.R_OK) and os.path.isdir(path):
                        nodes = os.listdir(path)
                    else:
                        continue

                    # NVIDIA tegra #
                    if "devfreq" in nodes:
                        candList[path] = {}
                        self.gpuNameList[path] = "NVIDIA"

                    # QUALCOMM #
                    if "kgsl-3d0" in nodes:
                        name = "%s/%s/devfreq" % (path, "kgsl-3d0")
                        candList[name] = {}
                        self.gpuNameList[name] = "QUALCOMM"

        # no GPU supported #
        if not self.gpuCoreList:
            SysMgr.gpuEnable = False
            return

        # read GPU stat from list #
        for cand, value in self.gpuCoreList.items():
            try:
                target = None

                # set GPU name #
                gpuName = self.gpuNameList[cand]

                # save device info for NVIDIA #
                if gpuName.startswith("NVIDIA"):
                    devName = cand[cand.rfind("/") + 1 :]
                    target = "%s/%s" % (gpuName, devName)
                    self.gpuData[target] = {}
                    nodePath = "%s/devfreq/%s" % (cand, devName)

                    if not "uevent" in value:
                        self.gpuCoreList[cand]["uevent"] = open(
                            "%s/uevent" % cand, "r"
                        )
                    fd = self.gpuCoreList[cand]["uevent"]
                    fd.seek(0)

                    for item in fd.readlines():
                        attr, value = item[:-1].split("=")
                        self.gpuData[target][attr] = value

                    # save GPU device load #
                    if not "load" in value:
                        self.gpuCoreList[cand]["load"] = open(
                            "%s/load" % cand, "r"
                        )
                    fd = self.gpuCoreList[cand]["load"]
                    fd.seek(0)
                    self.gpuData[target]["CUR_LOAD"] = (
                        long(fd.readline()[:-1]) / 10
                    )

                # save device info for QUALCOMM #
                elif gpuName.startswith("QUALCOMM"):
                    realCand = cand.rstrip("/devfreq")
                    devName = realCand[realCand.rfind("/") + 1 :]
                    target = "%s/%s" % (gpuName, devName)
                    self.gpuData[target] = {}
                    nodePath = cand

                    # save GPU device load #
                    value = {}
                    try:
                        self.gpuCoreList[cand]["load"] = open(
                            "%s/gpu_busy_percentage" % realCand, "r"
                        )
                        fd = self.gpuCoreList[cand]["load"]
                        fd.seek(0)
                        self.gpuData[target]["CUR_LOAD"] = long(
                            fd.readline()[:-3]
                        )
                    except SystemExit:
                        sys.exit(0)
                    except:
                        self.gpuCoreList[cand]["load"] = open(
                            "%s/gpu_load" % cand, "r"
                        )
                        fd = self.gpuCoreList[cand]["load"]
                        fd.seek(0)
                        self.gpuData[target]["CUR_LOAD"] = long(
                            fd.readline()[:-1]
                        )

                # save current clock of GPU device #
                if not "curfreq" in value:
                    self.gpuCoreList[cand]["curfreq"] = open(
                        "%s/cur_freq" % nodePath, "r"
                    )
                fd = self.gpuCoreList[cand]["curfreq"]
                fd.seek(0)
                self.gpuData[target]["CUR_FREQ"] = (
                    long(fd.readline()[:-1]) / 1000000
                )

                # save min clock of GPU device #
                if not "minfreq" in value:
                    self.gpuCoreList[cand]["minfreq"] = open(
                        "%s/min_freq" % nodePath, "r"
                    )
                fd = self.gpuCoreList[cand]["minfreq"]
                fd.seek(0)
                self.gpuData[target]["MIN_FREQ"] = (
                    long(fd.readline()[:-1]) / 1000000
                )

                # save max clock of GPU device #
                if not "maxfreq" in value:
                    self.gpuCoreList[cand]["maxfreq"] = open(
                        "%s/max_freq" % nodePath, "r"
                    )
                fd = self.gpuCoreList[cand]["maxfreq"]
                fd.seek(0)
                self.gpuData[target]["MAX_FREQ"] = (
                    long(fd.readline()[:-1]) / 1000000
                )
            except SystemExit:
                sys.exit(0)
            except:
                pass

    def saveProcSchedData(self, path, tid):
        self.procData[tid]["execTime"] = 0
        self.procData[tid]["waitTime"] = 0

        if SysMgr.minStatEnable or not SysMgr.schedstatEnable:
            return

        try:
            schedBuf = self.saveTaskData(path, tid, "schedstat")
            if not schedBuf:
                if not os.path.exists("%s/1/schedstat" % SysMgr.procPath):
                    SysMgr.schedstatEnable = False
                return

            SCHED_POLICY = schedBuf[0].split()
            self.procData[tid]["execTime"] = float(SCHED_POLICY[0])
            self.procData[tid]["waitTime"] = float(SCHED_POLICY[1])
            self.procData[tid]["nrSlice"] = float(SCHED_POLICY[2])
        except SystemExit:
            sys.exit(0)
        except:
            return

    def isKernelThread(self, tid):
        ppid = self.procData[tid]["stat"][self.ppidIdx]
        if ppid == "2" or tid == "2":
            return True
        else:
            return False

    def saveCmdlineData(self, path, tid):
        if not SysMgr.cmdlineEnable:
            return

        if "cmdline" in self.procData[tid]:
            return self.procData[tid]["cmdline"]

        if not path:
            path = "%s/%s" % (SysMgr.procPath, tid)

        # check kernel thread #
        if self.isKernelThread(tid):
            self.procData[tid]["cmdline"] = ""
            return

        # check main thread to remove redundant operation #
        if SysMgr.checkMode("ttop"):
            mainID = self.procData[tid]["mainID"]
            if mainID in self.procData:
                if "cmdline" in self.procData[mainID]:
                    self.procData[tid]["cmdline"] = self.procData[mainID][
                        "cmdline"
                    ]
                    return

        # save cmdline info #
        self.procData[tid]["cmdline"] = SysMgr.getCmdline(tid)

        if SysMgr.checkMode("ttop"):
            if mainID in self.procData:
                self.procData[mainID]["cmdline"] = self.procData[tid][
                    "cmdline"
                ]

    def saveTaskData(self, path, tid, name, decode=True, retry=True):
        buf = []

        try:
            fd = "%sFd" % name
            self.procData[tid][fd] = self.prevProcData[tid][fd]
            while 1:
                self.prevProcData[tid][fd].seek(0)
                buf = self.procData[tid][fd].readlines()
                # retry to read for shared descriptor #
                if buf or not retry:
                    break
        except SystemExit:
            sys.exit(0)
        except:
            try:
                newPath = "%s/%s" % (path, name)
                newFd = self.procData[tid][fd] = open(newPath, "rb")
                buf = newFd.readlines()

                # fd resource is about to run out #
                if SysMgr.maxKeepFd < newFd.fileno():
                    newFd.close()
                    self.procData[tid][fd] = None
                    self.reclaimFds()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenWarn(newPath)

        # decode data #
        if decode and sys.version_info >= (3, 0):
            buf = list(map(lambda x: x.decode(), buf))

        return buf

    def saveCgroupData(self, path, tid):
        if not SysMgr.cgroupEnable:
            return

        cgroupBuf = self.saveTaskData(path, tid, "cgroup")

        cstr = ""
        indentlen = 39
        linelen = indentlen + 3
        for item in cgroupBuf:
            clist = item[:-1].split(":")
            if len(clist) != 3 or clist[-1] == "/":
                continue

            new = "%s:%s, " % (clist[1], clist[2])

            if cstr and linelen + len(new) > SysMgr.ttyCols:
                indent = "\n{0:>{ilen}} | ".format(" ", ilen=indentlen)
                linelen = len(indent) + len(new)
            else:
                indent = ""
                linelen += len(new)

            cstr = "%s%s%s" % (cstr, indent, new)

        if cstr:
            self.procData[tid]["cgroup"] = cstr[:-2]

    def saveProcStatusData(self, path, tid):
        if SysMgr.minStatEnable or not tid in self.procData:
            return

        isKernelThread = self.isKernelThread(tid)

        # PID/status #
        stat = "status"
        # no memory and context switch for kernel threads in process mode #
        if SysMgr.processEnable and isKernelThread:
            pass
        elif not self.procData[tid][stat]:
            statusBuf = self.saveTaskData(path, tid, stat, False)
            if not self.procData[tid]["status"]:
                self.procData[tid]["status"] = {}

            # check status change #
            self.procData[tid]["statusOrig"] = statusBuf
            if (
                tid in self.prevProcData
                and "statusOrig" in self.prevProcData[tid]
                and self.prevProcData[tid]["statusOrig"] == statusBuf
            ):
                self.procData[tid]["status"] = self.prevProcData[tid]["status"]
            else:
                # decode items #
                if sys.version_info >= (3, 0):
                    statusBuf = list(map(lambda x: x.decode(), statusBuf))

                for line in statusBuf:
                    try:
                        statusList = line.split(":", 1)
                        self.procData[tid]["status"][
                            statusList[0]
                        ] = statusList[1].strip()
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass

        # PID/statm #
        stat = "statm"
        if not self.procData[tid][stat]:
            mainID = self.procData[tid]["mainID"]

            # kernel thread #
            if isKernelThread:
                pass
            # sibling thread #
            elif (
                mainID in self.procData
                and stat in self.procData[mainID]
                and self.procData[mainID][stat]
            ):
                self.procData[tid][stat] = self.procData[mainID][stat]
            # main thread #
            else:
                statmBuf = self.saveTaskData(path, tid, stat)
                if statmBuf:
                    self.procData[tid][stat] = statmBuf[0].split()
                    if mainID in self.procData:
                        self.procData[mainID][stat] = self.procData[tid][stat]

    def saveProcData(self, path, tid, pid=None):
        def _getStatBuf(self, path, tid):
            fd = os.open(path, os.O_RDONLY)
            self.procData[tid]["statFd"] = fd
            statBuf = os.read(fd, 1024)
            self.procFdData[tid] = fd

            if tid in self.prevProcData:
                self.prevProcData[tid]["alive"] = True

            # fd resource is about to run out #
            if SysMgr.maxKeepFd < fd:
                os.close(fd)
                self.procData[tid]["statFd"] = None
                self.reclaimFds()

            return statBuf

        if not path:
            path = "%s/%s" % (SysMgr.procPath, tid)

        # initialize task #
        if not tid in self.procData:
            if not pid:
                pid = tid
            self.procData[tid] = dict(self.init_procData)
            self.procData[tid]["mainID"] = pid
            self.procData[tid]["taskPath"] = path
            self.procData[tid]["fdList"] = {}

        statPath = "%s/%s" % (path, "stat")

        # save stat data #
        try:
            try:
                prevFd = self.prevProcData[tid]["statFd"]
                self.procData[tid]["statFd"] = prevFd
                while 1:
                    os.lseek(prevFd, 0, 0)
                    statBuf = os.read(prevFd, 1024)
                    # retry to read for shared descriptor #
                    if statBuf:
                        break
                self.prevProcData[tid]["alive"] = True
            except SystemExit:
                sys.exit(0)
            except:
                statBuf = _getStatBuf(self, statPath, tid)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenWarn(statPath)
            self.procData.pop(tid, None)
            self.abnormalTasks[pid] = "?"
            return False

        # check stat change #
        self.procData[tid]["statOrig"] = statBuf
        if (
            tid in self.prevProcData
            and "statOrig" in self.prevProcData[tid]
            and self.prevProcData[tid]["statOrig"] == statBuf
        ):
            self.procData[tid]["stat"] = self.prevProcData[tid]["stat"]
            del self.prevProcData[tid]["statOrig"]
            self.procData[tid]["changed"] = False
        else:
            # convert string to list #
            statList = statBuf.decode().split()
            if len(statList) + 1 < self.statCnt:
                SysMgr.printWarn(
                    "failed to read stat for the task having TID %s" % tid
                )
                self.procData.pop(tid, None)
                return False

            # merge comm parts that splited by space #
            statList = SysMgr.mergeCommStat(statList, self.commIdx)

            # convert type of values #
            self.procData[tid]["stat"] = statList
            statList[self.majfltIdx] = long(statList[self.majfltIdx])
            statList[self.utimeIdx] = long(statList[self.utimeIdx])
            statList[self.stimeIdx] = long(statList[self.stimeIdx])
            statList[self.btimeIdx] = long(statList[self.btimeIdx])
            statList[self.cutimeIdx] = long(statList[self.cutimeIdx])
            statList[self.cstimeIdx] = long(statList[self.cstimeIdx])

        # check task status #
        tstat = self.procData[tid]["stat"][self.statIdx]
        if tstat != "S" and tstat != "R" and tstat != "I":
            self.abnormalTasks[tid] = tstat

        # set comm #
        comm = self.procData[tid]["comm"] = self.procData[tid]["stat"][
            self.commIdx
        ].strip("()")

        # change sched priority #
        for item in SysMgr.schedFilter:
            target = str(item[2])
            if not target:
                target = tid
            elif tid != target and not target in comm:
                continue

            # set deadline sched #
            if item[0].upper() == "D":
                runtime, deadline, period = SysMgr.getDeadlineArgs(item[1])

                SysMgr.setDeadlinePriority(
                    long(tid), runtime, deadline, period
                )
            # set other scheds #
            else:
                SysMgr.setPriority(long(tid), item[0], long(item[1]))

        # change CPU affinity #
        if SysMgr.affinityFilter:
            alist = list(SysMgr.affinityFilter)
            for idx, item in enumerate(alist):
                val = item[0]
                if not val:
                    target = tid
                elif tid != val and not val in comm:
                    continue

                try:
                    mask = item[1]
                    if val == tid or val in comm:
                        SysMgr.setAffinity(mask, [tid])

                    flag = item[2]
                    if flag != "CONT":
                        SysMgr.affinityFilter.remove(item)
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

        # send signal #
        if SysMgr.killFilter:
            slist = list(SysMgr.killFilter)
            for idx, item in enumerate(slist):
                val = item[0]
                sig = item[1]
                flag = item[2]
                if tid != val and not val in comm:
                    continue

                try:
                    os.kill(long(tid), sig)
                    SysMgr.printInfo(
                        "sent %s to %s(%s)"
                        % (ConfigMgr.SIG_LIST[sig], comm, tid)
                    )
                    if flag != "CONT":
                        SysMgr.killFilter.remove(item)
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

        # save I/O data #
        if SysMgr.blockEnable:
            ioBuf = self.saveTaskData(path, tid, "io")
            # check I/O support in proc filesystem #
            if not ioBuf and not os.path.isfile(
                "%s/self/io" % SysMgr.procPath
            ):
                SysMgr.printWarn(
                    "failed to use bio event, please check kernel configs"
                )
                SysMgr.blockEnable = False
            self.procData[tid]["ioData"] = ioBuf

            # check I/O data #
            if (
                tid in self.prevProcData
                and "ioData" in self.prevProcData[tid]
                and self.prevProcData[tid]["ioData"] == ioBuf
            ):
                self.procData[tid]["io"] = self.prevProcData[tid]["io"]
            else:
                self.procData[tid]["io"] = {}
                for line in ioBuf:
                    # get stats #
                    ios = line.split()
                    if len(ios) != 2:
                        continue

                    # check stats #
                    name, val = ios
                    if not name in ("read_bytes:", "write_bytes:"):
                        continue

                    # save stats #
                    self.procData[tid]["io"][name[:-1]] = long(val)

        # save perf fds #
        if (
            SysMgr.perfGroupEnable
            and tid in self.prevProcData
            and "perfFds" in self.prevProcData[tid]
        ):
            self.procData[tid]["perfFds"] = self.prevProcData[tid]["perfFds"]

        # save oom_score #
        if SysMgr.oomEnable:
            self.updateOOMScore(path, tid)

        # save namespace #
        if SysMgr.nsEnable:
            self.updateNamespace(path, tid)

        return True

    def updateNamespace(self, path, tid):
        if not SysMgr.isLinux:
            return

        nsPath = "%s/%s" % (path, "ns")
        try:
            self.procData[tid]["ns"] = ""
            for items in os.walk(nsPath):
                for node in items[2]:
                    value = os.readlink(os.path.join(items[0], node))[
                        len(node) + 1 :
                    ]
                    if not value:
                        continue

                    # update global info #
                    value = value[1:-1]
                    self.nsData.setdefault(node, {})
                    self.nsData[node].setdefault(value, {})
                    self.nsData[node][value].setdefault(tid, 0)

                    # update task info #
                    self.procData[tid]["ns"] += "%s:%s, " % (node, value)
        except SystemExit:
            sys.exit(0)
        except:
            comm = self.procData[tid]["stat"][self.commIdx].strip("()")
            SysMgr.printWarn(
                "failed to read namespace value for %s(%s)" % (comm, tid),
                reason=True,
            )

    def updateOOMScore(self, path, tid):
        if not SysMgr.isLinux:
            return

        # check main thread to remove redundant operation #
        if not SysMgr.processEnable:
            mainID = self.procData[tid]["mainID"]
            if mainID in self.procData:
                if "oomScore" in self.procData[mainID]:
                    self.procData[tid]["oomScore"] = self.procData[mainID][
                        "oomScore"
                    ]
                    self.procData[tid]["oomFd"] = self.procData[mainID][
                        "oomFd"
                    ]
                    return

        try:
            self.prevProcData[tid]["oomFd"].seek(0)
            self.procData[tid]["oomFd"] = self.prevProcData[tid]["oomFd"]
            self.procData[tid]["oomScore"] = long(
                self.procData[tid]["oomFd"].readline()
            )
        except SystemExit:
            sys.exit(0)
        except:
            try:
                oomPath = "%s/%s" % (path, "oom_score")
                oomFd = self.procData[tid]["oomFd"] = open(oomPath, "r")
                self.procData[tid]["oomScore"] = long(
                    self.procData[tid]["oomFd"].readline()
                )

                # fd resource is about to run out #
                if SysMgr.maxKeepFd < oomFd.fileno():
                    oomFd.close()
                    self.procData[tid]["oomFd"] = None
                    self.reclaimFds()
                elif SysMgr.checkMode("ttop"):
                    if mainID in self.procData:
                        self.procData[mainID]["oomScore"] = self.procData[tid][
                            "oomScore"
                        ]
                        self.procData[mainID]["oomFd"] = self.procData[tid][
                            "oomFd"
                        ]
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenWarn(oomPath)

                self.procData.pop(tid, None)

    def reclaimFds(self, nrReq=64):
        nrRclm = 0
        for pid, val in sorted(self.procData.items(), key=lambda x: int(x[0])):
            for item in val:
                if not item.endswith("Fd"):
                    continue

                # close file descriptors #
                try:
                    if isinstance(val[item], (int, long)):
                        os.close(val[item])
                    else:
                        val[item].close()

                    val[item] = None
                    nrRclm += 1
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

            # return the number of closed files #
            if nrRclm >= nrReq:
                return nrRclm

    def printSystemUsage(self):
        # define shortcut #
        convColor = UtilMgr.convColor
        convCpuColor = UtilMgr.convCpuColor
        convSize = UtilMgr.convSize2Unit

        vmData = self.vmData
        prevVmData = self.prevVmData
        memData = self.memData
        prevMemData = self.prevMemData
        failedStat = []

        # total memory #
        try:
            totalMem = memData["MemTotal"] >> 10
        except SystemExit:
            sys.exit(0)
        except:
            totalMem = 0
            failedStat.append("MemTotal")

        # free memory #
        try:
            freeMem = memData["MemFree"] >> 10
            freeMemDiff = freeMem - (prevMemData["MemFree"] >> 10)
            freeMemPer = long(freeMem / float(totalMem) * 100)

            # add free memory interval #
            self.addSysInterval("mem", "free", freeMem)
        except SystemExit:
            sys.exit(0)
        except:
            freeMem = freeMemDiff = freeMemPer = 0
            failedStat.append("MemFree")

        # available memory #
        try:
            assert not SysMgr.freeMemEnable

            # assume MemAvailable #
            if not "MemAvailable" in memData:
                memData["MemAvailable"] = (
                    memData["MemFree"]
                    + memData["Inactive(file)"]
                    + memData["SReclaimable"]
                    + memData["SwapCached"]
                )

            availMem = memData["MemAvailable"] >> 10
            if "MemAvailable" in prevMemData:
                availMemDiff = availMem - (prevMemData["MemAvailable"] >> 10)
            else:
                availMemDiff = 0

            availMemPer = long(availMem / float(totalMem) * 100)

            # add available memory interval #
            self.addSysInterval("mem", "available", availMem)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.freeMemEnable = True
            availMem = availMemDiff = availMemPer = 0

        # anonymous memory #
        try:
            actAnonMem = vmData["nr_active_anon"] >> 8
            inactAnonMem = vmData["nr_inactive_anon"] >> 8
            totalAnonMem = vmData["nr_anon_pages"] >> 8
            anonMemDiff = (
                vmData["nr_anon_pages"] - self.prevVmData["nr_anon_pages"]
            ) >> 8

            # add anon memory interval #
            self.addSysInterval("mem", "anon", totalAnonMem)
        except SystemExit:
            sys.exit(0)
        except:
            actAnonMem = inactAnonMem = totalAnonMem = anonMemDiff = 0
            failedStat.append("MemAnon")

        # file memory #
        try:
            actFileMem = vmData["nr_active_file"] >> 8
            inactFileMem = vmData["nr_inactive_file"] >> 8
            totalFileMem = vmData["nr_file_pages"] >> 8
            fileMemDiff = (
                vmData["nr_file_pages"] - self.prevVmData["nr_file_pages"]
            ) >> 8

            # add file cache interval #
            self.addSysInterval("mem", "file", totalFileMem)
        except SystemExit:
            sys.exit(0)
        except:
            actFileMem = inactFileMem = totalFileMem = fileMemDiff = 0
            failedStat.append("MemFile")

        # dirty memory #
        try:
            pgDirty = vmData["nr_dirty"]

            """
            dirtyRatio = \
                long((vmData['nr_dirty'] / \
                float(vmData['nr_dirty_threshold'])) * 100)
            dirtyBgRatio = \
                long((vmData['nr_dirty'] / \
                float(vmData['nr_dirty_background_threshold'])) * 100)
            """
        except SystemExit:
            sys.exit(0)
        except:
            pgDirty = 0
            failedStat.append("MemDirty")

        # slab memory #
        try:
            slabReclm = vmData["nr_slab_reclaimable"] >> 8
            slabUnReclm = vmData["nr_slab_unreclaimable"] >> 8
            slabReclmDiff = (
                vmData["nr_slab_reclaimable"]
                - self.prevVmData["nr_slab_reclaimable"]
            )
            slabUnReclmDiff = (
                vmData["nr_slab_unreclaimable"]
                - self.prevVmData["nr_slab_unreclaimable"]
            )
            totalSlabMem = (
                vmData["nr_slab_reclaimable"] + vmData["nr_slab_unreclaimable"]
            ) >> 8
            slabMemDiff = (slabReclmDiff + slabUnReclmDiff) >> 8

            # add slab cache interval #
            self.addSysInterval("mem", "slab", totalSlabMem)
        except SystemExit:
            sys.exit(0)
        except:
            slabReclm = (
                slabUnReclm
            ) = (
                slabReclmDiff
            ) = slabUnReclmDiff = totalSlabMem = slabMemDiff = 0
            failedStat.append("MemSlab")

        totalCacheMem = totalFileMem + totalSlabMem

        # kernel memory #
        try:
            totalKernelMem = totalMem - (
                totalAnonMem + totalCacheMem + freeMem
            )
        except SystemExit:
            sys.exit(0)
        except:
            totalKernelMem = 0

        # fault #
        try:
            nrMajFault = vmData["pgmajfault"] - self.prevVmData["pgmajfault"]
            nrTotalFault = vmData["pgfault"] - self.prevVmData["pgfault"]
            nrMinFault = nrTotalFault - nrMajFault
        except SystemExit:
            sys.exit(0)
        except:
            nrMajFault = nrTotalFault = nrMinFault = 0
            failedStat.append("MemFault")

        # paged in/out from/to disk #
        try:
            if SysMgr.totalEnable:
                prevpgpgin = 0
                prevpgpgout = 0
            else:
                prevpgpgin = self.prevVmData["pgpgin"]
                prevpgpgout = self.prevVmData["pgpgout"]

            pgInMemDiff = (vmData["pgpgin"] - prevpgpgin) >> 10
            pgOutMemDiff = (vmData["pgpgout"] - prevpgpgout) >> 10
        except SystemExit:
            sys.exit(0)
        except:
            pgInMemDiff = pgOutMemDiff = 0
            failedStat.append("MemPg")

        # swap memory #
        try:
            swapTotal = vmData["swapTotal"] >> 10
            swapUsage = vmData["swapUsed"] >> 10
            swapFree = swapTotal - swapUsage
            prevVmData = self.prevVmData
            if swapTotal:
                swapUsagePer = long(swapUsage / float(swapTotal) * 100)
            else:
                swapUsagePer = 0
            swapUsageDiff = (prevVmData["swapUsed"] - vmData["swapUsed"]) >> 10
            swapInMem = (vmData["pswpin"] - prevVmData["pswpin"]) >> 10
            swapOutMem = (vmData["pswpout"] - prevVmData["pswpout"]) >> 10
        except SystemExit:
            sys.exit(0)
        except:
            swapTotal = (
                swapUsage
            ) = swapUsageDiff = swapUsagePer = swapInMem = swapOutMem = 0
            failedStat.append("MemSwap")

        # background reclaim #
        try:
            # init variable #
            pgRclmBg = 0

            if SysMgr.totalEnable:
                prevData = None
            else:
                prevData = self.prevVmData

            # accumulate the number of pages #
            for name in list(ConfigMgr.BGRECLAIMSTAT):
                try:
                    prevStat = prevData[name]
                except:
                    prevStat = 0

                try:
                    pgRclmBg += vmData[name] - prevStat
                except:
                    ConfigMgr.BGRECLAIMSTAT.remove(name)

            # calculate the count #
            try:
                nrBgReclaim = (
                    vmData["pageoutrun"] - self.prevVmData["pageoutrun"]
                )
            except SystemExit:
                sys.exit(0)
            except:
                nrBgReclaim = 0
        except SystemExit:
            sys.exit(0)
        except:
            pgRclmBg = nrBgReclaim = 0
            failedStat.append("MemBgReclaim")

        # add background reclaim interval #
        self.addSysInterval("mem", "pgRclmBg", pgRclmBg)

        # direct reclaim #
        try:
            pgRclmFg = 0

            if SysMgr.totalEnable:
                prevData = None
            else:
                prevData = self.prevVmData

            # accumulate the number of pages #
            for name in list(ConfigMgr.FGRECLAIMSTAT):
                try:
                    prevStat = prevData[name]
                except:
                    prevStat = 0

                try:
                    pgRclmFg += vmData[name] - prevStat
                except:
                    ConfigMgr.FGRECLAIMSTAT.remove(name)

            # calculate the count #
            try:
                nrDrReclaim = (
                    vmData["allocstall"] - self.prevVmData["allocstall"]
                )
            except SystemExit:
                sys.exit(0)
            except:
                nrDrReclaim = 0
        except SystemExit:
            sys.exit(0)
        except:
            pgRclmFg = nrDrReclaim = 0
            failedStat.append("MemFgReclaim")

        # add foreground reclaim interval #
        self.addSysInterval("mem", "pgRclmFg", pgRclmFg)

        # mlock #
        try:
            pgMlock = vmData["nr_mlock"]
            # mappedMem = vmData['nr_mapped'] >> 8
        except:
            pgMlock = 0
            failedStat.append("MemMlock")

        # pending #
        try:
            nrBlocked = self.cpuData["procs_blocked"]["procs_blocked"]
        except:
            nrBlocked = 0
            failedStat.append("NrBlocked")

        # cma mem #
        try:
            if "CmaTotal" in memData:
                cmaTotalMem = memData["CmaTotal"]

                if "CmaFree" in memData:
                    cmaFreeMem = memData["CmaFree"]
                else:
                    cmaFreeMem = 0
                if "CmaDeviceAlloc" in memData:
                    cmaDevMem = memData["CmaDeviceAlloc"]
                else:
                    cmaDevMem = 0
            else:
                cmaTotalMem = 0
        except SystemExit:
            sys.exit(0)
        except:
            cmaTotalMem = cmaFreeMem = cmaDevMem = 0
            failedStat.append("MemCma")

        """
        try:
            shMem = vmData['nr_shmem'] >> 8
            pageTableMem = vmData['nr_page_table_pages'] >> 8
            kernelStackMem = vmData['nr_kernel_stack'] * 8 >> 10
        except:
            failedStat.append('MemShm')
        """

        # check available memory type #
        if SysMgr.freeMemEnable:
            memTitle = "MemFre"
        else:
            memTitle = "MemAvl"

        # get iowait time #
        # iowait = SysMgr.getIowaitTime()

        # print failed stats #
        if failedStat:
            SysMgr.printWarn("failed to get %s stats" % ", ".join(failedStat))

        titleStr = (
            "{0:^7}|{1:>5}({2:^3}/{3:^3}/{4:^3}/{5:^3})|"
            "{6:>6}({7:>3}/{8:>6}/{9:>6}/{10:>5})|"
            "{11:>5}({12:>4}/{13:>3}/{14:>3})|{15:^11}|{16:^7}|{17:^7}|"
            "{18:^3}|{19:^8}|{20:^7}|{21:^8}|{22:^12}|\n"
        ).format(
            "ID",
            "CPU",
            "Usr",
            "Ker",
            "Blk",
            "IRQ",
            memTitle,
            "Per",
            "User",
            "Cache",
            "Kern",
            "Swap",
            "Per",
            "In",
            "Out",
            "PgRclm",
            "BlkRW",
            "NrFlt",
            "Blk",
            "NrSIRQ",
            "PgMlk",
            "PgDirt",
            "Network",
        )

        # print system status menu #
        SysMgr.addPrint(
            "%s\n%s%s\n" % (twoLine, titleStr, oneLine),
            newline=3,
        )

        # set interval #
        if SysMgr.totalEnable:
            interval = 1
        else:
            interval = SysMgr.uptimeDiff
            if interval == 0:
                return

        # set context switch #
        try:
            nrCtxSwc = (
                self.cpuData["ctxt"]["ctxt"] - self.prevCpuData["ctxt"]["ctxt"]
            )
            if nrCtxSwc < 0:
                nrCtxSwc = 0
        except SystemExit:
            sys.exit(0)
        except:
            nrCtxSwc = 0

        try:
            nrIrq = (
                self.cpuData["intr"]["intr"] - self.prevCpuData["intr"]["intr"]
            )
            if nrIrq < 0:
                nrIrq = 0
        except SystemExit:
            sys.exit(0)
        except:
            nrIrq = 0

        try:
            nrSoftIrq = (
                self.cpuData["softirq"]["softirq"]
                - self.prevCpuData["softirq"]["softirq"]
            )
            if nrSoftIrq < 0:
                nrSoftIrq = 0
        except SystemExit:
            sys.exit(0)
        except:
            nrSoftIrq = 0

        # get total CPU usage #
        try:
            nowData = self.cpuData["all"]
            prevData = self.prevCpuData["all"]
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to get system CPU stat")
            return

        # set maximum CPU usage #
        if SysMgr.cpuAvgEnable:
            nrCore = SysMgr.nrCore
            maxUsage = 100
        else:
            nrCore = 1
            maxUsage = 100 * SysMgr.nrCore

        # initialize accumulated CPU values #
        userUsage = kerUsage = ioUsage = irqUsage = idleUsage = 0
        coreStats = {}

        for idx in list(self.cpuData):
            try:
                nrIdx = long(idx)
                nowData = self.cpuData[nrIdx]

                # check previous data #
                if not nrIdx in self.prevCpuData:
                    coreStat = (
                        "{0:<7}|{1:>5}({2:^3}/{3:^3}/{4:^3}/{5:^3})|".format(
                            "Core/" + str(idx), "- %", "-", "-", "-", "-"
                        )
                    )
                    SysMgr.addPrint("%s\n" % coreStat)
                    continue

                # set previous stat #
                if SysMgr.totalEnable:
                    prevData = self.init_cpuData
                else:
                    prevData = self.prevCpuData[nrIdx]

                coreStats[idx] = {}

                # -------------------- SIMPLE STAT --------------------#
                userStat = nowData["user"] - prevData["user"]
                niceStat = nowData["nice"] - prevData["nice"]
                userCoreUsage = long((userStat + niceStat) / interval)

                kerCoreUsage = long(
                    (nowData["system"] - prevData["system"]) / interval
                )

                irqStat = nowData["irq"] - prevData["irq"]
                softirqStat = nowData["softirq"] - prevData["softirq"]
                irqCoreUsage = long((irqStat + softirqStat) / interval)

                ioCoreUsage = long(
                    (nowData["iowait"] - prevData["iowait"]) / interval
                )

                idleCoreUsage = long(
                    (nowData["idle"] - prevData["idle"]) / interval
                )

                # -------------------- REVISED STAT --------------------#
                if SysMgr.totalEnable:
                    scale = 1
                else:
                    # get scaled factor #
                    totalStat = (
                        userCoreUsage
                        + kerCoreUsage
                        + ioCoreUsage
                        + irqCoreUsage
                        + idleCoreUsage
                    )
                    scale = 100 / float(totalStat)

                # get CPU stats #
                coreStats[idx]["user"] = long(userCoreUsage * scale)
                userUsage += coreStats[idx]["user"]
                coreStats[idx]["kernel"] = long(kerCoreUsage * scale)
                kerUsage += coreStats[idx]["kernel"]
                coreStats[idx]["io"] = long(ioCoreUsage * scale)
                ioUsage += coreStats[idx]["io"]
                coreStats[idx]["irq"] = long(irqCoreUsage * scale)
                irqUsage += coreStats[idx]["irq"]
                coreStats[idx]["idle"] = long(idleCoreUsage * scale)
                idleUsage += coreStats[idx]["idle"]

                # check core filter #
                if SysMgr.perCoreList and not idx in SysMgr.perCoreList:
                    coreStats.pop(idx, None)
            except SystemExit:
                sys.exit(0)
            except:
                pass

        # divide total CPU usage by the number of cores #
        userUsage = long(userUsage / nrCore)
        kerUsage = long(kerUsage / nrCore)
        ioUsage = long(ioUsage / nrCore)
        irqUsage = long(irqUsage / nrCore)
        idleUsage = long(idleUsage / nrCore)

        # get total usage #
        if SysMgr.totalEnable:
            totalUsage = userUsage + kerUsage + irqUsage
        elif idleUsage < maxUsage:
            totalUsage = maxUsage - idleUsage - ioUsage
        else:
            totalUsage = 0

        # add CPU interval #
        SysMgr.cpuUsage = totalUsage
        self.addSysInterval("cpu", "total", totalUsage)
        self.addSysInterval("cpu", "user", userUsage)
        self.addSysInterval("cpu", "kernel", kerUsage)
        self.addSysInterval("cpu", "iowait", ioUsage)
        self.addSysInterval("cpu", "irq", irqUsage)

        # get network usage in bytes #
        if SysMgr.isLinux:
            (netIn, netOut) = self.getNetworkUsage(
                SysMgr.prevNetstat, SysMgr.netstat
            )
        else:
            netIn = SysMgr.netstat[0] - SysMgr.prevNetstat[0]
            netOut = SysMgr.netstat[1] - SysMgr.prevNetstat[1]

        # add network interval #
        self.addSysInterval("net", "inbound", netIn)
        self.addSysInterval("net", "outbound", netOut)

        # convert network usage #
        try:
            netIO = "%s/%s" % (convSize(netIn, True), convSize(netOut, True))
        except SystemExit:
            sys.exit(0)
        except:
            netIO = "-/-"

        # check available memory #
        if availMem == 0:
            availMem = freeMem
            availMemDiff = freeMemDiff
            availMemPer = freeMemPer

        # add memory interval #
        SysMgr.memAvail = availMem

        # convert color for CPU usage #
        totalUsageStr = r"%3s %%" % totalUsage
        totalUsageStr = convCpuColor(totalUsage, totalUsageStr)

        # convert color for mem available #
        availMemStr = r"%6s" % availMem
        if availMemPer == 0:
            pass
        elif availMemPer <= SysMgr.memAvailPerThreshold:
            availMemStr = convColor(availMemStr, "RED")
        else:
            availMemStr = convColor(availMemStr, "YELLOW")

        # convert color for block #
        ioUsageStr = r"%3s" % ioUsage
        if ioUsage > 0:
            ioUsageStr = convColor(ioUsageStr, "RED")

        # convert color for swap usage #
        swapUsageStr = r"%5s" % swapUsage
        if swapUsagePer == 0:
            pass
        else:
            # add swap device interval #
            self.addSysInterval("swap", "swap", swapUsagePer)

            if swapUsagePer >= SysMgr.swapPerThreshold:
                swapUsageStr = convColor(swapUsageStr, "RED")
            else:
                swapUsageStr = convColor(swapUsageStr, "YELLOW")

        # convert color for reclaim stats #
        pgRclmStr = r"%s/%s" % (pgRclmBg, pgRclmFg)
        pgRclmStr = r"{0:^11}".format(pgRclmStr)
        if pgRclmBg > 0 or pgRclmFg > 0:
            pgRclmStr = convColor(pgRclmStr, "RED")

        # convert color for I/O stats #
        pgIOMemDiffStr = r"%s/%s" % (pgInMemDiff, pgOutMemDiff)
        pgIOMemDiffStr = r"{0:^7}".format(pgIOMemDiffStr)
        if pgInMemDiff > 0 or pgOutMemDiff > 0:
            pgIOMemDiffStr = convColor(pgIOMemDiffStr, "RED")

        # convert color for network stats #
        if not (netIO == "-/-" or netIO == "0/0"):
            netIO = r"{0:^12}".format(netIO)
            netIO = convColor(netIO, "YELLOW")

        # make total stat string #
        totalCoreStat = (
            "{0:<7}|{1:>5}({2:>3}/{3:>3}/{4:>3}/{5:>3})|"
            "{6:>6}({7:>3}/{8:>6}/{9:>6}/{10:>5})|"
            "{11:>5}({12:>4}/{13:>3}/{14:>3})|{15:^11}|{16:^7}|"
            "{17:^7}|{18:^3}|{19:^8}|{20:^7}|{21:^8}|{22:^12}|\n"
        ).format(
            "Total",
            totalUsageStr,
            userUsage,
            kerUsage,
            ioUsageStr,
            irqUsage,
            availMemStr,
            availMemPer,
            totalAnonMem,
            totalCacheMem,
            totalKernelMem,
            swapUsageStr,
            swapUsagePer,
            swapInMem,
            swapOutMem,
            pgRclmStr,
            pgIOMemDiffStr,
            "%5s" % nrMajFault,
            nrBlocked,
            "%6s" % nrSoftIrq,
            "%5s" % pgMlock,
            "%6s" % pgDirty,
            netIO,
        )

        SysMgr.addPrint(totalCoreStat)

        # get CPU/GPU temperature #
        if SysMgr.isLinux and (SysMgr.cpuEnable or SysMgr.gpuEnable):
            coreTempData = {}
            tempDirList = []
            tempPath = "/sys/class/hwmon"

            try:
                self.tempFdList
            except:
                self.tempFdList = {}

            try:
                for item in os.listdir(tempPath):
                    devPath = "%s/%s/name" % (tempPath, item)
                    if os.path.isfile(devPath):
                        tempDirList.append(devPath)

                    devPath = "%s/%s/device/name" % (tempPath, item)
                    if os.path.isfile(devPath):
                        tempDirList.append(devPath)
            except SystemExit:
                sys.exit(0)
            except:
                pass

            tempPath = []
            for tempDir in tempDirList:
                try:
                    if tempDir in self.tempFdList:
                        fd = self.tempFdList[tempDir]
                        fd.seek(0)
                    else:
                        fd = open(tempDir, "r")
                        self.tempFdList[tempDir] = fd

                    if fd.readline()[:-1] == "coretemp":
                        tempPath.append(os.path.dirname(tempDir))
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

            # /sys/class/hwmon #
            for hwPath in tempPath:
                try:
                    hwdirs = os.listdir(hwPath)
                except SystemExit:
                    sys.exit(0)
                except:
                    continue

                tempDirList = [
                    "%s/%s" % (hwPath, item.replace("input", "label"))
                    for item in hwdirs
                    if item.endswith("_input")
                ]

                phyId = 0
                tempData = {}

                for tempDir in tempDirList:
                    try:
                        if tempDir in self.tempFdList:
                            lfd = self.tempFdList[tempDir]
                            lfd.seek(0)
                        else:
                            lfd = open(tempDir, "r")
                            self.tempFdList[tempDir] = lfd

                        name = lfd.readline()[:-1]
                        if name.startswith("Physical id ") or name.startswith(
                            "Package id "
                        ):
                            phyId = name[name.rfind(" ") + 1 :]
                        elif name.startswith("Core "):
                            coreId = name[name.rfind(" ") + 1 :]

                            tempDir = tempDir.replace("label", "input")
                            if tempDir in self.tempFdList:
                                tfd = self.tempFdList[tempDir]
                                tfd.seek(0)
                            else:
                                tfd = open(tempDir, "r")
                                self.tempFdList[tempDir] = tfd

                            tempData[coreId] = long(tfd.readline()[:-4])
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass

                for idx, val in sorted(
                    tempData.items(), key=lambda x: long(x[0])
                ):
                    coreTempData["%s-%s" % (phyId, idx)] = val

            # /sys/class/thermal #
            tempPath = "/sys/class/thermal"
            try:
                tempDirList = [
                    "%s/%s" % (tempPath, item)
                    for item in os.listdir(tempPath)
                    if item.startswith("thermal_zone")
                ]
            except SystemExit:
                sys.exit(0)
            except:
                tempDirList = []

            for tempDir in sorted(tempDirList):
                try:
                    ctype = None

                    with open("%s/type" % tempDir, "r") as fd:
                        ctype = fd.readline()[:-1]

                    with open("%s/temp" % tempDir, "r") as fd:
                        if "CPU" in ctype:
                            coreTempData["CPU"] = long(fd.readline()[:-4])
                        elif "GPU" in ctype:
                            coreTempData["GPU"] = long(fd.readline()[:-4])
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

        # print CPU stats #
        perCoreStats = {}
        if SysMgr.cpuEnable or SysMgr.reportEnable or SysMgr.jsonEnable:
            shortCoreStats = ""
            lenCoreStat = 0

            if self.cpuData:
                SysMgr.addPrint("%s\n" % oneLine)

            freqPath = "/sys/devices/system/cpu/cpu"

            # set max cols #
            if SysMgr.ttyCols >= len(oneLine):
                maxCols = len(oneLine) + 1
            else:
                maxCols = SysMgr.ttyCols

            # get CPU frequency #
            if not SysMgr.isLinux:
                try:
                    freqList = SysMgr.getPkg("psutil").cpu_freq(percpu=True)
                    if freqList and len(freqList) == 1:
                        freqList = [freqList[0]] * len(self.cpuData)
                except SystemExit:
                    sys.exit(0)
                except:
                    freqList = []

            # traverse core files #
            for idx in sorted(
                list(self.cpuData),
                key=lambda x: long(x) if UtilMgr.isNumber(x) else -1,
            ):
                try:
                    if idx == -1 or not idx in coreStats:
                        continue
                    elif SysMgr.checkCutCond():
                        return

                    # init per-core dict #
                    cid = None
                    perCoreStats[idx] = {}

                    # get CPU stats #
                    userCoreUsage = coreStats[idx]["user"]
                    kerCoreUsage = coreStats[idx]["kernel"]
                    ioCoreUsage = coreStats[idx]["io"]
                    irqCoreUsage = coreStats[idx]["irq"]
                    idleCoreUsage = coreStats[idx]["idle"]

                    # get total usage #
                    if SysMgr.totalEnable:
                        totalCoreUsage = (
                            userCoreUsage + kerCoreUsage + irqCoreUsage
                        )
                    elif idleCoreUsage < 100:
                        totalCoreUsage = 100 - idleCoreUsage - ioCoreUsage
                    else:
                        totalCoreUsage = 0

                    # limit total core usage in each modes #
                    if not SysMgr.totalEnable:
                        if userCoreUsage > 100:
                            userCoreUsage = 100
                        if kerCoreUsage > 100:
                            kerCoreUsage = 100

                    # set percore stats #
                    perCoreStats[idx]["user"] = userCoreUsage
                    perCoreStats[idx]["kernel"] = kerCoreUsage
                    perCoreStats[idx]["iowait"] = ioCoreUsage
                    perCoreStats[idx]["irq"] = irqCoreUsage
                    perCoreStats[idx]["idle"] = idleCoreUsage
                    perCoreStats[idx]["total"] = totalCoreUsage

                    # apply color #
                    totalCoreUsageStr = convCpuColor(totalCoreUsage, size=3)

                    coreStat = (
                        "{0:<7}|{1:>5}({2:^3}/{3:^3}/{4:^3}/{5:^3})|".format(
                            "Core/%s" % idx,
                            "%s %%" % totalCoreUsageStr,
                            userCoreUsage,
                            kerCoreUsage,
                            ioCoreUsage,
                            irqCoreUsage,
                        )
                    )
                except SystemExit:
                    sys.exit(0)
                except:
                    continue

                # save frequency #
                if (
                    not SysMgr.reportEnable
                    and not SysMgr.jsonEnable
                    and not SysMgr.barGraphEnable
                    and SysMgr.nrCore > SysMgr.NRMANYCORE
                ):
                    pass
                elif not SysMgr.isLinux:
                    try:
                        cid = None
                        curFreq = minFreq = maxFreq = None
                        perCoreStats[idx]["id"] = None
                        freq = freqList[idx]
                        if len(freq) > 0:
                            curFreq = long(freq[0]) << 10
                        if len(freq) > 1:
                            minFreq = long(freq[1]) << 10
                        if len(freq) > 2:
                            maxFreq = long(freq[2]) << 10
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass
                else:
                    # set default path #
                    defPath = "%s%s/cpufreq" % (freqPath, idx)

                    # get current CPU frequency #
                    """
                    if the core has been suspended,
                    reading current frequency will take quite some time.
                    """
                    try:
                        prevCurFd = self.prevCpuData[idx]["curFd"]
                        prevCurFd.seek(0)
                        curFreq = long(prevCurFd.readline()[:-1])
                        self.cpuData[idx]["curFd"] = prevCurFd
                        perCoreStats[idx]["curFreq"] = curFreq
                    except SystemExit:
                        sys.exit(0)
                    except:
                        infoPath = "%s/cpuinfo_cur_freq" % defPath
                        scalingPath = "%s/scaling_cur_freq" % defPath

                        if os.path.isfile(infoPath):
                            curPath = infoPath
                        elif os.path.isfile(scalingPath):
                            curPath = scalingPath
                        else:
                            curPath = None

                        try:
                            newCurFd = open(curPath, "r")
                            self.cpuData[idx]["curFd"] = newCurFd
                            curFreq = long(newCurFd.readline()[:-1])
                            perCoreStats[idx]["curFreq"] = curFreq
                        except SystemExit:
                            sys.exit(0)
                        except:
                            curFreq = None

                    # get min CPU frequency #
                    try:
                        prevMinFd = self.prevCpuData[idx]["minFd"]
                        prevMinFd.seek(0)
                        minFreq = long(prevMinFd.readline()[:-1])
                        self.cpuData[idx]["minFd"] = prevMinFd
                        perCoreStats[idx]["minFreq"] = minFreq
                    except SystemExit:
                        sys.exit(0)
                    except:
                        infoPath = "%s/cpuinfo_min_freq" % defPath
                        scalingPath = "%s/scaling_min_freq" % defPath

                        if os.path.isfile(infoPath):
                            minPath = infoPath
                        elif os.path.isfile(scalingPath):
                            minPath = scalingPath
                        else:
                            minPath = None

                        try:
                            newMinFd = open(minPath, "r")
                            self.cpuData[idx]["minFd"] = newMinFd
                            minFreq = long(newMinFd.readline()[:-1])
                            perCoreStats[idx]["minFreq"] = minFreq
                        except SystemExit:
                            sys.exit(0)
                        except:
                            minFreq = None

                    # get max CPU frequency #
                    try:
                        prevMaxFd = self.prevCpuData[idx]["maxFd"]
                        prevMaxFd.seek(0)
                        maxFreq = long(prevMaxFd.readline()[:-1])
                        self.cpuData[idx]["maxFd"] = prevMaxFd
                        perCoreStats[idx]["maxFreq"] = maxFreq
                    except SystemExit:
                        sys.exit(0)
                    except:
                        infoPath = "%s/cpuinfo_max_freq" % defPath
                        scalingPath = "%s/scaling_max_freq" % defPath

                        if os.path.isfile(infoPath):
                            maxPath = infoPath
                        elif os.path.isfile(scalingPath):
                            maxPath = scalingPath
                        else:
                            maxPath = None

                        try:
                            newMaxFd = open(maxPath, "r")
                            self.cpuData[idx]["maxFd"] = newMaxFd
                            maxFreq = long(newMaxFd.readline()[:-1])
                            perCoreStats[idx]["maxFreq"] = maxFreq
                        except SystemExit:
                            sys.exit(0)
                        except:
                            maxFreq = None

                    # get current governor #
                    try:
                        self.prevCpuData[idx]["govFd"].seek(0)
                        gov = self.prevCpuData[idx]["govFd"].readline()[:-1]
                        self.cpuData[idx]["govFd"] = self.prevCpuData[idx][
                            "govFd"
                        ]
                        perCoreStats[idx]["governor"] = gov
                    except SystemExit:
                        sys.exit(0)
                    except:
                        govPath = "%s/scaling_governor" % defPath

                        try:
                            self.cpuData[idx]["govFd"] = open(govPath, "r")
                            gov = self.cpuData[idx]["govFd"].readline()[:-1]
                            perCoreStats[idx]["governor"] = gov
                        except:
                            gov = None

                    # get package ID #
                    try:
                        # get core ID #
                        if (
                            idx in self.prevCpuData
                            and "cidFd" in self.prevCpuData[idx]
                        ):
                            fd = self.prevCpuData[idx]["cidFd"]
                            fd.seek(0)
                            coreId = long(fd.readline()[:-1])
                            self.cpuData[idx]["cidFd"] = fd
                        else:
                            cidPath = "%s%s/topology/core_id" % (freqPath, idx)
                            newCidFd = open(cidPath, "r")

                            self.cpuData[idx]["cidFd"] = newCidFd
                            coreId = long(newCidFd.readline()[:-1])

                        if coreId < 0:
                            coreId = "?"

                        # get package ID #
                        if (
                            idx in self.prevCpuData
                            and "pidFd" in self.prevCpuData[idx]
                        ):
                            fd = self.prevCpuData[idx]["pidFd"]
                            fd.seek(0)
                            phyId = long(fd.readline()[:-1])
                            self.cpuData[idx]["pidFd"] = fd
                        else:
                            pidPath = "%s%s/topology/physical_package_id" % (
                                freqPath,
                                idx,
                            )
                            newPidFd = open(pidPath, "r")

                            self.cpuData[idx]["pidFd"] = newPidFd
                            phyId = long(newPidFd.readline()[:-1])

                        if phyId < 0:
                            phyId = "?"

                        cid = "%s-%s" % (phyId, coreId)
                        perCoreStats[idx]["id"] = cid
                    except SystemExit:
                        sys.exit(0)
                    except:
                        perCoreStats[idx]["id"] = None

                # merge frequency info #
                try:
                    coreFreq = ""

                    # frequency #
                    if curFreq:
                        coreFreq = "%d Mhz" % (long(curFreq) >> 10)
                    # cache #
                    else:
                        sysObj = SysMgr.sysInstance
                        if not sysObj.cpuCacheData:
                            sysObj.saveCpuCacheInfo(True)
                        try:
                            coreFreq = sysObj.cpuCacheData[str(idx)]
                        except SystemExit:
                            sys.exit(0)
                        except:
                            coreFreq = "? Mhz"

                    if minFreq and maxFreq:
                        coreFreq = "%s [%d-%d]" % (
                            coreFreq,
                            long(minFreq) >> 10,
                            long(maxFreq) >> 10,
                        )

                    coreFreq = "%20s|" % coreFreq
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

                # merge temperature info #
                try:
                    coreFreq = "{0:^6} | {1:>3} C | {2:<1}".format(
                        cid, coreTempData[cid], coreFreq
                    )
                except SystemExit:
                    sys.exit(0)
                except:
                    try:
                        coreFreq = "{0:^6} | {1:>3} C | {2:<1}".format(
                            cid, coreTempData["CPU"], coreFreq
                        )
                    except SystemExit:
                        sys.exit(0)
                    except:
                        if cid:
                            coreFreq = "{0:^6} | {1:>3} C | {2:<1}".format(
                                cid, "?", coreFreq
                            )
                        else:
                            coreFreq = "%3s C | %s" % ("?", coreFreq)

                # merge governor info #
                try:
                    coreFreq = "{0:^13} | {1:>1}".format(gov, coreFreq)
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

                # print final output for a core #
                try:
                    # get real length without ansi for core stat #
                    if lenCoreStat == 0:
                        lenCoreStat = len(UtilMgr.removeColor(coreStat))

                    # use short core stats for many-core system #
                    if (
                        SysMgr.barGraphEnable is None
                        and SysMgr.nrCore > SysMgr.NRMANYCORE
                    ) or SysMgr.barGraphEnable is False:
                        shortCoreStats += coreStat
                        coreFactor = long(maxCols / lenCoreStat)
                        if (idx + 1) % coreFactor == 0:
                            SysMgr.addPrint(shortCoreStats[:-1] + "\n")
                            shortCoreStats = ""

                        raise Exception()

                    # get length of string #
                    lenFreq = len(coreFreq)
                    lenLine = SysMgr.lineLength - lenCoreStat - lenFreq - 2

                    # print graph of per-core usage #
                    if not SysMgr.totalEnable and totalCoreUsage > 0:
                        coreGraph = "#" * long(lenLine * totalCoreUsage / 100)
                        coreGraph += " " * (lenLine - len(coreGraph))
                        coreGraph = convCpuColor(totalCoreUsage, coreGraph)
                    else:
                        coreGraph = " " * lenLine

                    SysMgr.addPrint(
                        "%s%s| %s\n" % (coreStat, coreGraph, coreFreq)
                    )
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

            # print remain core stats #
            if shortCoreStats:
                SysMgr.addPrint(shortCoreStats[:-1] + "\n")

        # print GPU stats #
        gpuStats = {}
        if SysMgr.isLinux and SysMgr.gpuEnable:
            if self.gpuData:
                SysMgr.addPrint("%s\n" % oneLine)

            for idx, value in self.gpuData.items():
                try:
                    if SysMgr.checkCutCond():
                        return

                    totalGpuUsage = long(value["CUR_LOAD"])

                    # convert color for GPU usage #
                    totalGpuUsageStr = "%s %%" % totalGpuUsage
                    if SysMgr.colorEnable and totalGpuUsage > 0:
                        totalGpuUsageStr = r"{0:>5}".format(totalGpuUsageStr)
                        totalGpuUsageStr = convCpuColor(
                            totalGpuUsage, totalGpuUsageStr
                        )

                    coreStat = "{0:<23}({1:>5})|".format(
                        idx[:23], totalGpuUsageStr
                    )

                    gpuStats[idx] = totalGpuUsage

                    # set frequency info #
                    try:
                        coreFreq = "%d Mhz" % value["CUR_FREQ"]
                    except SystemExit:
                        sys.exit(0)
                    except:
                        coreFreq = "? Mhz"
                    if (
                        "MIN_FREQ" in value
                        and "MAX_FREQ" in value
                        and value["MIN_FREQ"] > 0
                        and value["MAX_FREQ"] > 0
                    ):
                        coreFreq = "%s [%d-%d]" % (
                            coreFreq,
                            value["MIN_FREQ"],
                            value["MAX_FREQ"],
                        )
                    coreFreq = "%20s|" % coreFreq

                    # set memory info #
                    try:
                        memUsage = None
                        if (
                            self.gpuMemData
                            and not "GPUTEMP" in SysMgr.environList
                        ):
                            memUsage = convSize(
                                self.gpuMemData["0"]["size"],
                                isInt=True,
                                unit="M",
                            )
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass

                    # additional info #
                    try:
                        # GPU memory #
                        if memUsage:
                            coreFreq = "{0:^6}| {1:1}".format(
                                memUsage, coreFreq
                            )
                        # CPU temperature #
                        else:
                            coreFreq = "%3s C | %s" % (value["TEMP"], coreFreq)
                    except SystemExit:
                        sys.exit(0)
                    except:
                        # GPU temperature #
                        try:
                            coreFreq = "%3s C | %s" % (
                                coreTempData["GPU"],
                                coreFreq,
                            )
                        except SystemExit:
                            sys.exit(0)
                        except:
                            coreFreq = "%3s C | %s" % ("?", coreFreq)

                    lenCore = len(coreStat)
                    lenFreq = len(coreFreq)
                    lenLine = SysMgr.lineLength - lenCore - lenFreq - 2

                    # print bar graph for GPU usage #
                    if totalGpuUsage > 0:
                        coreGraph = "#" * long(lenLine * totalGpuUsage / 100)
                        coreGraph += " " * (lenLine - len(coreGraph))
                        origCoreGraph = coreGraph
                        coreGraph = convCpuColor(totalGpuUsage, coreGraph)
                        coreGraph += " " * (
                            len(coreGraph) - len(origCoreGraph)
                        )
                    else:
                        coreGraph = " " * lenLine

                    SysMgr.addPrint(
                        "%s%s| %s\n" % (coreStat, coreGraph, coreFreq)
                    )
                except SystemExit:
                    sys.exit(0)
                except:
                    continue

        # check report option #
        if not SysMgr.reportEnable and not SysMgr.jsonEnable:
            return

        # initialize report data #
        """
        - jsonData: just data to be kept in JSON format
        - reportData: serializable data to be reported outside in JSON format
        """
        self.reportData = {}

        # utctime #
        self.reportData["timestamp"] = SysMgr.uptime
        self.reportData["utctime"] = UtilMgr.getUTCTime()

        # system info #
        if not SysMgr.sysInstance.uname:
            SysMgr.sysInstance.saveUnameInfo()
        if SysMgr.sysInstance.uname:
            if len(SysMgr.sysInstance.uname) == 4:
                osinfo, host, kernel, release = SysMgr.sysInstance.uname
            elif len(SysMgr.sysInstance.uname) == 5:
                (
                    osinfo,
                    host,
                    kernel,
                    release,
                    machine,
                ) = SysMgr.sysInstance.uname
            else:
                osinfo = host = kernel = release = None
        else:
            osinfo = host = kernel = release = None

        # system #
        if "system" in SysMgr.jsonData:
            self.reportData["system"] = SysMgr.jsonData["system"]
        else:
            self.reportData["system"] = {}
        self.reportData["system"].update(
            {
                "pid": SysMgr.pid,
                "uptime": SysMgr.uptime,
                "interval": interval,
                "nrIrq": nrIrq,
                "nrSoftIrq": nrSoftIrq,
                "os": osinfo,
                "host": host,
                "kernel": kernel,
                "release": release,
            }
        )

        # load #
        try:
            loads = list(map(float, SysMgr.loadavg.split()[:3]))
            self.reportData["system"]["load1m"] = loads[0]
            self.reportData["system"]["load5m"] = loads[1]
            self.reportData["system"]["load15m"] = loads[2]
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # fd #
        try:
            self.reportData["fd"] = {}

            sysFds = SysMgr.getNrSysFdHandle()
            self.reportData["fd"]["curFd"] = sysFds[0]
            self.reportData["fd"]["maxFd"] = sysFds[2]
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # sock #
        try:
            self.reportData["sock"] = {}

            # check skip condition #
            if "NOSOCKPROF" in SysMgr.environList:
                raise Exception("no socket profilng")

            # flush socket caches #
            SysMgr.udpListCache = {}
            SysMgr.tcpListCache = {}
            SysMgr.udsListCache = {}

            # get the number of sockets #
            SysMgr.getSocketAddrList([])
            SysMgr.getUdsList([])

            self.reportData["sock"]["nrUDPSock"] = SysMgr.nrUDPSock
            self.reportData["sock"]["nrTCPSock"] = SysMgr.nrTCPSock
            self.reportData["sock"]["nrTCPConn"] = SysMgr.nrTCPConn
            self.reportData["sock"]["nrUDSSock"] = SysMgr.nrUDSSock

            # add socket interval #
            self.addSysInterval("sock", "nrUDPSock", SysMgr.nrUDPSock)
            self.addSysInterval("sock", "nrTCPSock", SysMgr.nrTCPSock)
            self.addSysInterval("sock", "nrTCPConn", SysMgr.nrTCPConn)
            self.addSysInterval("sock", "nrUDSSock", SysMgr.nrUDSSock)
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # CPU #
        self.reportData["cpu"] = {
            "total": totalUsage,
            "idle": idleUsage,
            "user": userUsage,
            "kernel": kerUsage,
            "irq": irqUsage,
            "iowait": ioUsage,
            "nrCore": SysMgr.nrCore,
            "perCore": perCoreStats,
        }

        # GPU #
        self.reportData["gpu"] = gpuStats

        # GPU memory #
        self.reportData["gpumem"] = self.gpuMemData

        # memory #
        self.reportData["mem"] = {
            "total": totalMem,
            "free": freeMem,
            "available": availMem,
            "anon": totalAnonMem,
            "file": totalFileMem,
            "slab": totalSlabMem,
            "cache": totalCacheMem,
            "kernel": totalKernelMem,
            "freeDiff": freeMemDiff,
            "availableDiff": availMemDiff,
            "anonDiff": anonMemDiff,
            "fileDiff": fileMemDiff,
            "slabDiff": slabMemDiff,
            "pgDirty": pgDirty,
            "pgRclmBg": pgRclmBg,
            "pgRclmFg": pgRclmFg,
            "nrMinFlt": nrMinFault,
            "pgMlock": pgMlock,
        }

        # CMA #
        try:
            self.reportData["mem"]["cmaTotal"] = cmaTotalMem
            self.reportData["mem"]["cmaFree"] = cmaFreeMem
            self.reportData["mem"]["cmaDev"] = cmaDevMem
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # swap #
        self.reportData["swap"] = {
            "total": swapTotal,
            "usage": swapUsage,
            "usagePer": swapUsagePer,
            "usageDiff": swapUsageDiff,
            "swapin": swapInMem,
            "swapout": swapOutMem,
        }

        # block #
        self.reportData["block"] = {
            "read": pgInMemDiff,
            "write": pgOutMemDiff,
            "ioWait": ioUsage,
            "nrMajFlt": nrMajFault,
            "nrTask": nrBlocked,
        }

        # task #
        self.reportData["task"] = {
            "nrBlocked": nrBlocked,
            "nrProc": self.nrProcess,
            "nrThread": self.nrThread,
            "nrCtx": nrCtxSwc,
        }

        # network #
        self.reportData["net"] = {"inbound": netIn, "outbound": netOut}

        # MAC #
        if not SysMgr.sysInstance.macAddr:
            SysMgr.sysInstance.saveMacAddr()
        if SysMgr.sysInstance.macAddr:
            macAddr = SysMgr.sysInstance.macAddr
            macStr = "%s_%s" % (macAddr[0], macAddr[1])
            self.reportData["net"]["macip"] = macStr
            self.reportData["net"]["mac"] = macAddr[0]
            self.reportData["net"]["ip"] = macAddr[1]

        # network device #
        if SysMgr.networkEnable:
            SysMgr.sysInstance.updateNetworkInfo()

            for dev, value in sorted(SysMgr.sysInstance.networkInfo.items()):
                # check value #
                if not "rdiff" in value or not "tdiff" in value:
                    continue

                self.reportData["net"][dev] = {}
                reportData = self.reportData["net"][dev]

                reportData["ipaddr"] = value["ipaddr"]

                rdiff = value["rdiff"]
                tdiff = value["tdiff"]

                reportData["recv"] = {
                    "bytes": rdiff[0],
                    "packets": rdiff[1],
                    "errs": rdiff[2],
                    "drop": rdiff[3],
                    "fifo": rdiff[4],
                    "frame": rdiff[5],
                    "compressed": rdiff[6],
                    "multicast": rdiff[7],
                }

                reportData["trans"] = {
                    "bytes": tdiff[0],
                    "packets": tdiff[1],
                    "errs": tdiff[2],
                    "drop": tdiff[3],
                    "fifo": tdiff[4],
                    "frame": tdiff[5],
                    "compressed": tdiff[6],
                    "multicast": tdiff[7],
                }

                # add network device interval #
                self.addSysInterval("net", dev + ":recv", rdiff[0])
                self.addSysInterval("net", dev + ":trans", tdiff[0])

        # storage #
        if SysMgr.diskEnable:
            SysMgr.sysInstance.updateStorageInfo()

            # copy storage data into report data structure #
            self.reportData["storage"] = UtilMgr.deepcopy(
                SysMgr.sysInstance.storageData
            )

            prevStorageData = SysMgr.sysInstance.prevStorageData

            # calculate diff of read /write on each devices #
            for dev, value in sorted(self.reportData["storage"].items()):
                # add storage device interval #
                self.addSysInterval("storage", dev, value["usagePer"])

                # get read size on this interval #
                try:
                    value["read"] -= prevStorageData[dev]["read"]
                except SystemExit:
                    sys.exit(0)
                except:
                    value["read"] = 0

                # get write size on this interval #
                try:
                    value["write"] -= prevStorageData[dev]["write"]
                except SystemExit:
                    sys.exit(0)
                except:
                    value["write"] = 0

                # get readtime on this interval #
                try:
                    value["readtime"] -= prevStorageData[dev]["readtime"]
                except SystemExit:
                    sys.exit(0)
                except:
                    value["readtime"] = 0

                # get writetime on this interval #
                try:
                    value["writetime"] -= prevStorageData[dev]["writetime"]
                except SystemExit:
                    sys.exit(0)
                except:
                    value["writetime"] = 0

                # get iotime on this interval #
                try:
                    value["iotime"] -= prevStorageData[dev]["iotime"]
                except SystemExit:
                    sys.exit(0)
                except:
                    value["iotime"] = 0

                # get iowtime on this interval #
                try:
                    value["iowtime"] -= prevStorageData[dev]["iowtime"]
                except SystemExit:
                    sys.exit(0)
                except:
                    value["iowtime"] = 0

                # get avq on this interval #
                try:
                    value["avq"] = value["iowtime"] / value["iotime"]
                except SystemExit:
                    sys.exit(0)
                except:
                    value["avq"] = 0
        else:
            self.reportData["storage"] = {}

        # storage #
        if "PMU" in SysMgr.jsonData:
            self.reportData["PMU"] = SysMgr.jsonData["PMU"]

        # custom #
        if "REPORTFUNC" in SysMgr.environList:
            for item in SysMgr.environList["REPORTFUNC"]:
                # get function info #
                try:
                    values = item.split(":")
                    path, func = values[:2]
                    if len(values) > 2:
                        args = values[2:]
                    else:
                        args = []
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(
                        "failed to parse function info from '%s'" % item, True
                    )
                    sys.exit(-1)

                # call function #
                ret = UtilMgr.callPyFunc(path, func, args)
                try:
                    self.reportData.setdefault("custom", {})
                    fname = "%s(%s)" % (func, args)
                    self.reportData["custom"][fname] = ret
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(
                        "failed to get custom data from '%s'" % item, True
                    )

        # apply report data to global data #
        if SysMgr.jsonEnable:
            SysMgr.jsonData.update(self.reportData)

    def setProcUsage(self):
        interval = SysMgr.uptimeDiff
        if interval == 0:
            interval = 0.1

        for pid, value in self.procData.items():
            try:
                # rss #
                value["rss"] = long(value["stat"][self.rssIdx]) >> 8

                # add RSS interval #
                self.addProcInterval("mem", pid, value, "rssInt", value["rss"])

                # define now data #
                nowData = value["stat"]

                # update runtime #
                value["runtime"] = long(
                    SysMgr.uptime - (float(nowData[self.starttimeIdx]) / 100)
                )

                # use total stat #
                if SysMgr.totalEnable:
                    raise Exception()

                # define prev data #
                prevData = self.prevProcData[pid]["stat"]
                if self.prevProcData[pid]["created"]:
                    value["created"] = True
                    if not value["comm"].startswith("*"):
                        value["comm"] = "*%s" % (value["comm"])

                # update I/O #
                if value["io"]:
                    value["read"] = (
                        value["io"]["read_bytes"]
                        - self.prevProcData[pid]["io"]["read_bytes"]
                    )
                    value["write"] = (
                        value["io"]["write_bytes"]
                        - self.prevProcData[pid]["io"]["write_bytes"]
                    )
                    value["rw"] = value["read"] + value["write"]

                # check stat change #
                if not value["changed"]:
                    value["utime"] = value["stime"] = value["ttime"] = 0
                    value["btime"] = value["cttime"] = 0

                    # add CPU interval #
                    self.addProcInterval(
                        "cpu", pid, value, "cpuInt", value["ttime"]
                    )

                    continue

                # major fault #
                value["majflt"] = (
                    nowData[self.majfltIdx] - prevData[self.majfltIdx]
                )

                # utime #
                utick = nowData[self.utimeIdx] - prevData[self.utimeIdx]
                value["utime"] = long(utick / interval)
                if (
                    value["utime"] >= 100
                    and value["stat"][self.nrthreadIdx] == "1"
                ):
                    value["utime"] = 100

                # stime #
                stick = nowData[self.stimeIdx] - prevData[self.stimeIdx]
                value["stime"] = long(stick / interval)
                if (
                    value["stime"] >= 100
                    and value["stat"][self.nrthreadIdx] == "1"
                ):
                    value["stime"] = 100

                # ttime #
                value["ttime"] = utick + stick
                if SysMgr.floatEnable:
                    value["ttime"] = round(value["ttime"] / interval, 1)
                else:
                    value["ttime"] = long(value["ttime"] / interval)
                if (
                    value["ttime"] >= 100
                    and value["stat"][self.nrthreadIdx] == "1"
                ):
                    value["ttime"] = 100
                elif value["ttime"] == 0:
                    value["ttime"] = 0

                # add CPU interval #
                self.addProcInterval(
                    "cpu", pid, value, "cpuInt", value["ttime"]
                )

                # child utime #
                cutick = nowData[self.cutimeIdx] - prevData[self.cutimeIdx]
                if SysMgr.floatEnable:
                    cutime = round(cutick / interval, 1)
                else:
                    cutime = long(cutick / interval)

                # child stime #
                cstick = nowData[self.cstimeIdx] - prevData[self.cstimeIdx]
                if SysMgr.floatEnable:
                    cstime = round(cstick / interval, 1)
                else:
                    cstime = long(cstick / interval)

                # child ttime #
                value["cttime"] = cutime + cstime

                # btime #
                btick = nowData[self.btimeIdx] - prevData[self.btimeIdx]
                if SysMgr.floatEnable:
                    value["btime"] = round(btick / interval, 1)
                    if value["btime"] == 0:
                        value["btime"] = 0
                else:
                    value["btime"] = long(btick / interval)

                if (
                    value["ttime"] + value["btime"] > 100
                    and value["stat"][self.nrthreadIdx] == "1"
                ):
                    value["btime"] = 100 - value["ttime"]
            except SystemExit:
                sys.exit(0)
            except:
                # set flags for new task #
                if SysMgr.totalEnable and pid in self.prevProcData:
                    pass
                else:
                    value["new"] = True
                    value["created"] = True

                    # update comm #
                    value["comm"] = "*%s" % value["comm"]

                if SysMgr.totalEnable:
                    interval = 1

                value["majflt"] = nowData[self.majfltIdx]

                # user time #
                value["utime"] = long(nowData[self.utimeIdx] / interval)
                if (
                    not SysMgr.totalEnable
                    and value["utime"] >= 100
                    and value["stat"][self.nrthreadIdx] == "1"
                ):
                    value["utime"] = 100
                if SysMgr.floatEnable:
                    utick = round(nowData[self.utimeIdx] / interval, 1)
                else:
                    utick = value["utime"]

                # system time #
                value["stime"] = long(nowData[self.stimeIdx] / interval)
                if (
                    not SysMgr.totalEnable
                    and value["stime"] >= 100
                    and value["stat"][self.nrthreadIdx] == "1"
                ):
                    value["stime"] = 100
                if SysMgr.floatEnable:
                    stick = round(nowData[self.stimeIdx] / interval, 1)
                else:
                    stick = value["stime"]

                # total time #
                value["ttime"] = utick + stick
                if (
                    not SysMgr.totalEnable
                    and value["ttime"] >= 100
                    and value["stat"][self.nrthreadIdx] == "1"
                ):
                    value["ttime"] = 100

                # child time #
                if SysMgr.floatEnable:
                    cutime = round(nowData[self.cutimeIdx] / interval, 1)
                    cstime = round(nowData[self.cstimeIdx] / interval, 1)
                else:
                    cutime = long(nowData[self.cutimeIdx] / interval)
                    cstime = long(nowData[self.cstimeIdx] / interval)
                value["cttime"] = cutime + cstime

                # block time #
                if SysMgr.floatEnable:
                    value["btime"] = round(
                        nowData[self.btimeIdx] / interval, 1
                    )
                else:
                    value["btime"] = long(nowData[self.btimeIdx] / interval)
                if (
                    not SysMgr.totalEnable
                    and value["ttime"] + value["btime"] > 100
                    and value["stat"][self.nrthreadIdx] == "1"
                ):
                    value["btime"] = 100 - value["ttime"]

                if value["io"]:
                    value["read"] = value["io"]["read_bytes"]
                    value["write"] = value["io"]["write_bytes"]
                    value["rw"] = value["read"] + value["write"]

            # check delayacct_blkio_ticks error #
            if not SysMgr.totalEnable and value["btime"] >= 100:
                value["btime"] = 0

    def getMemDetails(self, idx, maps, vss=0):
        rss = 0
        sss = 0
        pss = 0
        wssTotal = 0
        memBuf = []

        if not maps:
            return [], 0, 0, 0

        convSize = UtilMgr.convSize2Unit

        for key, item in sorted(
            maps.items(),
            key=lambda e: e[1]["Size:"] if "Size:" in e[1] else 0,
            reverse=True,
        ):

            tmpstr = ""

            if not item or item["count"] == 0:
                continue

            try:
                prop = "Size:"
                val = item[prop]
                tmpstr = "%s%s%7s / " % (
                    tmpstr,
                    "VSS:",
                    convSize(val << 10),
                )
            except:
                tmpstr = "%s%s%7s / " % (tmpstr, "VSS:", 0)

            try:
                prop = "Rss:"
                val = item[prop]
                tmpstr = "%s%s%7s / " % (
                    tmpstr,
                    prop.upper(),
                    convSize(val << 10),
                )
                rss += val
            except:
                tmpstr = "%s%s%7s / " % (tmpstr, prop.upper(), 0)

            try:
                prop = "Pss:"
                val = item[prop]
                tmpstr = "%s%s%7s / " % (
                    tmpstr,
                    prop.upper(),
                    convSize(val << 10),
                )
                pss += val
            except:
                tmpstr = "%s%s%7s / " % (tmpstr, prop.upper(), 0)

            try:
                prop = "Swap:"
                val = item[prop]
                tmpstr = "%s%s%7s / " % (
                    tmpstr,
                    prop.upper(),
                    convSize(val << 10),
                )
            except:
                tmpstr = "%s%s%7s / " % (tmpstr, prop.upper(), 0)

            try:
                prop = "AnonHugePages:"
                val = item[prop]
                tmpstr = "%s%s:%5s / " % (
                    tmpstr,
                    "HUGE",
                    convSize(val << 10, True),
                )
            except:
                tmpstr = "%s%s:%5s / " % (tmpstr, "HUGE", 0)

            try:
                prop = "Locked:"
                val = item[prop]
                tmpstr = "%s%s%6s / " % (
                    tmpstr,
                    "LOCK:",
                    convSize(val << 10, True),
                )
            except:
                tmpstr = "%s%s%6s / " % (tmpstr, "LOCK:", 0)

            try:
                prop = "Shared_Clean:"
                sss += item[prop]
            except:
                pass

            try:
                prop = "Shared_Dirty:"
                val = item[prop]
                sss += val
                tmpstr = "%s%s:%7s / " % (
                    tmpstr,
                    "SDRT",
                    convSize(val << 10),
                )
            except:
                tmpstr = "%s%s:%7s / " % (tmpstr, "SDRT", 0)

            try:
                prop = "Private_Dirty:"
                val = item[prop]
                tmpstr = "%s%s:%7s" % (
                    tmpstr,
                    "PDRT",
                    convSize(val << 10),
                )
            except:
                tmpstr = "%s%s:%7s" % (tmpstr, "PDRT", 0)

            """
            try:
                prop = 'NOPM'
                tmpstr = "%s%s:%5s" % \
                    (tmpstr, prop, convSize(item[prop] << 10, True))
            except:
                tmpstr = "%s%s:%5s" % (tmpstr, prop, 0)
            """

            mtype = "MEM(%s/%s)" % (key, item["count"])
            memBuf.append([key, "{0:>39} | {1:1}|\n".format(mtype, tmpstr)])

            if SysMgr.wssEnable:
                # get current WSS size #
                try:
                    wssNum = item["Referenced:"] << 10
                    wssTotal += wssNum
                    wss = convSize(wssNum, False)
                except:
                    wss = 0

                # get previous WSS history #
                try:
                    self.procData[idx]["wss"] = self.prevProcData[idx]["wss"]
                except:
                    self.procData[idx].setdefault("wss", {})

                    # clear reference bits #
                    SysMgr.clearPageRefs(idx, val="1")

                # update WSS history #
                try:
                    history = self.procData[idx]["wss"][key]
                    self.procData[idx]["wss"][key] = "%s -> %7s" % (
                        history,
                        wss,
                    )
                except SystemExit:
                    sys.exit(0)
                except:
                    initVal = "[%s]" % UtilMgr.convColor(wss, "RED", 7)
                    self.procData[idx]["wss"][key] = initVal

        # update uss #
        uss = rss - sss
        wssTotal = wssTotal >> 10

        # update history for wss #
        if SysMgr.wssEnable:
            unitItems = (
                ("VSS", vss),
                ("RSS", rss),
                ("PSS", pss),
                ("USS", uss),
                ("WSS", wssTotal),
            )
            for item in unitItems:
                name = item[0]
                unit = UtilMgr.convSize2Unit(item[1] << 10)
                if name in self.procData[idx]["wss"]:
                    history = self.procData[idx]["wss"][name]
                    self.procData[idx]["wss"][name] = "%s -> %7s" % (
                        history,
                        unit,
                    )
                else:
                    initVal = "[%s]" % UtilMgr.convColor(unit, "RED", 7)
                    self.procData[idx]["wss"][name] = initVal

        if not SysMgr.memEnable:
            memBuf = []

        return memBuf, rss, pss, uss

    def printDefaultUsage(self, title):
        try:
            nrNewThreads = (
                self.cpuData["processes"]["processes"]
                - self.prevCpuData["processes"]["processes"]
            )
        except SystemExit:
            sys.exit(0)
        except:
            nrNewThreads = 0

        try:
            if SysMgr.isLinux:
                loadlist = SysMgr.loadavg.split()[:3]
            else:
                loadlist = list(SysMgr.loadavg)

            for idx, load in enumerate(loadlist):
                loadlist[idx] = str("%d" % float(load))

            loadavg = "/".join(loadlist)
        except SystemExit:
            sys.exit(0)
        except:
            loadavg = "?"

        try:
            oom_kill = long(self.vmData["oom_kill"])
            if oom_kill:
                oomstr = " [OOM: %d] " % oom_kill
            else:
                oomstr = " "
        except SystemExit:
            sys.exit(0)
        except:
            oomstr = " "
            oom_kill = 0

        try:
            nrCtxt = (
                self.cpuData["ctxt"]["ctxt"] - self.prevCpuData["ctxt"]["ctxt"]
            )

            if nrCtxt < 0:
                nrCtxt = 0
        except SystemExit:
            sys.exit(0)
        except:
            nrCtxt = 0

        try:
            nrTermThreads = abs(
                self.nrThread - nrNewThreads - self.nrPrevThread
            )
        except SystemExit:
            sys.exit(0)
        except:
            nrTermThreads = 0

        try:
            nrIrq = (
                self.cpuData["intr"]["intr"] - self.prevCpuData["intr"]["intr"]
            )

            if nrIrq < 0:
                nrIrq = 0
        except SystemExit:
            sys.exit(0)
        except:
            nrIrq = 0

        try:
            memTotal = UtilMgr.convSize2Unit(self.memData["MemTotal"] << 10)
            if SysMgr.memTotal < 0:
                SysMgr.memTotal = self.memData["MemTotal"] >> 10
        except SystemExit:
            sys.exit(0)
        except:
            memTotal = 0

        try:
            swapTotal = UtilMgr.convSize2Unit(self.memData["SwapTotal"] << 10)
        except SystemExit:
            sys.exit(0)
        except:
            swapTotal = 0

        try:
            if SysMgr.battery:
                battery = " [Power:%d%%/%s/%s]" % (
                    SysMgr.battery[0],
                    UtilMgr.convTime(SysMgr.battery[1]),
                    "+" if SysMgr.battery[2] else "-",
                )
            else:
                battery = ""
        except SystemExit:
            sys.exit(0)
        except:
            battery = ""

        # print stats #
        SysMgr.addPrint(
            UtilMgr.convColor(
                (
                    "%s [Time: %7.3f] [Inter: %.1f] [Ctxt: %d] "
                    "[Life: +%d/-%d]%s[IRQ: %d] [Core: %d] [Task: %d/%d] "
                    "[Load: %s] [RAM: %s] [Swap: %s]%s\n"
                )
                % (
                    title,
                    SysMgr.uptime,
                    SysMgr.uptimeDiff,
                    nrCtxt,
                    nrNewThreads,
                    nrTermThreads,
                    oomstr,
                    nrIrq,
                    SysMgr.nrCore,
                    self.nrProcess,
                    self.nrThread,
                    loadavg,
                    memTotal,
                    swapTotal,
                    battery,
                ),
                "BOLD",
            )
        )

        # add JSON stats #
        if SysMgr.jsonEnable:
            SysMgr.jsonData.setdefault("system", {})
            jsonData = SysMgr.jsonData["system"]

            jsonData["uptime"] = SysMgr.uptime
            jsonData["startTime"] = SysMgr.startTime
            jsonData["interval"] = SysMgr.uptimeDiff
            jsonData["nrCtxt"] = nrCtxt
            jsonData["nrNewThreads"] = nrNewThreads
            jsonData["nrTermThreads"] = nrTermThreads
            jsonData["nrProcess"] = self.nrProcess
            jsonData["nrThreads"] = self.nrThread

            if oomstr:
                jsonData["oomKill"] = oom_kill

            if battery:
                try:
                    jsonData["battery"] = {
                        "per": SysMgr.battery[0],
                        "leftsec": SysMgr.battery[1],
                        "plugged": "true" if SysMgr.battery[2] else "false",
                    }
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

    def printMemoryUsage(self, nrIndent):
        if not self.memData or not SysMgr.memEnable:
            return

        databuf = ""
        edata = "%s %-10s" % (" " * nrIndent, " ")
        data = "%s [%-5s > " % (" " * nrIndent, "SYSTEM")
        curline = str(data)

        colorList = ["Active", "Inactive", "Cached"]

        for name, value in sorted(self.memData.items()):
            if not value:
                continue

            size = UtilMgr.convSize2Unit(value << 10)

            # add stats in a line #
            item = "%-15s %7s" % ("%s:" % name, size)
            if SysMgr.ttyCols and len(item) + len(curline) >= SysMgr.ttyCols:
                databuf += "%s]\n" % curline.rstrip(", ")
                curline = str(edata)

            # set color #
            if name in colorList or name.endswith("Free"):
                item = "%-15s %7s" % (
                    "%s:" % name,
                    UtilMgr.convColor(size, "YELLOW", 7),
                )

            curline += "%s, " % item

        # check last line #
        if curline != data:
            databuf += "%s]" % curline.rstrip(", \n")
        databuf = databuf.rstrip(", \n")

        SysMgr.addPrint("%s\n" % databuf, newline=databuf.count("\n") + 1)

    def printSlabUsage(self, nrIndent):
        if not self.slabData:
            return

        databuf = ""
        edata = "%s %-8s" % (" " * nrIndent, " ")
        data = "%s [%-4s > " % (" " * nrIndent, "SLAB")
        curline = str(data)
        nrLine = 1

        # get cutline #
        if "NRSLAB" in SysMgr.environList:
            cutLine = UtilMgr.getEnvironNum("NRSLAB")
        else:
            cutLine = 3

        # get target object #
        if "TOTALSLAB" in SysMgr.environList:
            target = "totsize"
        else:
            target = "actsize"

        for name, items in sorted(
            self.slabData.items(), key=lambda x: x[1][target], reverse=True
        ):

            # add stats in a line #
            item = "%s: %s" % (name, UtilMgr.convSize2Unit(items[target]))
            if SysMgr.ttyCols and len(item) + len(curline) >= SysMgr.ttyCols:
                if nrLine >= cutLine:
                    break

                databuf += "%s]\n" % curline.rstrip(", ")
                curline = str(edata)
                nrLine += 1

            curline += "%s, " % item

        # check last line #
        if curline != data:
            databuf += "%s]" % curline.rstrip(", \n")
        databuf = databuf.rstrip(", \n")

        SysMgr.addPrint("%s\n" % databuf, newline=databuf.count("\n") + 1)

    def printVmInfo(self, nrIndent):
        if not SysMgr.memEnable:
            return

        vmInfo = "%s [VM > " % (" " * nrIndent)

        # swappiness #
        vmInfo += "swappiness: %s" % SysMgr.swappiness

        # vmpressure #
        vmInfo += ", cache_pressure: %s" % UtilMgr.convNum(SysMgr.vmpressure)

        # overcommit #
        vmInfo += ", overcommit: %s" % SysMgr.overcommit

        SysMgr.addPrint(vmInfo + "]\n")

    def printLMKStat(self, nrIndent):
        if not SysMgr.memEnable:
            return

        # save LMK info #
        try:
            memBuf = None
            SysMgr.lmkFd.seek(0)
            memBuf = SysMgr.lmkFd.readline()
        except SystemExit:
            sys.exit(0)
        except:
            try:
                memPath = SysMgr.lmkPath
                SysMgr.lmkFd = open(memPath, "r")
                memBuf = SysMgr.lmkFd.readline()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenWarn(memPath)

        if not memBuf:
            return

        # threshold list #
        threshold = [
            "FGAPP",
            "VISAPP",
            "SECSER",
            "HIDAPP",
            "CONPRO",
            "EMPAPP",
        ]

        lmkstr = "%s [LMK > " % (" " * nrIndent)

        stats = memBuf.split(",")
        if stats:
            stats = list(map(long, stats))

        for idx, item in enumerate(stats):
            lmkstr = "%s%s: %s, " % (
                lmkstr,
                threshold[idx],
                UtilMgr.convSize2Unit(item << 12),
            )

        SysMgr.addPrint(lmkstr[:-2] + "]\n")

    def printZoneUsage(self, nrIndent):
        if not self.zoneData:
            return

        # add JSON stats #
        if SysMgr.jsonEnable:
            SysMgr.jsonData.setdefault("zone", {})

        ttyCols = SysMgr.ttyCols
        convSize = UtilMgr.convSize2Unit
        convColor = UtilMgr.convColor

        # define stat list #
        STAT_LIST = [
            "free",
            "min",
            "low",
            "high",
            "managed",
            "present",
            "spanned",
        ]

        for node, items in sorted(self.zoneData.items()):
            # check invalid zones #
            if "spanned" in items and items["spanned"] == 0:
                continue

            zoneData = "%s [%-10s > " % (" " * nrIndent, "N%s" % node)
            lenZone = len(zoneData)

            for info in STAT_LIST:
                # check stats by sequence #
                if not info in items:
                    continue

                val = items[info]
                stat = convSize(val << 12)
                statOrig = stat

                if SysMgr.jsonEnable:
                    SysMgr.jsonData["zone"].setdefault(node, {})

                if info == "free":
                    if (
                        not node in self.prevZoneData
                        or not info in self.prevZoneData[node]
                    ):
                        diff = val
                    else:
                        diff = val - self.prevZoneData[node][info]

                    # set color #
                    if diff > 0:
                        color = "GREEN"
                    else:
                        color = "YELLOW"

                    diff = convSize(diff << 12)
                    ninfo = "diff"

                    if SysMgr.jsonEnable:
                        SysMgr.jsonData["zone"][node][ninfo] = diff

                    zoneStat = "%s: %7s / " % (ninfo, diff)
                    lenZoneStat = len(zoneStat)
                    if diff != "0":
                        zoneStat = "%s: %7s / " % (
                            ninfo,
                            convColor(diff, color, 7),
                        )

                    if ttyCols and lenZone + lenZoneStat >= ttyCols:
                        zoneData = "%s\n%s %s" % (
                            zoneData,
                            " " * 14,
                            " " * nrIndent,
                        )
                        lenZone = nrIndent

                    zoneData += zoneStat
                    lenZone += lenZoneStat

                    # apply color #
                    try:
                        if val == 0:
                            pass
                        elif val <= items["min"]:
                            stat = convColor(stat, "RED", 6)
                        elif val <= items["low"]:
                            stat = convColor(stat, "YELLOW", 6)
                        elif val <= items["high"]:
                            stat = convColor(stat, "CYAN", 6)
                        else:
                            stat = convColor(stat, "GREEN", 6)
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass

                if SysMgr.jsonEnable:
                    SysMgr.jsonData["zone"][node][info] = statOrig
                    continue

                zoneStat = "%s: %6s / " % (info, statOrig)
                lenZoneStat = len(zoneStat)
                zoneStat = "%s: %6s / " % (info, stat)

                if ttyCols and lenZone + lenZoneStat >= ttyCols:
                    zoneData = "%s\n%s %s" % (
                        zoneData,
                        " " * 14,
                        " " * nrIndent,
                    )
                    lenZone = nrIndent

                zoneData += zoneStat
                lenZone += lenZoneStat

            SysMgr.addPrint(
                "{0:<1}]\n".format(zoneData[:-2].rstrip()),
                newline=zoneData.count("\n") + 1,
            )

    def printIrqUsage(self, nrIndent):
        if not self.irqData:
            return

        nrIrq = 0
        irqData = "%s [IRQ > " % (" " * nrIndent)
        lenIrq = len(irqData)

        # add JSON stats #
        if SysMgr.jsonEnable:
            SysMgr.jsonData.setdefault("irq", {})

        for irq, cnt in sorted(
            self.irqData.items(),
            key=lambda e: self.irqData[e[0]]
            if not e[0] in self.prevIrqData
            else e[1] - self.prevIrqData[e[0]],
            reverse=True,
        ):

            if not irq in self.prevIrqData:
                irqDiff = cnt
            else:
                irqDiff = cnt - self.prevIrqData[irq]

            if irqDiff <= 0:
                break
            elif SysMgr.jsonEnable:
                SysMgr.jsonData["irq"][irq] = irqDiff

            nrIrq += 1
            newIrq = "%s: %s / " % (irq, UtilMgr.convNum(irqDiff))
            lenNewIrq = len(newIrq)

            if SysMgr.ttyCols and lenIrq + lenNewIrq >= SysMgr.ttyCols:
                irqData = "%s\n%s %s" % (irqData, " " * 7, " " * nrIndent)
                lenIrq = nrIndent

            irqData += newIrq
            lenIrq += lenNewIrq

        if nrIrq > 0:
            SysMgr.addPrint(
                "{0:<1}]\n".format(irqData[:-2].rstrip()),
                newline=irqData.count("\n") + 1,
            )

    def printPerfUsage(self, nrIndent):
        if not SysMgr.perfEventData:
            return

        perfString = SysMgr.getPerfString(SysMgr.perfEventData)
        if not perfString:
            return

        SysMgr.addPrint("%s %s\n" % (" " * nrIndent, perfString))

        # add JSON stats #
        if SysMgr.jsonEnable:
            SysMgr.jsonData.setdefault("PMU", {})
            jsonData = SysMgr.jsonData["PMU"]

            plist = perfString[1:-1].split(" / ")
            for stat in plist:
                metric, value = stat.split(":")
                jsonData[metric] = value.strip()

    def printNetworkUsage(self):
        if not SysMgr.networkEnable:
            return
        elif SysMgr.uptimeDiff == 0:
            return
        elif not SysMgr.sysInstance:
            return

        # update network usage #
        SysMgr.sysInstance.updateNetworkInfo()

        if SysMgr.checkCutCond():
            return

        SysMgr.addPrint("%s\n" % twoLine)
        SysMgr.addPrint(
            "{0:^40} | {1:^53} | {2:^53} |\n{3:1}\n".format(
                "Network", "Receive", "Transfer", oneLine
            ),
            newline=2,
        )
        SysMgr.addPrint(
            (
                "{0:^16} | {1:^21} | "
                "{2:^8} | {3:^8} | {4:^8} | {5:^8} | {6:^9} | "
                "{2:^8} | {3:^8} | {4:^8} | {5:^8} | {6:^9} |\n"
            ).format(
                "Dev", "IP", "Size", "Packet", "Error", "Drop", "Multicast"
            )
        )
        SysMgr.addPrint("%s\n" % twoLine)

        convSize = UtilMgr.convSize2Unit

        if SysMgr.jsonEnable:
            SysMgr.jsonData.setdefault("net", {})

        cnt = 0
        totalStat = {"rdiff": [0] * 5, "tdiff": [0] * 5}

        for dev, val in sorted(
            SysMgr.sysInstance.networkInfo.items(), key=lambda e: e[0]
        ):
            """
            [ network stat sequence ]
            bytes, packets, errs, drop, fifo,
                frame, compressed, multicast
            """

            try:
                rdiff = val["rdiff"]
                tdiff = val["tdiff"]

                # sum total stats #
                totalStat["rdiff"][0] += rdiff[0]
                totalStat["rdiff"][1] += rdiff[1]
                totalStat["rdiff"][2] += rdiff[2]
                totalStat["rdiff"][3] += rdiff[3]
                totalStat["rdiff"][4] += rdiff[-1]
                totalStat["tdiff"][0] += tdiff[0]
                totalStat["tdiff"][1] += tdiff[1]
                totalStat["tdiff"][2] += tdiff[2]
                totalStat["tdiff"][3] += tdiff[3]
                totalStat["tdiff"][4] += tdiff[-1]
            except SystemExit:
                sys.exit(0)
            except:
                rdiff = [0 for i in xrange(len(val["recv"]))]
                tdiff = [0 for i in xrange(len(val["tran"]))]

            try:
                # convert color for network usage #
                recvSize = "%8s" % convSize(rdiff[0])
                if rdiff[0] > 0:
                    recvSize = UtilMgr.convColor(recvSize, "YELLOW")
                tranSize = "%8s" % convSize(tdiff[0])
                if tdiff[0] > 0:
                    tranSize = UtilMgr.convColor(tranSize, "YELLOW")

                # convert color for network error #
                recvErr = "%8s" % convSize(rdiff[2])
                if rdiff[2] > 0:
                    recvErr = UtilMgr.convColor(recvErr, "RED")
                tranErr = "%8s" % convSize(tdiff[2])
                if tdiff[2] > 0:
                    tranErr = UtilMgr.convColor(tranErr, "RED")

                SysMgr.addPrint(
                    (
                        "{0:>16} | {1:>21} | "
                        "{2:>8} | {3:>8} | {4:>8} | {5:>8} | {6:>9} | "
                        "{7:>8} | {8:>8} | {9:>8} | {10:>8} | {11:>9} |\n"
                    ).format(
                        dev[-16:],
                        val["ipaddr"][:21],
                        recvSize,
                        convSize(rdiff[1]),
                        recvErr,
                        convSize(rdiff[3]),
                        convSize(rdiff[-1]),
                        tranSize,
                        convSize(tdiff[1]),
                        tranErr,
                        convSize(tdiff[3]),
                        convSize(tdiff[-1]),
                    )
                )
                cnt += 1
            except SystemExit:
                sys.exit(0)
            except:
                pass

        if cnt == 0:
            SysMgr.addPrint("\tNone\n")
        else:
            rdiff = totalStat["rdiff"]
            tdiff = totalStat["tdiff"]

            # convert color for network usage #
            recvSize = "%8s" % convSize(rdiff[0])
            if rdiff[0] > 0:
                recvSize = UtilMgr.convColor(recvSize, "YELLOW")
            tranSize = "%8s" % convSize(tdiff[0])
            if tdiff[0] > 0:
                tranSize = UtilMgr.convColor(tranSize, "YELLOW")

            # convert color for network error #
            recvErr = "%8s" % convSize(rdiff[2])
            if rdiff[2] > 0:
                recvErr = UtilMgr.convColor(recvErr, "RED")
            tranErr = "%8s" % convSize(tdiff[2])
            if tdiff[2] > 0:
                tranErr = UtilMgr.convColor(tranErr, "RED")

            SysMgr.addPrint(
                (
                    "{0:>16} | {1:^21} | "
                    "{2:>8} | {3:>8} | {4:>8} | {5:>8} | {6:>9} | "
                    "{7:>8} | {8:>8} | {9:>8} | {10:>8} | {11:>9} |\n"
                ).format(
                    "[ TOTAL ]",
                    " ",
                    recvSize,
                    convSize(rdiff[1]),
                    recvErr,
                    convSize(rdiff[3]),
                    convSize(rdiff[-1]),
                    tranSize,
                    convSize(tdiff[1]),
                    tranErr,
                    convSize(tdiff[3]),
                    convSize(tdiff[-1]),
                )
            )

    def printDiskUsage(self):
        if not SysMgr.diskEnable:
            return
        elif SysMgr.uptimeDiff == 0:
            return
        elif not SysMgr.sysInstance:
            return

        # update storage usage #
        SysMgr.sysInstance.updateStorageInfo()

        if SysMgr.checkCutCond():
            return

        # define shortcut variables #
        convColor = UtilMgr.convColor
        convSize2Unit = UtilMgr.convSize2Unit

        SysMgr.addPrint("%s\n" % twoLine)
        SysMgr.addPrint(
            (
                "{0:^24}|{1:4}|{2:^5}|{3:^7}|{4:^7}|{5:>7}({6:>7})|"
                "{7:^5}|{8:^7}|{9:^7}|{10:^8}|{11:^53}|\n"
            ).format(
                "DEV",
                "BUSY",
                "AVQ",
                "READ",
                "WRITE",
                "FREE",
                "DIFF",
                "USAGE",
                "TOTAL",
                "NrAVF",
                "FS",
                "MountPoint <Option>",
            )
        )
        SysMgr.addPrint("%s\n" % oneLine)

        storageData = SysMgr.sysInstance.storageData
        prevStorageData = SysMgr.sysInstance.prevStorageData

        if SysMgr.jsonEnable:
            SysMgr.jsonData.setdefault("storage", {})

        printCnt = 0
        for dev, value in sorted(
            storageData.items(),
            key=lambda e: e[1]["load"] if "load" in e[1] else 0,
            reverse=True,
        ):

            # skip total usage #
            if dev == "total":
                continue
            elif SysMgr.totalEnable:
                pass
            elif value["total"] == 0:
                continue

            # handle fs #
            origDev = dev
            if "mount" in value:
                if value["mount"]["fs"] == "tmpfs":
                    dev = value["mount"]["path"]
                elif value["mount"]["fs"] == "devfs":
                    continue

            # get readtime #
            try:
                if SysMgr.totalEnable:
                    readtime = value["readtime"]
                else:
                    readtime = (
                        value["readtime"]
                        - prevStorageData[origDev]["readtime"]
                    )
            except SystemExit:
                sys.exit(0)
            except:
                readtime = 0

            # get writetime #
            try:
                if SysMgr.totalEnable:
                    writetime = value["writetime"]
                else:
                    writetime = (
                        value["writetime"]
                        - prevStorageData[origDev]["writetime"]
                    )
            except SystemExit:
                sys.exit(0)
            except:
                writetime = 0

            # get busytime #
            try:
                if SysMgr.totalEnable:
                    iotime = value["iotime"]
                    busyper = long(iotime / 10.0 / SysMgr.uptime)
                else:
                    iotime = (
                        value["iotime"] - prevStorageData[origDev]["iotime"]
                    )
                    busyper = long(iotime / 10.0 / SysMgr.uptimeDiff)

                # convert color for storage busy rate #
                busytime = "%3s%%" % busyper
                if busyper > 0:
                    busytime = convColor(busytime, "RED")
            except SystemExit:
                sys.exit(0)
            except:
                busytime = "0%"

            # get avq #
            try:
                if SysMgr.totalEnable:
                    iowtime = value["iowtime"]
                else:
                    iowtime = (
                        value["iowtime"] - prevStorageData[origDev]["iowtime"]
                    )

                avq = "%.1f" % (iowtime / iotime)
            except SystemExit:
                sys.exit(0)
            except:
                avq = "0"

            # get read size on this interval #
            try:
                if SysMgr.totalEnable:
                    readSize = value["read"]
                else:
                    readSize = value["read"] - prevStorageData[origDev]["read"]

                if readSize:
                    readSize = convSize2Unit(readSize << 20)
                    readSize = convColor(readSize, "CYAN", 7)
            except SystemExit:
                sys.exit(0)
            except:
                readSize = 0

            # get write size on this interval #
            try:
                if SysMgr.totalEnable:
                    writeSize = value["write"]
                else:
                    writeSize = (
                        value["write"] - prevStorageData[origDev]["write"]
                    )

                if writeSize:
                    writeSize = convSize2Unit(writeSize << 20)
                    writeSize = convColor(writeSize, "CYAN", 7)
            except SystemExit:
                sys.exit(0)
            except:
                writeSize = 0

            # get other stats #
            if value["total"] > 0:
                total = convSize2Unit(value["total"] << 20)
                free = convSize2Unit(value["free"] << 20)
                fs = value["mount"]["fs"]
                path = value["mount"]["path"]

                try:
                    favail = "%7s" % convSize2Unit(value["favail"])
                    if value["favail"] == 0:
                        favail = convColor(favail, "RED")
                except SystemExit:
                    sys.exit(0)
                except:
                    favail = "%7s" % 0
            else:
                total = free = favail = fs = path = "-"

            # get free space change on this interval #
            try:
                freeDiff = value["free"] - prevStorageData[origDev]["free"]

                if freeDiff < 0:
                    op = "-"
                elif freeDiff == 0:
                    op = ""
                else:
                    op = "+"

                freeDiff = op + convSize2Unit(long(abs(freeDiff)) << 20)
            except SystemExit:
                sys.exit(0)
            except:
                freeDiff = 0

            # convert color for storage usage #
            usePer = "%4s%%" % value["usagePer"]
            if value["usagePer"] > SysMgr.diskPerHighThreshold:
                usePer = convColor(usePer, "RED")
            elif value["usagePer"] > 0:
                usePer = convColor(usePer, "YELLOW")

            # make disk stat string #
            option = "+".join(
                [value["mount"]["option"], value["mount"]["soption"]]
            )

            if option:
                mountInfo = "%s <%s>" % (path, option)
            else:
                mountInfo = path

            if "NOCUT" in SysMgr.environList:
                mountLen = None
            else:
                mountLen = 51

            diskInfo = (
                "{0:<24}|{1:>4}|{2:>5}|{3:>7}|{4:>7}|{5:>7}({6:>7})|"
                "{7:>5}|{8:>7}|{9:>7}|{10:>8}| {11:<52}|\n"
            ).format(
                dev[-24:],
                busytime,
                avq,
                readSize,
                writeSize,
                free,
                freeDiff,
                usePer,
                total,
                favail,
                fs,
                mountInfo[:mountLen],
            )

            if SysMgr.checkCutCond():
                return

            SysMgr.addPrint(diskInfo)

            printCnt += 1

        if printCnt == 0:
            SysMgr.addPrint("\tNone\n")

    def getSortedProcData(self):
        checkCond = True

        # check order type #
        if "ORDERASC" in SysMgr.environList:
            reverse = False
        elif "ORDERDESC" in SysMgr.environList:
            reverse = True
        else:
            reverse = None

        # memory #
        if not SysMgr.sort:
            # set CPU usage as default #
            sortedProcData = sorted(
                self.procData.items(),
                key=lambda e: e[1]["ttime"],
                reverse=True if reverse is None else reverse,
            )
        elif SysMgr.sort == "m":
            sortedProcData = sorted(
                self.procData.items(),
                key=lambda e: long(e[1]["stat"][self.rssIdx]),
                reverse=True if reverse is None else reverse,
            )
        # block #
        elif SysMgr.sort == "b":
            sortedProcData = sorted(
                self.procData.items(),
                key=lambda e: e[1]["rw"],
                reverse=True if reverse is None else reverse,
            )
        # WFC #
        elif SysMgr.sort == "w":
            sortedProcData = sorted(
                self.procData.items(),
                key=lambda e: e[1]["cttime"],
                reverse=True if reverse is None else reverse,
            )
        # pid #
        elif SysMgr.sort == "p":
            sortedProcData = sorted(
                self.procData.items(),
                key=lambda e: long(e[0]),
                reverse=False if reverse is None else reverse,
            )
            checkCond = False
        # new #
        elif SysMgr.sort == "n":
            sortedProcData = sorted(
                self.procData.items(),
                key=lambda e: e[1]["new"],
                reverse=True if reverse is None else reverse,
            )
            checkCond = False
        # runtime #
        elif SysMgr.sort == "r":
            sortedProcData = sorted(
                self.procData.items(),
                key=lambda e: e[1]["runtime"],
                reverse=True if reverse is None else reverse,
            )
        # oomscore #
        elif SysMgr.sort == "o":
            sortedProcData = sorted(
                self.procData.items(),
                key=lambda e: e[1]["oomScore"],
                reverse=True if reverse is None else reverse,
            )
        # priority #
        elif SysMgr.sort == "P":
            sortedProcData = sorted(
                self.procData.items(),
                key=lambda e: long(e[1]["stat"][self.prioIdx]),
                reverse=False if reverse is None else reverse,
            )
            checkCond = False
        # exectime #
        elif SysMgr.sort in ("e", "d"):
            if SysMgr.sort == "e":
                statName = "execTime"
            elif SysMgr.sort == "d":
                statName = "waitTime"

            try:
                for idx, value in self.procData.items():
                    self.saveProcSchedData(value["taskPath"], idx)

                sortedProcData = sorted(
                    self.procData.items(),
                    key=lambda e: e[1][statName],
                    reverse=True if reverse is None else reverse,
                )
            except SystemExit:
                sys.exit(0)
            except:
                sortedProcData = self.procData.items()
        # swap #
        elif SysMgr.sort == "s":
            try:
                for idx, value in self.procData.items():
                    self.saveProcStatusData(value["taskPath"], idx)

                sortedProcData = sorted(
                    self.procData.items(),
                    key=lambda e: long(e[1]["status"]["VmSwap"].split()[0])
                    if e[1]["status"]
                    else 0,
                    reverse=True if reverse is None else reverse,
                )
            except SystemExit:
                sys.exit(0)
            except:
                sortedProcData = self.procData.items()
        # contextswitch #
        elif SysMgr.sort == "C":
            try:
                for idx, value in self.procData.items():
                    self.saveProcStatusData(value["taskPath"], idx)

                now = self.procData
                prev = self.prevProcData
                yld = "voluntary_ctxt_switches"
                prmpt = "nonvoluntary_ctxt_switches"
                sortedProcData = sorted(
                    now.items(),
                    key=lambda k: (
                        long(now[k[0]]["status"][yld])
                        - long(prev[k[0]]["status"][yld])
                    )
                    + (
                        long(now[k[0]]["status"][prmpt])
                        - long(prev[k[0]]["status"][prmpt])
                    )
                    if k[0] in prev
                    else 0,
                    reverse=True if reverse is None else reverse,
                )
            except SystemExit:
                sys.exit(0)
            except:
                sortedProcData = self.procData.items()
        # dbus #
        elif SysMgr.sort == "d":
            sortedProcData = sorted(
                self.procData.items(),
                key=lambda e: long(e[1]["dbusCnt"])
                if "dbusCnt" in e[1]
                else 0,
                reverse=True if reverse is None else reverse,
            )
            checkCond = False
        # name #
        elif SysMgr.sort == "N":
            sortedProcData = sorted(
                self.procData.items(),
                key=lambda e: e[1]["stat"][self.commIdx],
                reverse=False if reverse is None else reverse,
            )
            checkCond = False
        # CPU #
        else:
            # set CPU usage as default #
            sortedProcData = sorted(
                self.procData.items(),
                key=lambda e: e[1]["ttime"],
                reverse=True if reverse is None else reverse,
            )

        # convert sort condition type to number #
        if checkCond and SysMgr.sortCond:
            try:
                origCond = SysMgr.sortCond

                if SysMgr.sort in ("r", "e"):
                    SysMgr.sortCond = UtilMgr.convUnit2Time(origCond)
                else:
                    SysMgr.sortCond = UtilMgr.convUnit2Size(origCond)

                if origCond != SysMgr.sortCond:
                    SysMgr.printInfo(
                        "converted sort condition '%s' to '%s'"
                        % (origCond, SysMgr.sortCond)
                    )
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "failed to convert '%s' to number for sort condition"
                    % SysMgr.sortCond,
                    True,
                )
                sys.exit(-1)

        return sortedProcData

    def getCgroupUsage(self):
        interval = SysMgr.uptimeDiff
        if interval == 0:
            interval = 0.1

        stats = {}
        prevData = self.prevCgroupData
        cpuStatStr = "nr_periods 0\nnr_throttled 0\nthrottled_time 0"

        for system, groups in self.cgroupData.items():
            for group, values in groups.items():
                # filter group #
                if SysMgr.filterGroup:
                    if not UtilMgr.isValidStr(group, ignCap=True):
                        continue

                for name, value in values.items():
                    stats.setdefault(group, {})

                    if name == "tasks" or name == "cgroup.procs":
                        stat = value.count("\n")
                    elif name == "cpu.stat":
                        if value.startswith(cpuStatStr):
                            continue

                        try:
                            # throttled_time #
                            stat = long(value.split("\n")[2].split()[1])
                            pvalue = prevData[system][group][name]
                            prevStat = long(pvalue.split("\n")[2].split()[1])
                            stat = stat - prevStat
                        except SystemExit:
                            sys.exit(0)
                        except:
                            stat = 0
                    else:
                        stat = long(value.rstrip())

                        # calculate usage #
                        if system == "cpuacct":
                            try:
                                prevStat = prevData[system][group][name]
                                prevStat = long(prevStat.rstrip())
                                stat = stat - prevStat
                            except SystemExit:
                                sys.exit(0)
                            except:
                                pass

                    # save stat #
                    stats[group].setdefault(name, stat)
                    if stats[group][name] == 0:
                        stats[group][name] = stat

        return stats

    def printCgroupUsage(self):
        # check return condition #
        if SysMgr.uptimeDiff == 0 or SysMgr.checkCutCond():
            return
        elif not self.cgroupData:
            SysMgr.addPrint(twoLine)
            return

        # calculate resource usage of cgroup #
        stats = self.getCgroupUsage()

        # print menu #
        ret = SysMgr.addPrint(
            (
                "{0:1}\n{1:<108}|{2:>4}|{3:>4}|"
                "{4:>6}|{5:>3}|{6:>7}|{7:>7}|{8:>7}|\n{9:1}\n"
            ).format(
                twoLine,
                "Control Group",
                "Proc",
                "Task",
                "CPU(%)",
                "Thr",
                "Memory",
                "Read",
                "Write",
                oneLine,
            ),
            newline=3,
        )

        # set sort value #
        if SysMgr.sort == "m":
            item = "memory.usage_in_bytes"
        else:
            item = "cpuacct.usage"

        # iterate stats #
        for system, value in sorted(
            stats.items(),
            key=lambda e: e[1][item] if item in e[1] else 0,
            reverse=True,
        ):

            # CPU Usage #
            try:
                usage = value["cpuacct.usage"] / 10000000
                cpu = "%6.1f" % usage

                # convert color for CPU usage #
                if usage < SysMgr.cpuPerLowThreshold:
                    pass
                else:
                    cpu = UtilMgr.convCpuColor(usage, cpu)
            except SystemExit:
                sys.exit(0)
            except:
                cpu = 0

            # CPU Throttle #
            try:
                throttle = long(value["cpu.stat"] / 10000000)
                throttle = UtilMgr.convCpuColor(usage, throttle, 3)
            except SystemExit:
                sys.exit(0)
            except:
                throttle = 0

            # Memory #
            try:
                mem = value["memory.usage_in_bytes"]
                mem = UtilMgr.convSize2Unit(mem)
            except SystemExit:
                sys.exit(0)
            except:
                mem = 0

            # Task #
            try:
                proc = value["cgroup.procs"]
                task = value["tasks"]
            except SystemExit:
                sys.exit(0)
            except:
                proc = 0
                task = 0

            # print stats of a process #
            ret = SysMgr.addPrint(
                (
                    "{0:<108}|{1:>4}|{2:>4}|"
                    "{3:>6}|{4:>3}|{5:>7}|{6:>7}|{7:>7}|\n"
                ).format(
                    system[-108:], proc, task, cpu, throttle, mem, "-", "-"
                )
            )
            if not ret:
                return -1

        if not stats:
            SysMgr.addPrint("\tNone\n")

        SysMgr.addPrint("%s\n" % oneLine)

    def printTaskUsageGen(self, idIndex=False):
        # check return condition #
        if SysMgr.uptimeDiff == 0 or SysMgr.checkCutCond():
            return
        elif not self.procData:
            ret = SysMgr.addPrint("%s\n" % twoLine)
            if not ret:
                return
            ret = SysMgr.addPrint("\tNone\n")
            if not ret:
                return
            SysMgr.addPrint(oneLine)
            return

        # increase print tick #
        self.printTick += 1

        # get pid length #
        pd = len(str(SysMgr.maxPid))
        if pd < 5:
            pd = 5

        # print menu #
        if not self.taskStreamEnable or self.printTick <= 1:
            ret = SysMgr.addPrint(
                (
                    "{24:1}\n{0:>16} ({1:>{pd}}/{2:>{pd}}/{3:>4}/{4:>4})|"
                    "{5:>4}({6:^3}/{7:^3}/{8:^3})|"
                    "{9:>4}({10:>4}/{11:^3}/{12:^3}/{13:^3})|"
                    "{14:>4}({15:>4}/{16:>4}/{17:>5})|"
                    "{18:^5}|{19:^6}|{20:^4}|{21:>9}|{22:^21}|\n{23:1}\n"
                ).format(
                    "Process",
                    "PID",
                    "PPID",
                    "Nr",
                    "Pri",
                    "CPU",
                    "Usr",
                    "Ker",
                    "Dly",
                    "VSS",
                    "RSS",
                    "Txt",
                    "Shr",
                    "Swp",
                    "Blk",
                    "RD",
                    "WR",
                    "NrFlt",
                    "Yld",
                    "User",
                    "FD",
                    "LifeTime",
                    "Parent",
                    oneLine,
                    twoLine,
                    pd=pd,
                ),
                newline=3,
            )
            if not ret:
                return

        # print stats #
        printCnt = 0
        uptimeDiff = SysMgr.uptimeDiff
        for pid, value in sorted(
            self.procData.items(),
            key=lambda e: e[1]["ttimeDiff"],
            reverse=True,
        ):
            # CPU #
            ttime = long(value["ttimeDiff"] * 100 / uptimeDiff)
            stime = long(value["stimeDiff"] * 100 / uptimeDiff)
            utime = long(value["utimeDiff"] * 100 / uptimeDiff)
            btime = 0

            ppid = value["ppid"]

            # check break condition #
            if SysMgr.filterGroup:
                if not UtilMgr.isValidStr(value["comm"]):
                    continue
            elif not SysMgr.showAll and ttime == 0:
                break

            printCnt += 1

            # I/O #
            read = 0
            write = 0
            nrpgflt = value["nrpgfltDiff"]

            nryield = value["yieldDiff"]
            nrpreempted = value["preemptedDiff"]

            # memory #
            rss = value["rss"]
            if SysMgr.isDarwin:
                vss = value["vss"]  # GB #
            else:
                vss = value["vss"]  # MB #

            # user #
            if value["user"]:
                user = value["user"][:6]
            else:
                user = " "

            # etc #
            code = 0
            shr = 0
            swap = 0
            pri = value["nice"]

            if ppid in self.procData:
                etc = "%s(%s)" % (self.procData[ppid]["comm"], ppid)
            else:
                etc = ""

            # print stats of a process #
            ret = SysMgr.addPrint(
                (
                    "{0:>16} ({1:>{pd}}/{2:>{pd}}/{3:>4}/{4:>4})|"
                    "{5:>4}({6:>3}/{7:>3}/{8:>3})|"
                    "{9:>4}({10:>4}/{11:>3}/{12:>3}/{13:>3})|"
                    "{14:>4}({15:>4}/{16:>4}/{17:>5})|"
                    "{18:>5}|{19:>6}|{20:>4}|{21:>9}|{22:>21}|\n"
                ).format(
                    value["comm"][:16],
                    pid,
                    ppid,
                    value["nrThread"],
                    pri,
                    ttime,
                    utime,
                    stime,
                    0,
                    vss,
                    rss,
                    code,
                    shr,
                    swap,
                    btime,
                    read,
                    write,
                    nrpgflt,
                    nryield,
                    user,
                    value["nrFds"],
                    UtilMgr.convTime(value["runtime"])[:9],
                    etc[:21],
                    pd=pd,
                )
            )
            if not ret:
                return

            # print cmdline #
            if SysMgr.cmdlineEnable and value["cmdline"]:
                SysMgr.addPrint(
                    "{0:>39} | {1:1}\n".format("CMDLINE", value["cmdline"])
                )

        if printCnt == 0:
            ret = SysMgr.addPrint("\tNone\n")
            if not ret:
                return

        SysMgr.addPrint(oneLine)

    def printTaskUsage(self, idIndex=False):
        def _isBreakCond(idx, value):
            # define target #
            if not SysMgr.sort or SysMgr.sort == "c":
                target = value["ttime"]
            elif SysMgr.sort == "m":
                target = long(stat[self.rssIdx]) >> 8
            elif SysMgr.sort == "b":
                target = value["rw"]
            elif SysMgr.sort == "w":
                target = value["cttime"]
            elif SysMgr.sort == "p":
                target = long(idx)
            elif SysMgr.sort == "n":
                target = value["new"]
            elif SysMgr.sort == "o":
                target = value["oomScore"]
            elif SysMgr.sort == "r":
                target = value["runtime"]
            elif SysMgr.sort == "e":
                target = value["execTime"] / 1000000000
            elif SysMgr.sort == "d":
                target = value["waitTime"] / 1000000000
            elif SysMgr.sort == "s":
                try:
                    target = long(value["status"]["VmSwap"].split()[0]) << 10
                except SystemExit:
                    sys.exit(0)
                except:
                    target = 0
            elif SysMgr.sort == "C":
                try:
                    prevStat = self.prevProcData[idx]["status"]
                    prevCtx = long(prevStat["voluntary_ctxt_switches"]) + long(
                        prevStat["nonvoluntary_ctxt_switches"]
                    )
                except SystemExit:
                    sys.exit(0)
                except:
                    prevCtx = 0

                try:
                    nowStat = value["status"]
                    nowCtx = long(nowStat["voluntary_ctxt_switches"]) + long(
                        nowStat["nonvoluntary_ctxt_switches"]
                    )
                except SystemExit:
                    sys.exit(0)
                except:
                    nowCtx = 0

                target = nowCtx - prevCtx
            else:
                target = 1

            # check sort condition #
            try:
                if SysMgr.sortCond:
                    if not SysMgr.sortCondOp or SysMgr.sortCondOp == ">":
                        if target <= long(SysMgr.sortCond):
                            return True
                        else:
                            return False
                    else:
                        if target >= long(SysMgr.sortCond):
                            return True
                        else:
                            return False
            except SystemExit:
                sys.exit(0)
            except:
                pass

            # check filter #
            if not SysMgr.filterGroup and not SysMgr.showAll and not target:
                return True
            else:
                return False

        def _isExceptTask(idx):
            def __check2ndFilter(exceptFlag):
                if exceptFlag:
                    return True
                elif "FILTER" in SysMgr.environList and not UtilMgr.isValidStr(
                    procData[idx]["comm"].lstrip("*"),
                    SysMgr.environList["FILTER"],
                ):
                    return True
                else:
                    return False

            exceptFlag = False

            # check comm and ID #
            if not TaskAnalyzer.checkFilter(
                procData[idx]["comm"].lstrip("*"), idx
            ):
                exceptFlag = True
            else:
                exceptFlag = __check2ndFilter(exceptFlag)

            # save cmdline info #
            if exceptFlag and SysMgr.filterGroup and SysMgr.cmdlineEnable:
                self.saveCmdlineData(procData[idx]["taskPath"], idx)
                if TaskAnalyzer.checkFilter(procData[idx]["cmdline"], idx):
                    exceptFlag = False

            # single mode #
            if not SysMgr.groupProcEnable:
                return exceptFlag
            # group mode #
            elif not exceptFlag:
                return exceptFlag
            # check siblings #
            else:
                exceptFlag = False

            for item in list(SysMgr.filterGroup):
                # process mode #
                if SysMgr.processEnable:
                    ppid = procData[idx]["stat"][self.ppidIdx]

                    # check current's parent pid by comm #
                    if ppid in plist:
                        break
                    # check current's parent comm #
                    elif ppid in procData and UtilMgr.isValidStr(
                        procData[ppid]["comm"].lstrip("*"), [item]
                    ):
                        break
                    # check current's parent pid #
                    elif (
                        item in procData
                        and procData[item]["stat"][self.ppidIdx]
                        == stat[self.ppidIdx]
                    ):
                        break
                    else:
                        exceptFlag = True
                # thread mode #
                else:
                    pid = procData[idx]["mainID"]

                    # check current pid by comm #
                    if pid in plist:
                        break
                    # check current process comm #
                    elif pid in procData and UtilMgr.isValidStr(
                        procData[pid]["comm"].lstrip("*"), [item]
                    ):
                        break
                    # check current's pid #
                    elif (
                        item in procData
                        and procData[item]["mainID"] == value["mainID"]
                    ):
                        break
                    elif idx == item or value["mainID"] == item:
                        break
                    else:
                        exceptFlag = True

            exceptFlag = __check2ndFilter(exceptFlag)

            return exceptFlag

        def _getParentList():
            if not SysMgr.groupProcEnable:
                return {}

            plist = {}

            for idx, value in sortedProcData:
                if not UtilMgr.isValidStr(value["comm"].lstrip("*")):
                    continue

                if SysMgr.processEnable:
                    plist[self.procData[idx]["stat"][self.ppidIdx]] = 0
                else:
                    plist[self.procData[idx]["mainID"]] = 0

            return plist

        def _getTypes():
            if SysMgr.processEnable:
                mode = "Process"
                pidType = "PID"
                ppidType = "PPID"
                sidType = "SID"
                pgrpType = "USER"
            else:
                mode = "Thread"
                pidType = "TID"
                ppidType = "PID"
                sidType = "Yld"
                pgrpType = "Prmt"

            # check GPU option #
            if (
                "GPUMEM" in SysMgr.environList
                or "GPUMEMSUM" in SysMgr.environList
            ):
                sidType = "GPU"

            # check delay option #
            if SysMgr.wfcEnable:
                dprop = "WFC"
            else:
                dprop = "Dly"

            # check last field #
            if SysMgr.wchanEnable:
                etc = "WaitChannel"
            elif SysMgr.affinityEnable:
                etc = "Affinity"
            elif SysMgr.oomEnable:
                etc = "OOMScore"
            elif SysMgr.sigHandlerEnable:
                etc = "SignalHandler"
            elif SysMgr.processEnable:
                etc = "Parent"
            else:
                etc = "Process"

            # set memory type #
            if SysMgr.pssEnable:
                mem = "PSS"
            elif SysMgr.ussEnable:
                mem = "USS"
            else:
                mem = "RSS"

            return mode, pidType, ppidType, sidType, pgrpType, dprop, etc, mem

        def _printStackSamples(idx):
            # set indent size including arrow #
            initIndent = 42

            for stack, cnt in sorted(
                self.stackTable[idx]["stack"].items(),
                key=lambda e: e[1],
                reverse=True,
            ):

                line = ""
                newLine = 1
                fullstack = ""
                per = long((cnt / float(self.stackTable[idx]["total"])) * 100)
                self.stackTable[idx]["stack"][stack] = 0

                if per == 0:
                    continue

                indent = initIndent + 3

                for call in stack.split("\n"):
                    try:
                        astack = call.split()[1]

                        if astack.startswith("0xffffffff"):
                            if fullstack == line == "":
                                line = "N/A"
                            else:
                                line = line[: line.rfind("<-")]
                            break

                        lenLine = indent + len(line) + len(astack)
                        if lenLine >= SysMgr.lineLength:
                            indent = 0
                            fullstack = "%s%s\n" % (fullstack, line)
                            newLine += 1
                            line = " " * initIndent

                        line = "%s%s <- " % (line, astack)
                    except:
                        pass

                fullstack += line
                fullstack = fullstack.rstrip(" <- ")

                ret = SysMgr.addPrint(
                    "{0:>39} | {1:1}\n".format(
                        "KSTACK(%3s%%)" % per, fullstack
                    ),
                    newLine,
                )
                if not ret:
                    return -1

            return newLine

        def _printDelay(self, value):
            if not SysMgr.delayEnable:
                return

            conv = UtilMgr.convNum

            # get performance stats #
            while 1:
                val = SysMgr.getTaskstats(idx)
                if not val or str(val["ac_pid"]) == idx:
                    break

            scaledFactor = 1000000000.0

            # get total usage #
            try:
                cpuRealTotal = val["cpu_run_real_total"] / scaledFactor
                cpuVirtTotal = val["cpu_run_virtual_total"] / scaledFactor
                cpuStimeTotal = val["ac_stime"] / 1000000.0
                cpuStimePer = cpuStimeTotal / cpuRealTotal * 100
                cpuUtimeTotal = val["ac_utime"] / 1000000.0
                cpuUtimePer = cpuUtimeTotal / cpuRealTotal * 100
                majfltTotal = conv(val["ac_majflt"])
                minfltTotal = conv(val["ac_minflt"])

                cpuTotalStr = (
                    "REALTIME: %.3f / VIRTTIME: %.3f / STIME: %.3f(%d%%) / "
                    "UTIME: %.3f(%d%%) / MAJFLT: %s / MINFLT: %s"
                ) % (
                    cpuRealTotal,
                    cpuVirtTotal,
                    cpuStimeTotal,
                    cpuStimePer,
                    cpuUtimeTotal,
                    cpuUtimePer,
                    majfltTotal,
                    minfltTotal,
                )

                SysMgr.addPrint(
                    "{0:>39} | {1:1}\n".format("TOTAL_USAGE", cpuTotalStr)
                )
            except SystemExit:
                sys.exit(0)
            except:
                pass

            # get total delay #
            cpuDelay = val["cpu_delay_total"]
            blkDelay = val["blkio_delay_total"]
            swapDelay = val["swapin_delay_total"]
            rclmDelay = val["freepages_delay_total"]

            value["delay"] = {
                "CPU": cpuDelay,
                "BLK": blkDelay,
                "SWAP": swapDelay,
                "RCLM": rclmDelay,
            }

            prevData = self.prevProcData[idx]

            cpuTotalDelay = cpuDelay / scaledFactor
            blkTotalDelay = blkDelay / scaledFactor
            swapTotalDelay = swapDelay / scaledFactor
            rclmTotalDelay = rclmDelay / scaledFactor

            delayTotalStr = (
                "CPU: %.3f / BLK: %.3f / SWAP: %.3f / RCLM: %.3f"
                % (
                    cpuTotalDelay,
                    blkTotalDelay,
                    swapTotalDelay,
                    rclmTotalDelay,
                )
            )

            SysMgr.addPrint(
                "{0:>39} | {1:1}\n".format("TOTAL_DELAY", delayTotalStr)
            )

            if not "delay" in prevData:
                return

            cpuDelayDiff = cpuDelay - prevData["delay"]["CPU"]
            blkDelayDiff = blkDelay - prevData["delay"]["BLK"]
            swapDelayDiff = swapDelay - prevData["delay"]["SWAP"]
            rclmDelayDiff = rclmDelay - prevData["delay"]["RCLM"]

            cpuDelayDiff /= scaledFactor
            blkDelayDiff /= scaledFactor
            swapDelayDiff /= scaledFactor
            rclmDelayDiff /= scaledFactor

            delayStr = "CPU: %.3f / BLK: %.3f / SWAP: %.3f / RCLM: %.3f" % (
                cpuDelayDiff,
                blkDelayDiff,
                swapDelayDiff,
                rclmDelayDiff,
            )

            SysMgr.addPrint(
                "{0:>39} | {1:1}\n".format("INTER_DELAY", delayStr)
            )

        # check return condition #
        if SysMgr.uptimeDiff == 0 or SysMgr.checkCutCond():
            return
        elif not self.procData:
            SysMgr.addPrint(twoLine)
            return

        # pid length #
        pd = self.getPidLen()

        # comm length #
        if "COMMLEN" in SysMgr.environList:
            cl = UtilMgr.getEnvironNum("COMMLEN")
        else:
            cl = 26 - (pd * 2)

        # calculate resource usage of processes #
        self.setProcUsage()

        # get types #
        (
            mode,
            pidType,
            ppidType,
            sidType,
            pgrpType,
            dprop,
            etc,
            mem,
        ) = _getTypes()

        # check EXCEPTSHM #
        if (
            not (SysMgr.pssEnable or SysMgr.ussEnable)
            and "EXCEPTSHM" in SysMgr.environList
        ):
            exceptShm = True
            mem = "U" + mem
        else:
            exceptShm = False

        # check GPU memory sum #
        if "GPUMEMSUM" in SysMgr.environList:
            isGpuMemSum = True
            mem = "G" + mem
        else:
            isGpuMemSum = False

        # check GPU memory #
        if "GPUMEM" in SysMgr.environList:
            isGpuMem = True
        else:
            isGpuMem = False

        # add JSON stats #
        if SysMgr.jsonEnable:
            jtype = mode.lower()
            SysMgr.jsonData.setdefault(jtype, {})
            jsonData = SysMgr.jsonData[jtype]

        # increase print tick #
        self.printTick += 1

        # print menu #
        if not self.taskStreamEnable or self.printTick <= 1:
            ret = SysMgr.addPrint(
                (
                    "{24:1}\n{0:>{cl}} ({1:>{pd}}/{2:>{pd}}/{3:>4}/{4:>4})|"
                    "{5:>4}({6:^3}/{7:^3}/{8:^3})|"
                    "{9:>4}({10:>4}/{11:^3}/{12:^3}/{13:^3})|"
                    "{14:>4}({15:>4}/{16:>4}/{17:>5})|"
                    "{18:^5}|{19:^6}|{20:^4}|{21:>9}|{22:^21}|\n{23:1}\n"
                ).format(
                    mode,
                    pidType,
                    ppidType,
                    "Nr",
                    "Pri",
                    "CPU",
                    "Usr",
                    "Ker",
                    dprop,
                    "VSS",
                    mem,
                    "Txt",
                    "Shr",
                    "Swp",
                    "Blk",
                    "RD",
                    "WR",
                    "NrFlt",
                    sidType,
                    pgrpType,
                    "FD",
                    "LifeTime",
                    etc,
                    oneLine,
                    twoLine,
                    cl=cl,
                    pd=pd,
                ),
                newline=3,
            )
            if not ret:
                return

        # set sort value #
        sortedProcData = self.getSortedProcData()

        # make parent list #
        plist = _getParentList()

        # define convert function #
        convNum = UtilMgr.convNum
        convSize = UtilMgr.convSize2Unit
        convTime = UtilMgr.convTime
        convColor = UtilMgr.convColor
        convCpuColor = UtilMgr.convCpuColor

        totalStats = {"read": 0, "write": 0, "yld": 0, "prtd": 0, "task": 0}

        # clear ID list #
        if idIndex:
            SysMgr.idList = []

        # get FD attribute info #
        if "ACTUALFD" in SysMgr.environList:
            useActualFd = True
        else:
            useActualFd = False

        # check WSS init #
        if SysMgr.initWssEnable:
            initWss = True
            SysMgr.initWssEnable = False
        else:
            initWss = False

        # init normal task dict #
        saveJsonStat = False
        if SysMgr.reportEnable and "SAVEJSONSTAT" in SysMgr.environList:
            self.reportData.setdefault("task", {})
            self.reportData["task"].setdefault("normal", {})
            saveJsonStat = True

        # set maximum top rank #
        if "NRTOPRANK" in SysMgr.environList:
            nrTopRank = UtilMgr.getEnvironNum("NRTOPRANK", isInt=True)
        else:
            nrTopRank = sys.maxsize

        # print resource usage of tasks #
        procCnt = 0
        procData = self.procData
        for idx, value in sortedProcData:
            stat = value["stat"]

            # check exception flag #
            if SysMgr.filterGroup and _isExceptTask(idx):
                continue

            # add task to fixed target list #
            if SysMgr.fixTargetEnable:
                SysMgr.fixedProcList.setdefault(idx, None)

            # add task into JSON data #
            if SysMgr.jsonEnable:
                jsonData.setdefault(
                    idx,
                    UtilMgr.convStr2Dict(
                        UtilMgr.convDict2Str(value, ignore=True)
                    ),
                )

            # add task into stack trace list #
            if SysMgr.stackEnable:
                self.stackTable.setdefault(idx, {})

                if not "fd" in self.stackTable[idx]:
                    spath = "%s/%s/stack" % (SysMgr.procPath, idx)
                    try:
                        self.stackTable[idx]["fd"] = open(spath, "r")
                        self.stackTable[idx]["stack"] = {}
                        self.stackTable[idx]["total"] = 0
                    except SystemExit:
                        sys.exit(0)
                    except:
                        SysMgr.printOpenWarn(spath)
                        self.stackTable.pop(idx, None)

            # check break condition #
            if _isBreakCond(idx, value):
                break
            # check the number of task #
            elif procCnt >= nrTopRank:
                break
            # check terminal rows #
            elif SysMgr.checkCutCond():
                return

            # init WSS #
            if initWss:
                # clear reference bits #
                SysMgr.clearPageRefs(idx, val="1")

            # comm #
            comm = value["comm"]
            if self.isKernelThread(idx):
                if comm.startswith("*"):
                    comm = "*[%s]" % comm.lstrip("*")
                else:
                    comm = "[%s]" % comm

            # parent ID #
            if SysMgr.processEnable:
                pid = stat[self.ppidIdx]
            else:
                pid = value["mainID"]

            # sched priority #
            SCHED_POLICY = ConfigMgr.SCHED_POLICY
            nrPrio = long(stat[self.prioIdx])
            if SCHED_POLICY[long(stat[self.policyIdx])] == "C":
                schedValue = "%3d" % (nrPrio - 20)
            else:
                schedValue = "%3d" % (abs(nrPrio + 1))

            # lifetime #
            lifeTime = convTime(value["runtime"])

            # save status info to get memory status #
            self.saveProcStatusData(value["taskPath"], idx)
            try:
                status = value["status"]
            except SystemExit:
                sys.exit(0)
            except:
                status = None

            # save cmdline info #
            self.saveCmdlineData(value["taskPath"], idx)

            # save cgroup info #
            self.saveCgroupData(value["taskPath"], idx)

            # save sched info to get delayed time #
            if not SysMgr.wfcEnable:
                self.saveProcSchedData(value["taskPath"], idx)

            # save wait channel info #
            if SysMgr.wchanEnable:
                self.saveProcWchanData(value["taskPath"], idx)

            # save memory map info to get memory details #
            if SysMgr.memEnable:
                TaskAnalyzer.saveProcSmapsData(
                    value["taskPath"], idx, mini=not SysMgr.wssEnable
                )

            # swap #
            try:
                swapSize = long(status["VmSwap"].split()[0]) >> 10
                value["swap"] = swapSize

                # add swap interval #
                self.addProcInterval("swap", idx, value, "swapInt", swapSize)
            except SystemExit:
                sys.exit(0)
            except:
                swapSize = "-"
                value["swap"] = 0

            # scheduling info #
            if not SysMgr.processEnable:
                try:
                    value["yield"] = status["voluntary_ctxt_switches"]
                    value["preempted"] = status["nonvoluntary_ctxt_switches"]
                except SystemExit:
                    sys.exit(0)
                except:
                    value["yield"] = "-"
                    value["preempted"] = "-"

            # user #
            try:
                if (
                    idx in self.prevProcData
                    and "user" in self.prevProcData[idx]
                ):
                    value["user"] = self.prevProcData[idx]["user"]
                else:
                    SysMgr.sysInstance.saveUserInfo()
                    userData = SysMgr.sysInstance.userData
                    uid = status["Uid"].split()[0]
                    value["user"] = userData[uid]["name"]
            except SystemExit:
                sys.exit(0)
            except:
                value["user"] = "-"

            # file descriptor table length #
            try:
                if useActualFd:
                    if self.isKernelThread(idx):
                        fdsize = 0
                    else:
                        fdsize = SysMgr.getNrFd(idx)
                else:
                    fdsize = long(status["FDSize"])

                # update fdsize #
                value["fdSize"] = fdsize

                # apply color #
                if fdsize > SysMgr.fdHighThreshold:
                    fdstr = convColor(fdsize, "RED", 4)
                else:
                    fdstr = fdsize
            except SystemExit:
                sys.exit(0)
            except:
                value["fdSize"] = 0
                fdstr = "-"

            # scheduling info #
            if SysMgr.processEnable:
                # sid #
                yld = stat[self.sidIdx][-5:]
                if yld == "0":
                    yld = "-"

                # user #
                try:
                    prtd = value["user"][:6]
                except SystemExit:
                    sys.exit(0)
                except:
                    prtd = "-"
            else:
                # yield #
                try:
                    if SysMgr.totalEnable:
                        yld = long(value["yield"])
                    else:
                        prevStatus = self.prevProcData[idx]["status"]
                        yld = long(value["yield"]) - long(
                            prevStatus["voluntary_ctxt_switches"]
                        )
                except SystemExit:
                    sys.exit(0)
                except:
                    yld = "-"

                # preempted #
                try:
                    if SysMgr.totalEnable:
                        prtd = long(value["preempted"])
                    else:
                        prevStatus = self.prevProcData[idx]["status"]
                        prtd = long(value["preempted"]) - long(
                            prevStatus["nonvoluntary_ctxt_switches"]
                        )
                except SystemExit:
                    sys.exit(0)
                except:
                    prtd = "-"

            # GPU memory usage #
            if isGpuMem or isGpuMemSum:
                if idx in self.gpuMemData:
                    yld = convColor(
                        self.gpuMemData[idx]["size"] >> 20, "CYAN", 5
                    )
                else:
                    yld = "-"

            try:
                # blocking time of parent process waits for its children #
                if SysMgr.wfcEnable:
                    dtime = long(value["cttime"])
                # calculate delayed time in runqueue #
                else:
                    if SysMgr.totalEnable:
                        prevExecTime = 0
                        prevWaitTime = 0
                    else:
                        prevExecTime = self.prevProcData[idx]["execTime"]
                        prevWaitTime = self.prevProcData[idx]["waitTime"]

                    execTime = value["execTime"] - prevExecTime
                    waitTime = value["waitTime"] - prevWaitTime
                    execPer = (execTime / (execTime + waitTime)) * 100
                    totalTime = value["ttime"] * (100 / execPer)
                    dtime = long(totalTime - value["ttime"])

                if dtime > 0:
                    dtime = convColor("%3s" % dtime, "RED")
            except SystemExit:
                sys.exit(0)
            except:
                dtime = "-"

            # I/O size #
            try:
                readSize = value["read"] >> 20
                if readSize > 0:
                    readSize = convColor("%4s" % readSize, "RED")

                writeSize = value["write"] >> 20
                if writeSize > 0:
                    writeSize = convColor("%4s" % writeSize, "RED")
            except SystemExit:
                sys.exit(0)
            except:
                readSize = "-"
                writeSize = "-"

            # last field info #
            try:
                if SysMgr.wchanEnable:
                    etc = value["wchan"]
                elif SysMgr.affinityEnable:
                    etc = SysMgr.getAffinity(long(idx))
                elif SysMgr.oomEnable:
                    etc = str(value["oomScore"])
                elif SysMgr.sigHandlerEnable:
                    etc = status["SigCgt"].lstrip("0")
                elif not SysMgr.processEnable:
                    pgid = procData[idx]["mainID"]
                    etc = "%s(%s)" % (procData[pgid]["comm"], pgid)
                else:
                    pgid = procData[idx]["stat"][self.ppidIdx]
                    if pgid == "0":
                        etc = "swapper(0)"
                    else:
                        etc = "%s(%s)" % (procData[pgid]["comm"], pgid)
            except SystemExit:
                sys.exit(0)
            except:
                etc = "-"

            # sched info #
            try:
                schedPolicy = SCHED_POLICY[int(stat[self.policyIdx])]
                sched = "%s%s" % (schedPolicy, schedValue)
            except SystemExit:
                sys.exit(0)
            except:
                sched = "?"

            # convert color for priority #
            try:
                if schedPolicy == "I":
                    sched = convColor(sched, "WARNING", 4)
                elif nrPrio < 20:
                    if nrPrio >= 0:
                        sched = convColor(sched, "YELLOW", 4)
                    else:
                        sched = convColor(sched, "RED", 4)
            except SystemExit:
                sys.exit(0)
            except:
                pass

            if SysMgr.customCmd:
                # execute command #
                if self.execEnable:
                    SysMgr.executeCommand(pid=idx, comm=comm.lstrip("*"))

                # add shortcut prefix to comm #
                if idIndex:
                    SysMgr.idList.append(idx)
                    idStr = "%s>" % (len(SysMgr.idList) - 1)
                    spaces = " " * (cl - len(idStr) - len(comm))
                    comm = "%s%s%s" % (idStr, spaces, comm)

            # remove unshown field in lifetime #
            if len(lifeTime.split(":")) > 3:
                lifeTime = lifeTime[: lifeTime.rfind(":")]

            # convert time format #
            if SysMgr.floatEnable:
                ttime = "%.1f" % value["ttime"]
                btime = "%.1f" % value["btime"]
            else:
                ttime = value["ttime"]
                btime = value["btime"]

            # convert color for CPU usage #
            if value["ttime"] >= SysMgr.cpuPerLowThreshold:
                ttime = convCpuColor(value["ttime"], ttime, size=4)

            # vss #
            try:
                vss = long(stat[self.vssIdx]) >> 20
            except SystemExit:
                sys.exit(0)
            except:
                vss = 0

            # get physical memory usages #
            memBuf = []
            if SysMgr.memEnable:
                memBuf, nrss, pss, uss = self.getMemDetails(
                    idx, value["maps"], vss=vss << 10
                )
                value["pss"] = pss >> 10
                value["uss"] = uss >> 10
            elif SysMgr.pssEnable:
                pss = TaskAnalyzer.readProcMemStats(
                    value["taskPath"], idx, retPss=True, retShr=False
                )[0]
                value["pss"] = pss >> 10
            elif SysMgr.ussEnable:
                shared = TaskAnalyzer.readProcMemStats(
                    value["taskPath"], idx, retPss=False, retShr=True
                )[1]
                value["uss"] = value["rss"] - (shared >> 10)

            # get main memory usage #
            if SysMgr.pssEnable:
                mems = value["pss"]
            elif SysMgr.ussEnable:
                mems = value["uss"]
            else:
                mems = value["rss"]

            # add GPU memory usage to physical memory usage #
            if isGpuMemSum and idx in self.gpuMemData:
                mems += self.gpuMemData[idx]["size"] >> 20

            # code size #
            try:
                codeSize = (
                    long(stat[self.ecodeIdx]) - long(stat[self.scodeIdx])
                ) >> 20

                # except for shred text in RSS #
                if exceptShm:
                    mems -= codeSize
                    if mems < 0:
                        mems = 0
            except SystemExit:
                sys.exit(0)
            except:
                codeSize = 0

            # shared #
            try:
                shr = long(value["statm"][self.shrIdx]) >> 8

                # except for shred memory in RSS #
                if exceptShm:
                    mems -= shr
                    if mems < 0:
                        mems = 0
            except SystemExit:
                sys.exit(0)
            except:
                shr = "-"

            # convert color for SHM #
            try:
                if long(shr) >= SysMgr.memLowThreshold:
                    if shr >= SysMgr.memHighThreshold:
                        shr = convColor(shr, "RED", 3)
                    else:
                        shr = convColor(shr, "YELLOW", 3)
            except SystemExit:
                sys.exit(0)
            except:
                pass

            # convert color for physical memory usage #
            if mems < SysMgr.memLowThreshold:
                memstr = mems
            else:
                if mems >= SysMgr.memHighThreshold:
                    memstr = convColor(mems, "RED", 4)
                else:
                    memstr = convColor(mems, "YELLOW", 4)

            # convert color for BTIME #
            if float(btime) > 0:
                btimestr = convColor(btime, "RED", 4)
            else:
                btimestr = btime

            # print stats of a process #
            ret = SysMgr.addPrint(
                (
                    "{0:>{cl}} ({1:>{pd}}/{2:>{pd}}/{3:>4}/{4:>4})|"
                    "{5:>4}({6:>3}/{7:>3}/{8:>3})|"
                    "{9:>4}({10:>4}/{11:>3}/{12:>3}/{13:>3})|"
                    "{14:>4}({15:>4}/{16:>4}/{17:>5})|"
                    "{18:>5}|{19:>6}|{20:>4}|{21:>9}|{22:>21}|\n"
                ).format(
                    comm[:cl],
                    idx,
                    pid,
                    stat[self.nrthreadIdx],
                    sched,
                    ttime,
                    value["utime"],
                    value["stime"],
                    dtime,
                    vss,
                    memstr,
                    codeSize,
                    shr,
                    swapSize,
                    btimestr,
                    readSize,
                    writeSize,
                    value["majflt"],
                    yld,
                    prtd,
                    fdstr,
                    lifeTime[:9],
                    etc[:21],
                    cl=cl,
                    pd=pd,
                )
            )
            if not ret:
                return

            # save normal task stat #
            if saveJsonStat:
                self.reportData["task"]["normal"][idx] = value

            # check stream flag #
            if self.taskStreamEnable:
                continue

            # sum stats #
            try:
                totalStats["ttime"] += value["ttime"]
                totalStats["utime"] += value["utime"]
                totalStats["stime"] += value["stime"]
                totalStats["mem"] += mems
                if swapSize != "-":
                    totalStats["swap"] += swapSize
                totalStats["btime"] += value["btime"]
                totalStats["majflt"] += value["majflt"]
                totalStats["task"] += 1
            except SystemExit:
                sys.exit(0)
            except:
                totalStats["ttime"] = value["ttime"]
                totalStats["utime"] = value["utime"]
                totalStats["stime"] = value["stime"]
                totalStats["mem"] = mems
                totalStats["swap"] = swapSize
                totalStats["btime"] = value["btime"]
                totalStats["majflt"] = value["majflt"]
                totalStats["task"] = 1

            if not SysMgr.processEnable:
                try:
                    totalStats["yld"] += yld
                    totalStats["prtd"] += prtd
                except SystemExit:
                    sys.exit(0)
                except:
                    pass
            else:
                totalStats["yld"] = "-"
                totalStats["prtd"] = "-"

            if SysMgr.blockEnable:
                try:
                    totalStats["read"] += value["read"]
                    totalStats["write"] += value["write"]
                except SystemExit:
                    sys.exit(0)
                except:
                    try:
                        totalStats["read"] = value["read"]
                        totalStats["write"] = value["write"]
                    except SystemExit:
                        sys.exit(0)
                    except:
                        totalStats["read"] = "-"
                        totalStats["write"] = "-"
            else:
                totalStats["read"] = "-"
                totalStats["write"] = "-"

            # print PMU stats #
            if SysMgr.perfGroupEnable:
                try:
                    perfData = SysMgr.collectProcPerfData(value["perfFds"])
                    perfString = SysMgr.getPerfString(perfData)
                    if perfString:
                        ret = SysMgr.addPrint(
                            "{0:>40}| {1:1}\n".format("PERF", perfString)
                        )
                        if not ret:
                            return
                except SystemExit:
                    sys.exit(0)
                except:
                    self.procData[idx]["perfFds"] = SysMgr.initProcPerfEvents(
                        long(idx)
                    )

            memItems = ("WSS", "USS", "PSS", "RSS", "VSS")

            # insert memory usage stats #
            if SysMgr.wssEnable:
                for kind in memItems:
                    memBuf.insert(0, [kind, ""])

            # print memory details #
            for memData in memBuf:
                mprop = memData[0]
                mval = memData[1]

                ret = SysMgr.addPrint(mval)
                if not ret:
                    return

                if not SysMgr.wssEnable:
                    continue

                # split a long line #
                tstr = ""
                indent = 54
                indenta = 5
                lenItem = 7
                isFirstLined = True
                limit = SysMgr.lineLength - indent
                pstr = procData[idx]["wss"][mprop]

                if SysMgr.showAll:
                    while len(pstr) > limit:
                        slimit = len(pstr[:limit])
                        des = pstr[:slimit]
                        tstr = "%s%s\n%s" % (
                            tstr,
                            des,
                            " " * (indent + indenta),
                        )

                        if isFirstLined:
                            limit -= indenta + lenItem
                            isFirstLined = False

                        pstr = pstr[slimit:]
                elif len(UtilMgr.removeColor(pstr)) > limit:
                    sizes = pstr.split("->")
                    sizes.pop(1)
                    pstr = "->".join(sizes)
                    procData[idx]["wss"][mprop] = pstr

                # highlight final size #
                sizes = pstr.rsplit("->", 1)
                if len(sizes) > 1:
                    sizes[1] = convColor(sizes[1], "CYAN", 7)
                    pstr = "->".join(sizes)
                elif SysMgr.showAll and not isFirstLined:
                    pstr = convColor(pstr, "CYAN")

                tstr += pstr

                # count newlines #
                newline = tstr.count("\n") + 1

                # set name #
                if mval:
                    name = "WSS"
                    title = " "
                else:
                    name = mprop
                    title = "MEM(%s)" % mprop

                # print info #
                ret = SysMgr.addPrint(
                    "{0:>39} | {1:3}: {2:1}\n".format(title, name, tstr),
                    newline,
                )
                if not ret:
                    return

            # print memory summary #
            if memBuf:
                vmlist = [
                    "VmPeak",
                    "VmHWM",
                    "VmData",
                    "HugetlbPages",
                    "RssAnon",
                    "RssFile",
                    "RssShmem",
                ]

                if status:
                    memstr = ""
                    memset = status

                    for item in vmlist:
                        try:
                            vmsize = long(memset[item].split()[0]) << 10
                            memstr += "%s: %s, " % (item, convSize(vmsize))
                        except SystemExit:
                            sys.exit(0)
                        except:
                            pass

                    if memstr:
                        SysMgr.addPrint(
                            "{0:>39} | {1:111}|\n".format(
                                "MEM(SUM)", memstr[:-2]
                            )
                        )

            # print cmdline #
            if SysMgr.cmdlineEnable and value["cmdline"]:
                SysMgr.addPrint(
                    "{0:>39} | {1:1}\n".format("CMDLINE", value["cmdline"])
                )

            # print namespace #
            if SysMgr.nsEnable and value["ns"]:
                SysMgr.addPrint(
                    "{0:>39} | {1:1}\n".format(
                        "NAMESPACE", value["ns"].rstrip(", ")
                    ),
                    newline=value["ns"].count("\n") + 1,
                )

            # print cgroup #
            if "cgroup" in value:
                SysMgr.addPrint(
                    "{0:>39} | {1:1}\n".format("CGROUP", value["cgroup"]),
                    newline=value["cgroup"].count("\n") + 1,
                )

            # print sched #
            if SysMgr.schedEnable and (
                "execTime" in value or "waitTime" in value
            ):
                execTime = float(long(value["execTime"] / 1000000000))
                if value["runtime"] > 0:
                    execPer = execTime / value["runtime"] * 100
                else:
                    execPer = 0
                waitTime = float(long(value["waitTime"] / 1000000000))
                if value["runtime"] > 0:
                    waitPer = waitTime / value["runtime"] * 100
                else:
                    waitPer = 0

                execStr = "Exec: %s(%.1f%%)" % (convTime(execTime), execPer)
                waitStr = "Wait: %s(%.1f%%)" % (convTime(waitTime), waitPer)
                sliceStr = "NrTimeslice: %s" % convNum(value["nrSlice"])
                schedStr = "%s / %s / %s" % (execStr, waitStr, sliceStr)
                SysMgr.addPrint("{0:>39} | {1:1}\n".format("SCHED", schedStr))

            # print delay #
            try:
                _printDelay(self, value)
            except SystemExit:
                sys.exit(0)
            except:
                pass

            # print D-Bus #
            if "dbusList" in value and value["dbusList"]:
                for line in value["dbusList"]:
                    SysMgr.addPrint("{0:>39} | {1:1}\n".format("D-BUS", line))

            # print stacks of threads sampled #
            if SysMgr.stackEnable:
                try:
                    if _printStackSamples(idx) == -1:
                        SysMgr.addPrint("---more---")
                        return
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

                try:
                    self.stackTable[idx]["total"] = 0
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

            procCnt += 1
            if SysMgr.memEnable:
                SysMgr.addPrint("%s\n" % oneLine)

        # check stream flag #
        if self.taskStreamEnable:
            return
        elif procCnt > 0:
            # total CPU #
            totalTime = "%6.1f" % totalStats["ttime"]
            totalTime = convCpuColor(totalStats["ttime"], totalTime)

            # total BLOCK #
            totalBtime = totalStats["btime"]
            if totalStats["btime"] > 0:
                totalBtime = convColor(totalBtime, "RED", 4)

            # total READ #
            readsize = totalStats["read"]
            if readsize != "-":
                readsize = readsize >> 20
                if readsize > 0:
                    readsize = convColor(readsize, "RED", 4)

            # total WRITE #
            writesize = totalStats["write"]
            if writesize != "-":
                writesize = writesize >> 20
                if writesize > 0:
                    writesize = convColor(writesize, "RED", 4)

            # total MEM #
            tmem = convSize(totalStats["mem"] << 20)
            tmem = convColor(tmem, "YELLOW", 7)

            # total SWAP #
            tswap = totalStats["swap"]
            try:
                if tswap > 0:
                    tswap = convSize(totalStats["swap"] << 20, True)
                    tswap = convColor(tswap, "YELLOW", 5)
            except SystemExit:
                sys.exit(0)
            except:
                pass

            # print total stats #
            SysMgr.addPrint(
                (
                    "{0:>{td}}|"
                    "{1:>6}({2:>4}/{3:>4})|"
                    "{4:>4}:{5:>7}|{6:>3}:{7:>5}|"
                    "{8:>4}({9:>4}/{10:>4}/{11:>5})|"
                    "{12:>12}|{13:>14}|{14:>21}|\n"
                ).format(
                    "[ TOTAL ]",
                    totalTime,
                    totalStats["utime"],
                    totalStats["stime"],
                    mem,
                    tmem,
                    "Swp",
                    tswap,
                    totalBtime,
                    readsize,
                    writesize,
                    totalStats["majflt"],
                    "Yld: %s" % convNum(totalStats["yld"]),
                    "Prmt: %s" % convNum(totalStats["prtd"]),
                    "Task: %s" % convNum(totalStats["task"]),
                    td=cl + (pd * 2) + 14,
                )
            )

            SysMgr.addPrint("%s\n" % oneLine)
        else:
            text = "{0:^16}".format("None")
            frame = "%s%s|" % (text, " " * (SysMgr.lineLength - len(text) - 1))
            SysMgr.addPrint("{0:1}\n{1:1}\n".format(frame, oneLine))

        # print special tasks #
        if not self.printSpecialTask("abnormal", saveJsonStat):
            return
        if not self.printSpecialTask("new", saveJsonStat):
            return
        if not self.printSpecialTask("die", saveJsonStat):
            return

    def getPidLen(self):
        pidlen = len(str(self.maxPid))
        if pidlen < 4:
            return 4
        else:
            return pidlen

    def printSpecialTask(self, taskType, saveJsonStat):
        # set comm and pid size #
        pd = self.getPidLen()
        cl = 26 - (pd * 2)

        # init task dict #
        if saveJsonStat:
            self.reportData.setdefault("task", {})
            self.reportData["task"].setdefault(taskType, {})
            jsonData = self.reportData["task"][taskType]

        # get task list #
        if taskType == "abnormal":
            taskList = set(self.abnormalTasks)
        elif taskType == "new":
            taskList = set(self.procData) - set(self.prevProcData)
        elif taskType == "die":
            taskList = set(self.prevProcData) - set(self.procData)

        # check EXCEPTSHM #
        if (
            not (SysMgr.pssEnable or SysMgr.ussEnable)
            and "EXCEPTSHM" in SysMgr.environList
        ):
            exceptShm = True
        else:
            exceptShm = False

        procCnt = 0
        for tid in sorted(list(map(long, taskList))):
            if SysMgr.checkCutCond():
                return False

            idx = str(tid)

            # remove fixed task #
            if SysMgr.fixedProcList:
                SysMgr.fixedProcList.pop(idx, None)
                if not idx in SysMgr.fixedProcList:
                    continue

            # define stat variables #
            if idx in self.procData:
                value = self.procData[idx]
                stat = value["stat"]
            elif idx in self.prevProcData:
                value = self.prevProcData[idx]
                stat = value["stat"]
            else:
                value = dict(self.init_procData)
                stat = ["?"] * 52

            try:
                jsonData[idx] = value
            except:
                pass

            # set comm #
            comm = stat[self.commIdx].strip("()")
            if taskType == "new":
                comm = "[+]%s" % comm
            elif taskType == "die":
                comm = "[-]%s" % comm
            elif taskType == "abnormal":
                comm = "[%s]%s" % (self.abnormalTasks[idx], comm)

            if SysMgr.processEnable:
                pid = stat[self.ppidIdx]
            else:
                pid = value["mainID"]

            try:
                schedPolicy = ConfigMgr.SCHED_POLICY[int(stat[self.policyIdx])]
                if schedPolicy == "C":
                    schedValue = "%3d" % (long(stat[self.prioIdx]) - 20)
                else:
                    schedValue = "%3d" % (abs(long(stat[self.prioIdx]) + 1))
                schedPolicy += str(schedValue)
            except SystemExit:
                sys.exit(0)
            except:
                schedPolicy = "?"

            try:
                runtime = value["runtime"] + SysMgr.uptimeDiff
                lifeTime = UtilMgr.convTime(runtime)
                if len(lifeTime.split(":")) > 3:
                    lifeTime = lifeTime[: lifeTime.rfind(":")]
            except SystemExit:
                sys.exit(0)
            except:
                lifeTime = "?"

            try:
                swapSize = long(value["status"]["VmSwap"].split()[0]) >> 10
            except:
                swapSize = "-"

            if SysMgr.blockEnable:
                try:
                    readSize = value["read"] >> 20
                    writeSize = value["write"] >> 20
                except:
                    readSize = writeSize = 0
            else:
                readSize = "-"
                writeSize = "-"

            # get common dataset for tasks #
            if idx in self.prevProcData:
                dataset = self.prevProcData
            elif idx in self.procData:
                dataset = self.procData
            else:
                dataset = None

            if not SysMgr.processEnable:
                # process name #
                try:
                    pgid = dataset[idx]["mainID"]
                    etc = "%s(%s)" % (dataset[pgid]["comm"], pgid)
                except:
                    etc = "-"
            else:
                # parent name #
                try:
                    pgid = dataset[idx]["stat"][self.ppidIdx]
                    etc = "%s(%s)" % (dataset[pgid]["comm"], pgid)
                except:
                    etc = "-"

            if SysMgr.floatEnable:
                ttime = "%.1f" % value["ttime"]
                btime = "%.1f" % value["btime"]
            else:
                ttime = value["ttime"]
                btime = value["btime"]

            try:
                vss = long(stat[self.vssIdx]) >> 20
            except:
                vss = 0

            try:
                rss = long(stat[self.rssIdx]) >> 8
            except:
                rss = 0

            try:
                shr = long(value["statm"][self.shrIdx]) >> 8

                # except for shred text in RSS #
                if exceptShm:
                    rss -= shr
                    if rss < 0:
                        rss = 0
            except:
                shr = "-"

            try:
                codeSize = (
                    long(stat[self.ecodeIdx]) - long(stat[self.scodeIdx])
                ) >> 20

                # except for shred text in RSS #
                if exceptShm:
                    rss -= codeSize
                    if rss < 0:
                        rss = 0
            except:
                codeSize = 0

            # print thread information #
            SysMgr.addPrint(
                (
                    "{0:>{cl}} ({1:>{pd}}/{2:>{pd}}/{3:>4}/{4:>4})|"
                    "{5:>4}({6:>3}/{7:>3}/{8:>3})|"
                    "{9:>4}({10:>4}/{11:>3}/{12:>3}/{13:>3})|"
                    "{14:>4}({15:>4}/{16:>4}/{17:>5})|"
                    "{18:>5}|{19:>6}|{20:>4}|{21:>9}|{22:>21}|\n"
                ).format(
                    comm[:cl],
                    idx,
                    pid,
                    stat[self.nrthreadIdx],
                    schedPolicy,
                    ttime,
                    value["utime"],
                    value["stime"],
                    "-",
                    vss,
                    rss,
                    codeSize,
                    shr,
                    swapSize,
                    btime,
                    readSize,
                    writeSize,
                    value["majflt"],
                    "-",
                    "-",
                    "-",
                    lifeTime[:9],
                    etc[:21],
                    cl=cl,
                    pd=pd,
                )
            )
            procCnt += 1

        if procCnt > 0:
            SysMgr.addPrint("%s\n" % oneLine)

        return True

    def printReportStat(self, reportStat):
        if not reportStat:
            return
        elif type(reportStat) is dict:
            reportStat = UtilMgr.convDict2Str(reportStat)

        SysMgr.printPipe(reportStat, newline=False, flush=True)

        return

        printBuf = "%s\n" % twoLine

        if "event" in reportStat:
            for event, proc in reportStat["event"].items():
                printBuf += "[event] (%s)\n" % (event)

                for rank, stat in sorted(
                    proc.items(), key=lambda e: long(e[0]), reverse=False
                ):

                    printBuf += "[%s] " % (rank)

                    for item, val in stat.items():
                        printBuf += "(%s: %s) " % (item, val)

                    printBuf += "\n"

                printBuf += "%s\n" % oneLine

            del reportStat["event"]

        for idx, stat in reportStat.items():
            printBuf += "[%s] " % idx

            if type(stat) is dict:
                for item, val in sorted(stat.items(), reverse=False):
                    printBuf += "(%s: %s) " % (item, val)
            else:
                printBuf += "(%s) " % stat

            printBuf += "\n"

        printBuf += "%s\n" % twoLine

        SysMgr.printPipe(printBuf)

    def replyService(self, ip, port):
        if not SysMgr.remoteServObj:
            SysMgr.printErr(
                "failed to use server because it is not initialized"
            )
            return

        # send reply message to server #
        message = "ACK"
        SysMgr.localServObj.sendto(message, ip, port)

    def handleServerResponse(self, packet):
        # return by interrupt from recv #
        if not packet:
            sys.exit(-1)

        if type(packet) is tuple:
            data = packet[0]
            addr = packet[1]
        else:
            return

        # convert data #
        if type(data) is bytes:
            try:
                data = data.decode()
            except:
                pass

        # check data from server #
        if not UtilMgr.isString(data):
            SysMgr.printErr("failed to recognize data from server")
            return

        # get address info from server #
        try:
            ip = addr[0]
            port = long(addr[1])
        except:
            SysMgr.printErr("failed to recognize address from server")

        # wrong request from client #
        if SysMgr.remoteServObj == "NONE" and data in TaskAnalyzer.requestType:
            SysMgr.printErr("failed to handle %s request from client" % data)
            return

        # reply ACK to server #
        try:
            self.replyService(ip, port)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("failed to send ACK to server")

        # REPORT service #
        if data[0] == "{" and data.strip()[-1] == "}":
            # convert report data to dictionary type #
            reportStat = UtilMgr.convStr2Dict(data)

            # check converting result #
            if not reportStat:
                reportStat = data

            # print report data #
            self.printReportStat(reportStat)

        # REFUSE response #
        elif data == "REFUSE":
            SysMgr.printErr(
                "failed to request service because of no support from server"
            )
            sys.exit(-1)

        # DUPLICATED response #
        elif data == "PRINT" or data.startswith("REPORT"):
            SysMgr.printErr(
                "failed to request service "
                "because of same port used between client and sever"
            )
            sys.exit(-1)

        # PRINT service #
        else:
            # realtime mode #
            if not SysMgr.outPath:
                SysMgr.printPipe(data, newline=False, flush=True)
            # buffered mode #
            else:
                SysMgr.addProcBuffer(data)

                # flush buffer #
                SysMgr.clearPrint()

    def requestService(self):
        if not SysMgr.remoteServObj or not SysMgr.localServObj:
            SysMgr.remoteServObj = None
            return

        try:
            # set block socket #
            SysMgr.localServObj.socket.setblocking(1)

            if SysMgr.remoteServObj != "NONE":
                # send request to server #
                SysMgr.localServObj.sendto(
                    SysMgr.remoteServObj.request,
                    SysMgr.remoteServObj.ip,
                    SysMgr.remoteServObj.port,
                )

                # check event #
                if SysMgr.remoteServObj.request.startswith("EVENT_"):
                    SysMgr.printStat(
                        "requested %s to server" % SysMgr.remoteServObj.request
                    )
                    sys.exit(-1)

                SysMgr.printStat(
                    "wait for response of %s registration from server"
                    % SysMgr.remoteServObj.request
                )
            else:
                SysMgr.printStat("wait for input from server")
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "failed to send request '%s'" % SysMgr.remoteServObj.request
            )

    def handleEventCmd(self, cmd, source, user):
        # RESTART #
        if cmd.startswith("RESTART"):
            # print message #
            SysMgr.printInfo(
                "restart %s(%s)..." % (SysMgr.pid, SysMgr.getComm(SysMgr.pid))
            )

            # restart process #
            SysMgr.restart()

        # check PAUSE status #
        if not SysMgr.printEnable and SysMgr.waitEnable:
            return None

        # set event name #
        name = "USER" if user else source

        # SAVE #
        if cmd == "SAVE" or cmd.startswith("SAVE:"):
            ret = self.handleSaveCmd(cmd, name)
            if not ret:
                # disable event handling for child process #
                SysMgr.eventHandleEnable = False
            return ret
        # SAVERAW #
        elif cmd == "SAVERAW" or cmd.startswith("SAVERAW:"):
            ret = self.handleSaveCmd(cmd, name, raw=True)
            if not ret:
                # disable event handling for child process #
                SysMgr.eventHandleEnable = False
            return ret
        # UPDATE #
        elif cmd.startswith("UPDATE:"):
            # get threshold data #
            value = None
            path = UtilMgr.lstrip(cmd, "UPDATE:")

            # load data from the file #
            try:
                with open(path) as fd:
                    body = fd.read()
                    value = UtilMgr.convStr2Dict(body, True)
                    if not value:
                        return None
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenWarn(path, True, True)
                return None

            # update threshold condition #
            try:
                SysMgr.thresholdData.update(value)
            except:
                SysMgr.printErr("failed to update threshold data", True)
                return None

            # print message #
            SysMgr.printInfo(
                (
                    "updated the threshold data from '%s' by '%s' command "
                    "for %s event"
                )
                % (path, cmd, name)
            )

            # print threshold data #
            SysMgr.printWarn(
                UtilMgr.convDict2Str(SysMgr.thresholdData, pretty=True)
            )
        # FILTER #
        elif cmd.startswith("FILTER:"):
            value = UtilMgr.lstrip(cmd, "FILTER:").strip()
            if value:
                value = UtilMgr.cleanItem(value.split("|"))
                SysMgr.filterGroup = value
            else:
                SysMgr.filterGroup = []
                value = "[]"

            # print message #
            SysMgr.printInfo(
                (
                    "updated the task filter to %s by '%s' command "
                    "for %s event"
                )
                % (value, cmd, name)
            )
        # NOTIFY #
        elif cmd.startswith("NOTIFY:"):
            value = UtilMgr.lstrip(cmd, "NOTIFY:").strip()
            if not value:
                SysMgr.printErr("failed to handle notify event '%s'" % cmd)
                return None

            # print message #
            SysMgr.printInfo("be notified of '%s' event" % value)

            # get event info #
            try:
                item, name, target = UtilMgr.cleanItem(value.split("_", 2))
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "failed to get event info from '%s'" % value, True
                )
                return None

            # search event command #
            if not item in SysMgr.thresholdData:
                return None

            # init variables #
            eventList = []
            self.reportData.setdefault("event", {})

            for _name, _values in SysMgr.thresholdData[item].items():
                if name != _name:
                    continue

                # check type #
                if type(_values) is list:
                    pass
                elif type(_values) is dict:
                    _values = [_values]
                else:
                    continue

                for _value in _values:
                    # check skip condition #
                    if not "apply" in _value or _value["apply"] != "true":
                        continue
                    # check log condition #
                    elif "filter" in _value and target == _value["filter"]:
                        # check oneshot flag #
                        (
                            oneshot,
                            goneshot,
                            refresh,
                            lock,
                        ) = TaskAnalyzer.getThresholdAttr(_value)

                        # set threshold #
                        ename = self.setThresholdEvent(
                            _value,
                            "filter",
                            item,
                            None,
                            True,
                            name,
                            None,
                            None,
                            oneshot,
                            goneshot,
                            refresh,
                            lock,
                        )
                        if ename:
                            eventList.append(ename)

            # handle events #
            if eventList:
                self.handleThresholdEvents()
        # ENABLE / DISABLE #
        elif cmd.startswith("ENABLE:") or cmd.startswith("DISABLE:"):
            if cmd.startswith("ENABLE:"):
                act = "enable"
                value = True
                res = UtilMgr.lstrip(cmd, "ENABLE:")
            else:
                act = "disable"
                value = False
                res = UtilMgr.lstrip(cmd, "DISABLE:")

            # update target resource #
            if res == "ALL":
                SysMgr.showAll = value
            elif res == "CPU":
                SysMgr.cpuEnable = value
            elif res == "GPU":
                SysMgr.gpuEnable = value
            elif res == "MEM":
                SysMgr.memEnable = value
            elif res == "IRQ":
                SysMgr.irqEnable = value
            elif res == "DISK":
                SysMgr.diskEnable = value
            elif res == "NETWORK":
                SysMgr.networkEnable = value
            elif res == "BLOCK":
                if SysMgr.checkRootPerm(False):
                    SysMgr.blockEnable = value
            elif res == "PMU":
                if SysMgr.checkRootPerm(False):
                    SysMgr.perfEnable = value

                    # initialize perf events #
                    if value:
                        SysMgr.initSystemPerfEvents()
            elif res == "LOG":
                SysMgr.logEnable = value
            else:
                SysMgr.printWarn("no support '%s' resource" % res, True)
                return None

            # print message #
            SysMgr.printInfo(
                (
                    "%s the monitoring resource '%s' by '%s' command "
                    "for %s event"
                )
                % (act, res, cmd, name)
            )
        # CLEAR #
        elif cmd.startswith("CLEAR"):
            # clear buffer #
            SysMgr.clearProcBuffer()

            # print message #
            SysMgr.printInfo(
                (
                    "cleared the monitoring results by '%s' command "
                    "for %s event"
                )
                % (cmd, name)
            )
        # BUFFER #
        elif cmd.startswith("BUFFER:"):
            # get buffer size #
            size = UtilMgr.lstrip(cmd, "BUFFER:")

            # apply new buffer size #
            sizeOrig = size
            size = UtilMgr.convUnit2Size(size)
            if size > 0:
                SysMgr.bufferSize = size
            else:
                SysMgr.printErr("failed to apply buffer size to %s" % sizeOrig)
                return None

            # print message #
            SysMgr.printInfo(
                (
                    "changed the size of the monitoring buffer to %s by "
                    "'%s' command for %s event"
                )
                % (UtilMgr.convSize2Unit(size), cmd, name)
            )
        # INTERVAL #
        elif cmd.startswith("INTERVAL:"):
            # get interval #
            interval = UtilMgr.lstrip(cmd, "INTERVAL:")
            if not interval:
                interval = 1
            elif interval.startswith("_"):
                interval = interval[1:]

            # apply new interval #
            intervalOrig = interval
            interval = UtilMgr.convUnit2Time(interval)
            if interval > 0:
                SysMgr.intervalEnable = interval
            else:
                SysMgr.printErr(
                    "failed to apply interval to %s" % intervalOrig
                )
                return None

            # print message #
            SysMgr.printInfo(
                (
                    "changed the monitoring interval to %s sec by '%s'"
                    " command for %s event"
                )
                % (UtilMgr.convNum(interval), cmd, name)
            )
        # RELOAD #
        elif cmd.startswith("RELOAD"):
            # print message #
            SysMgr.printInfo("start reloading threshold config")

            # get file path #
            path = UtilMgr.lstrip(cmd, "RELOAD")
            if not path:
                path = SysMgr.confFileName
            elif path.startswith(":"):
                path = path[1:]
            else:
                SysMgr.printErr("wrong command format for 'RELOAD'")
                return None

            # convert path #
            path = os.path.realpath(path)

            # terminate event handling tasks #
            if SysMgr.eventCommandList:
                SysMgr.terminateTasks(
                    SysMgr.eventCommandList.values(), signal.SIGINT
                )
                SysMgr.eventCommandList = {}

            # reset threshold data #
            ConfigMgr.confData = {}
            SysMgr.thresholdEventHistory = {}
            SysMgr.thresholdEventList = {}

            # load and check config file #
            if not SysMgr.loadConfig(path):
                SysMgr.printErr("wrong path '%s' for config" % path)
                return None

            # reload threshold config #
            SysMgr.applyThreshold()
        # PAUSE #
        elif cmd.startswith("PAUSE"):
            # clear buffer #
            SysMgr.clearPrint()
            SysMgr.clearProcBuffer()
            SysMgr.shrinkHeap()

            # print message #
            SysMgr.printInfo(
                (
                    "cleared the monitoring results and paused all activities "
                    "by '%s' command for %s event"
                )
                % (cmd, name)
            )

            # disable print #
            SysMgr.printEnable = False
            SysMgr.logEnable = False

            # wait for RESTART event #
            SysMgr.waitEnable = True
            while 1:
                time.sleep(1)
                self.checkServer()
        # STOP #
        elif cmd.startswith("STOP"):
            # print message #
            SysMgr.printInfo("stop the threshold monitoring")

            # terminate event handling tasks #
            if SysMgr.eventCommandList:
                SysMgr.terminateTasks(
                    SysMgr.eventCommandList.values(), signal.SIGINT
                )
                SysMgr.eventCommandList = {}

            # clear threshold data #
            SysMgr.thresholdData = {}
            SysMgr.thresholdEventList = {}
            SysMgr.thresholdEventHistory = {}
        else:
            SysMgr.printWarn("no support '%s' command" % cmd, True)
            return None

        return True

    def checkServer(self):
        if not SysMgr.localServObj:
            return

        while 1:
            # get message from clients #
            ret = SysMgr.localServObj.recvfrom(verb=False)

            # verify request type #
            if ret is False:
                SysMgr.localServObj = None
                return
            elif not ret:
                return

            # check type #
            if type(ret) is not tuple:
                continue

            try:
                message = ret[0].decode()
            except:
                message = ret[0]

            # check message type #
            if not UtilMgr.isString(message):
                return

            try:
                ip = ret[1][0]
                port = ret[1][1]
            except:
                SysMgr.printWarn(
                    "failed to get address of client from message"
                )
                continue

            # create network object for send event info #
            if (
                SysMgr.localServObj.ip != ip
                or SysMgr.localServObj.port != port
            ):
                networkObject = NetworkMgr("client", ip, port)
                if not networkObject.ip:
                    continue

                # save current time in new object #
                networkObject.time = time.time()
            else:
                networkObject = None

            if message.startswith("EVENT_"):
                # get event name #
                event = message.split("_", 1)[1]

                # get runtime #
                pos = event.rfind("@")
                if pos >= 0:
                    rtime = event[pos + 1 :]
                    event = event[:pos]
                else:
                    rtime = SysMgr.uptime

                # append event to list #
                TaskAnalyzer.procEventData.append(
                    [SysMgr.uptime, event, rtime]
                )

                SysMgr.printInfo(
                    "added event '%s' from %s:%d" % (event, ip, port)
                )

                # handle command #
                if event.startswith("CMD_"):
                    if not SysMgr.eventHandleEnable:
                        SysMgr.printWarn("ignored '%s' event" % event)
                    else:
                        self.handleEventCmd(
                            UtilMgr.lstrip(event, "CMD_"),
                            "%s:%s" % (ip, port),
                            True,
                        )
                else:
                    # send event message #
                    if networkObject:
                        networkObject.send(message)
                        del networkObject

            elif message == "LOG":
                pass

            elif not networkObject:
                pass

            elif message == "PRINT":
                index = ip + ":" + str(port)
                if not index in SysMgr.addrListForPrint:
                    SysMgr.addrListForPrint[index] = networkObject
                    SysMgr.printInfo(
                        "registered %s:%d as remote address for PRINT"
                        % (ip, port)
                    )
                else:
                    SysMgr.printWarn(
                        "duplicated %s:%d as remote address" % (ip, port)
                    )

            elif message == "REPORT" or message == "THRESHOLD":
                if not SysMgr.reportEnable:
                    SysMgr.printWarn(
                        "ignored %s request from %s:%d because no service"
                        % (message, ip, port)
                    )
                    networkObject.send("REFUSE")
                    del networkObject
                    continue

                networkObject.request = message

                index = ip + ":" + str(port)
                if not index in SysMgr.addrListForReport:
                    SysMgr.addrListForReport[index] = networkObject
                    SysMgr.printInfo(
                        "registered %s:%d as remote address for REPORT"
                        % (ip, port)
                    )
                else:
                    SysMgr.addrListForReport[index] = networkObject
                    SysMgr.printInfo(
                        "updated %s:%d as remote address for REPORT"
                        % (ip, port)
                    )

            elif message == "ACK":
                index = ip + ":" + str(port)
                if index in SysMgr.addrListForPrint:
                    SysMgr.addrListForPrint[index].ignore -= 1
                    SysMgr.addrListForPrint[index].status = "READY"
                elif index in SysMgr.addrListForReport:
                    SysMgr.addrListForReport[index].ignore -= 1
                    SysMgr.addrListForReport[index].status = "READY"
                else:
                    SysMgr.printWarn(
                        "failed to find %s:%d as remote address" % (ip, port)
                    )

            # wrong request or just data from server #
            else:
                SysMgr.printErr("failed to recognize the request from client")

    def handleSaveCmd(self, cmd, event, raw=False):
        # replace event name #
        origCmd = cmd
        parts = cmd.split("@", 1)
        cmd = parts[0]
        if len(parts) > 1:
            event = "%s_%s" % (event, parts[1])

        # set target command #
        if raw:
            target = "SAVERAW"
        else:
            target = "SAVE"

        # verify save command #
        if cmd.split(":")[0] != target:
            SysMgr.printWarn("no support '%s' command" % origCmd, True)
            return -1

        # print message #
        SysMgr.printInfo(
            (
                "start saving the monitoring results by '%s' command "
                "for '%s' event"
            )
            % (origCmd, event)
        )

        # check out path #
        if not SysMgr.outPath:
            SysMgr.printErr("no output path for '%s' command" % origCmd)
            return -1

        # increase report number #
        SysMgr.nrReport += 1

        if SysMgr.isLinux:
            # create a new process #
            pid = SysMgr.createProcess()
            if pid > 0:
                return pid

            # change priority #
            SysMgr.setLowPriority(True)

            # register SIGINT handler #
            signal.signal(signal.SIGINT, SysMgr.stopHandler)

            # disable report #
            SysMgr.reportEnable = False

            # disable interval summary #
            if raw:
                SysMgr.addEnvironVar("NOINTSUMMARY")
        else:
            SysMgr.closePrintFd()

        # get time #
        timeinfo = UtilMgr.getUTCTime()
        if not timeinfo:
            timeinfo = long(SysMgr.uptime)

        # get output dir #
        if SysMgr.outPath == SysMgr.nullPath:
            targetDir = SysMgr.tmpPath
        elif os.path.isdir(SysMgr.outPath):
            targetDir = SysMgr.outPath
        else:
            targetDir = os.path.dirname(SysMgr.outPath)

        # change output path #
        SysMgr.outPath = "%s/guider_%08d_%08d_%s_%s_%s.out" % (
            targetDir,
            SysMgr.nrRun,
            SysMgr.nrReport,
            event,
            cmd,
            timeinfo,
        )

        # free up report directory #
        SysMgr.freeReportDir()

        # save output #
        if SysMgr.isLinux:
            # convert timer #
            try:
                timeunit = cmd.strip("%s:" % target)
                if not timeunit:
                    raise Exception("no time")
                sec = UtilMgr.convUnit2Time(timeunit)
            except SystemExit:
                sys.exit(0)
            except:
                sec = timeunit

            # immediate #
            if sec == timeunit:
                os.kill(SysMgr.pid, signal.SIGINT)
            # later #
            else:
                # close all shared file descriptors #
                self.reclaimFds(sys.maxsize)

                # set timer #
                signal.signal(signal.SIGALRM, SysMgr.stopHandler)
                signal.alarm(sec)

            return 0
        else:
            # immediate #
            try:
                SysMgr.termFlag = False
                SysMgr.stopHandler()
            except:
                pass
            finally:
                SysMgr.termFlag = True

            # recover output path #
            if SysMgr.isWindows:
                SysMgr.outPath = "NUL"
            else:
                SysMgr.outPath = SysMgr.nullPath

            return 0

    def executeEventCommand(self, eventList):
        for event in eventList:
            value = self.reportData["event"][event]
            if not "command" in value or type(value["command"]) is not list:
                continue

            # skip events that already exist #
            if event in SysMgr.eventCommandList:
                continue
            elif not value["run"]:
                SysMgr.printWarn(
                    (
                        "skipped event handling for '%s' "
                        "because of oneshot flag"
                    )
                    % event,
                    True,
                )
                continue

            for cmd in value["command"]:
                # convert command to full command by name #
                if (
                    "COMMAND" in SysMgr.thresholdData
                    and cmd in SysMgr.thresholdData["COMMAND"]
                ):
                    cmd = SysMgr.thresholdData["COMMAND"][cmd]
                # convert command to full command by name #
                elif (
                    "COMMAND" in SysMgr.prevThresholdData
                    and cmd in SysMgr.prevThresholdData["COMMAND"]
                ):
                    cmd = SysMgr.prevThresholdData["COMMAND"][cmd]
                # handle embedded commands #
                else:
                    ret = self.handleEventCmd(cmd, event, False)
                    # general commands #
                    if ret is True:
                        continue
                    # custom commands #
                    elif ret is None:
                        pass
                    # child task #
                    elif ret == 0:
                        return
                    # parent task #
                    else:
                        try:
                            # register the event handling process #
                            if ret > 0:
                                SysMgr.eventCommandList.setdefault(event, ret)

                            continue
                        except SystemExit:
                            sys.exit(0)
                        except:
                            pass

                # convert EVTPID #
                if "task" in value:
                    pid = list(value["task"])[0]
                    cmd = cmd.replace("EVTPID", pid)

                # convert variables #
                cmd = cmd.replace("SELFPID", str(SysMgr.pid))
                cmd = cmd.replace("EVTNAME", event)
                cmd = cmd.replace("EVTTIME", str(UtilMgr.getUTCTime()))
                cmd = cmd.replace("EVTUPTIME", str(long(SysMgr.uptime)))
                cmd = cmd.replace("NUMRUN", str(SysMgr.nrRun))
                cmd = cmd.replace("NUMREP", str(SysMgr.nrReport))

                SysMgr.printInfo('executed "%s" by %s event' % (cmd, event))

                # launch Guider #
                if cmd.startswith("GUIDER "):
                    # build command list #
                    cmdList = UtilMgr.parseCommand(cmd.lstrip("GUIDER "))

                    # launch command #
                    try:
                        ret = SysMgr.launchGuider(
                            cmdList,
                            pipe=False,
                            stderr=True,
                            stream=False,
                            logo=False,
                            log=True,
                        )
                    except SystemExit:
                        sys.exit(0)
                    except:
                        ret = False
                        SysMgr.printErr(
                            "failed to launch %s" % __module__, reason=True
                        )
                # launch command #
                else:
                    ret = SysMgr.createProcess(cmd)

                # register the event handling process #
                if ret:
                    SysMgr.eventCommandList.setdefault(event, ret)

    def handleThresholdEvents(self):
        # check exit condition #
        if not SysMgr.thresholdEnable:
            return
        elif not SysMgr.thresholdEventList and not self.reportData["event"]:
            return

        # print events #
        prevList = list(SysMgr.thresholdEventList)
        nowList = list(self.reportData["event"])
        timestr = "at %s (%s)" % (SysMgr.uptime, UtilMgr.getUTCTime())

        # print finished events #
        endList = set(prevList) - set(nowList)
        if endList:
            SysMgr.printInfo(
                "finished threshold events [ %s ] %s"
                % (", ".join(endList), timestr)
            )

        # print new events #
        newList = set(nowList) - set(prevList)
        if newList:
            SysMgr.printInfo(
                "started threshold events [ %s ] %s"
                % (", ".join(newList), timestr)
            )

            # save event timestamp #
            SysMgr.broadcastEvent(list(newList), [SysMgr.pid])

            # execute commands #
            self.executeEventCommand(newList)

        # print cont events #
        contList = set(nowList) & set(prevList)
        if contList:
            SysMgr.printWarn(
                "continued threshold events [ %s ] %s"
                % (", ".join(contList), timestr)
            )

        # update event list #
        SysMgr.thresholdEventList = self.reportData["event"]

        if not self.reportData["event"]:
            return

        # print event description #
        estr = UtilMgr.convDict2Str(self.reportData["event"], ignore=True)
        SysMgr.printWarn("%s" % estr)

    def checkResourceThreshold(self):
        if not SysMgr.thresholdData:
            return

        def _getIntval(item):
            if item in self.intervalData:
                return self.intervalData[item]
            else:
                return None

        # init event item #
        self.reportData["event"] = {}

        # check image created #
        if SysMgr.imagePath:
            self.reportData["event"]["IMAGE_CREATED"] = SysMgr.imagePath
            SysMgr.imagePath = None

        # update refresh items #
        if SysMgr.thresholdRefreshList:
            newList = []
            for item in SysMgr.thresholdRefreshList:
                tick, ename, data = item

                tick -= 1
                # keep #
                if tick > 0:
                    newList.append([tick, ename, data])
                # expired #
                elif "apply" in data:
                    data["apply"] = "true"

                    # remove event form history #
                    SysMgr.thresholdEventHistory.pop(ename, None)

            SysMgr.thresholdRefreshList = newList

        # check CPU #
        try:
            if not "cpu" in SysMgr.thresholdTarget:
                raise Exception()

            for item in ["total", "user", "kernel", "irq", "iowait"]:
                intval = _getIntval(item)
                self.checkThreshold("cpu", item, "CPU", "big", intval=intval)
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # check GPU #
        try:
            # check activation #
            if not "gpu" in SysMgr.thresholdTarget:
                raise Exception()

            # each devices #
            dinfo = {}
            for dev, vals in self.reportData["gpu"].items():
                target = vals
                dinfo.update({"dev": dev})

                try:
                    # all devices #
                    self.checkThreshold(
                        "gpu",
                        "total",
                        "GPU",
                        "big",
                        target,
                        "DEVICE",
                        addval=dinfo,
                    )

                    # a specific device #
                    self.checkThreshold(
                        "gpu", "total", "GPU", "big", target, dev, addval=dinfo
                    )
                except SystemExit:
                    sys.exit(0)
                except:
                    continue
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # check memory #
        try:
            if not "mem" in SysMgr.thresholdTarget:
                raise Exception()

            # check available memory #
            items = ["available", "free"]
            for item in items:
                intval = _getIntval(item)
                self.checkThreshold("mem", item, "MEM", "less", intval=intval)

            # check memory stats #
            items = ["anon", "file", "slab", "pgRclmBg", "pgRclmFg"]
            for item in items:
                intval = _getIntval(item)
                self.checkThreshold("mem", item, "MEM", "big", intval=intval)
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # check GPU memory #
        try:
            if not "gpumem" in SysMgr.thresholdTarget:
                raise Exception()

            self.checkThreshold("gpumem", "total", "GPUMEM", "big")
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # check swap #
        try:
            if not "swap" in SysMgr.thresholdTarget:
                raise Exception()

            intval = _getIntval("swap")
            self.checkThreshold(
                "swap", "usagePer", "SWAP", "big", intval=intval
            )
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # check iowait #
        try:
            if not "block" in SysMgr.thresholdTarget:
                raise Exception()

            self.checkThreshold("block", "ioWait", "IO", "big")
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # check storage #
        try:
            # check activation #
            if not "storage" in SysMgr.thresholdTarget:
                raise Exception()

            # total #
            vals = self.reportData["storage"]["total"]
            target = self.reportData["storage"]["total"]["usagePer"]
            self.checkThreshold(
                "storage", "usagePer", "STORAGE", "big", target, addval=vals
            )

            # each devices #
            for dev, vals in self.reportData["storage"].items():
                if dev == "total":
                    continue

                # usage percent #
                target = vals["usagePer"]
                vals.update({"dev": dev})

                intval = _getIntval(dev)

                try:
                    # all devices #
                    self.checkThreshold(
                        "storage",
                        "usagePer",
                        "STORAGE",
                        "big",
                        target,
                        "DEVICE",
                        intval=intval,
                        addval=vals,
                    )

                    # a specific device #
                    self.checkThreshold(
                        "storage",
                        "usagePer",
                        "STORAGE",
                        "big",
                        target,
                        dev,
                        intval=intval,
                        addval=vals,
                    )
                except SystemExit:
                    sys.exit(0)
                except:
                    continue
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # check network #
        try:
            # check activation #
            if not "net" in SysMgr.thresholdTarget:
                raise Exception()

            # total inbound #
            for direct, name in [["inbound", "NETIN"], ["outbound", "NETOUT"]]:
                target = self.reportData["net"][direct]
                intval = _getIntval(direct)
                self.checkThreshold(
                    "net", direct, name, "big", target, intval=intval
                )

            # each devices #
            dinfo = {}
            for dev, vals in self.reportData["net"].items():
                if dev == "inbound" or dev == "outbound":
                    continue
                elif type(vals) is not dict:
                    continue

                recv = vals["recv"]["bytes"]
                trans = vals["trans"]["bytes"]
                dinfo.update({"dev": dev})

                # check devices #
                for item in ["DEVICE", dev]:
                    try:
                        # get recv interval #
                        name = dev + ":recv"
                        intval = _getIntval(name)

                        # recv #
                        self.checkThreshold(
                            "net",
                            "recv",
                            "NETWORK",
                            "big",
                            recv,
                            item,
                            intval=intval,
                            addval=dinfo,
                        )

                        # get trans interval #
                        name = dev + ":trans"
                        intval = _getIntval(name)

                        # trans #
                        self.checkThreshold(
                            "net",
                            "trans",
                            "NETWORK",
                            "big",
                            trans,
                            item,
                            intval=intval,
                            addval=dinfo,
                        )
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # check loadavg #
        try:
            if not "load" in SysMgr.thresholdTarget:
                raise Exception()

            intval = _getIntval("load")

            for attr in ["load1m", "load5m", "load15m"]:
                self.checkThreshold(
                    "load",
                    attr,
                    "LOAD",
                    "big",
                    self.reportData["system"][attr],
                    intval=intval,
                )
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # check sched #
        try:
            # check activation #
            if not "task" in SysMgr.thresholdTarget:
                raise Exception()

            # context switch #
            target = self.reportData["task"]["nrCtx"]
            self.checkThreshold("task", "nrCtx", "CTXSWC", "big", target)

            # new status #
            if self.reportData["task"]["new"]:
                newList = list(self.reportData["task"]["new"])
                target = "_".join(newList)
                self.checkThreshold("task", "new", "NEW", None, target)

            # die status #
            if self.reportData["task"]["die"]:
                dieList = list(self.reportData["task"]["die"])
                target = "_".join(dieList)
                self.checkThreshold("task", "die", "DIE", None, target)

            # abnormal status #
            if self.reportData["task"]["abnormal"]:
                abnormalList = list(self.reportData["task"]["abnormal"])
                target = "_".join(abnormalList)
                self.checkThreshold(
                    "task", "abnormal", "ABNORMAL", None, target
                )
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # check fd #
        try:
            if not "fd" in SysMgr.thresholdTarget:
                raise Exception()

            self.checkThreshold("fd", "curFd", "FD", "big")
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # check fd #
        try:
            if not "sock" in SysMgr.thresholdTarget:
                raise Exception()

            items = ["nrUDPSock", "nrTCPSock", "nrTCPConn", "nrUDSSock"]
            for item in items:
                intval = _getIntval(item)
                self.checkThreshold("sock", item, "SOCK", "big", intval=intval)
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # check file #
        try:
            self.checkFileThreshold()
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # check task #
        try:
            self.checkTaskThreshold()
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn("failed to check task thresholds", reason=True)

        # handle events #
        self.handleThresholdEvents()

        # update event status #
        self.updateEventStatus()

    def updateEventStatus(self):
        # check event handling tasks #
        runList = SysMgr.getChildList()
        for event, pid in UtilMgr.deepcopy(SysMgr.eventCommandList).items():
            if not pid in runList:
                SysMgr.eventCommandList.pop(event, None)

        # update event lock #
        for event in UtilMgr.deepcopy(SysMgr.eventLockList):
            if not event in SysMgr.eventCommandList:
                SysMgr.eventLockList.pop(event, None)
                SysMgr.printWarn(
                    (
                        "released the lock of the threshold handling "
                        "caused by '%s' event"
                    )
                    % event,
                    True,
                )

    def setThresholdEvent(
        self,
        comval,
        item,
        event,
        comp="big",
        target=None,
        attr="SYSTEM",
        intval=None,
        addval=None,
        oneshot=False,
        goneshot=False,
        refresh=0,
        lock=False,
    ):

        # init value #
        value = None

        # check return condition #
        if not item in comval:
            return

        # convert threshold value (%) #
        thresholdVal = comval[item]
        try:
            if event in ("MEM", "GPUMEM"):
                if thresholdVal.endswith("%"):
                    per = long(thresholdVal.rstrip("%")) / 100.0
                    thresholdVal = long(SysMgr.memTotal * per)
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # check threshold #
        if not comp:
            value = target
        elif intval and "interval" in comval:
            if comval["interval"] > len(intval):
                return

            # check items in intervals #
            intval = intval[-comval["interval"] :]
            average = sum(intval) / len(intval)
            threshold = UtilMgr.convUnit2Size(thresholdVal)
            if (comp == "big" and threshold <= average) or (
                comp == "less" and threshold >= average
            ):
                value = average
        else:
            threshold = UtilMgr.convUnit2Size(thresholdVal)
            if (comp == "big" and threshold <= target) or (
                comp == "less" and threshold >= target
            ):
                value = target

        # check value #
        if value is None:
            return

        # check time conditions #
        for key in ("after", "before", "rafter", "rbefore"):
            try:
                # check field #
                if not key in comval:
                    continue

                # get threshold value #
                threshold = UtilMgr.convUnit2Time(comval[key])

                # check skip conditions #
                if key == "before":
                    if SysMgr.uptime > threshold:
                        return
                elif key == "after":
                    if SysMgr.uptime < threshold:
                        return
                elif key == "rbefore":
                    runtime = SysMgr.getRuntime(sec=True)
                    if runtime > threshold:
                        return
                elif key == "rafter":
                    runtime = SysMgr.getRuntime(sec=True)
                    if runtime < threshold:
                        return
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn(
                    "failed to check '%s' condition" % key, True, True
                )

        # set event name #
        ename = "%s_%s_%s" % (event, attr, item)

        # check event lock #
        if SysMgr.eventLockList:
            SysMgr.printWarn(
                "ignored '%s' event because of the lock of [%s]"
                % (ename, ", ".join(SysMgr.eventLockList.keys()))
            )
            return

        # add task info #
        if addval:
            comval.update(addval)

        # add event info #
        if "task" in comval:
            addinfo = ""
            for pid, data in comval["task"].items():
                addinfo += "%s_%s" % (data["comm"].lstrip("*"), pid)
            ename = "%s_%s" % (ename, addinfo.lstrip("_"))
        elif "dev" in comval:
            ename = "%s_%s" % (ename, comval["dev"])

        # add rest info #
        if item in comval:
            ename = "%s_%s" % (ename, thresholdVal)

        # replace '/' with '_' for path by event name #
        ename = ename.replace("/", "_")

        # handle goneshot flag #
        if goneshot:
            if SysMgr.thresholdData:
                SysMgr.prevThresholdData = SysMgr.thresholdData
            SysMgr.thresholdData = {}
            SysMgr.printWarn(
                (
                    "disabled the threshold monitoring "
                    "because of 'goneshot' event"
                ),
                True,
            )
        # update apply flag for oneshot #
        elif oneshot:
            # define function for checking resources #
            def _checkResource(item):
                if (
                    type(item) is dict
                    and "apply" in item
                    and item["apply"] == "true"
                ):
                    return True

                # check type #
                if type(item) is list:
                    for value in item:
                        if _checkResource(value):
                            return True
                elif type(item) is dict:
                    for key, value in item.items():
                        if _checkResource(value):
                            return True

                return False

            # update apply flag #
            if "apply" in comval:
                comval["apply"] = "false"

            # update threshold items #
            if refresh:
                SysMgr.thresholdRefreshList.append([refresh, ename, comval])
            elif not _checkResource(SysMgr.thresholdData):
                if SysMgr.thresholdData:
                    SysMgr.prevThresholdData = SysMgr.thresholdData
                SysMgr.thresholdData = {}
                SysMgr.printWarn(
                    (
                        "disabled the threshold monitoring "
                        "because of no active threshold"
                    ),
                    True,
                )

        # set lock for event #
        if lock:
            SysMgr.eventLockList.setdefault(ename, None)
            SysMgr.printWarn(
                "locked the threshold handling because of '%s' event" % ename,
                True,
            )

        # handle oneshot command #
        if goneshot:
            run = True
        elif oneshot and ename in SysMgr.thresholdEventHistory:
            run = False
        else:
            run = True

        # set value for event #
        self.reportData["event"][ename] = dict(comval)
        self.reportData["event"][ename]["run"] = run
        SysMgr.thresholdEventHistory.setdefault(ename, None)

        return ename

    @staticmethod
    def getThresholdAttr(items):
        if "oneshot" in items and items["oneshot"] == "true":
            oneshot = True
        else:
            oneshot = False

        if "goneshot" in items and items["goneshot"] == "true":
            goneshot = True
        else:
            goneshot = False

        if "refresh" in items:
            refresh = items["refresh"]
        else:
            refresh = 0

        if "lock" in items and items["lock"] == "true":
            lock = items["lock"]
        else:
            lock = False

        return oneshot, goneshot, refresh, lock

    def checkFileThreshold(self):
        # check threshold #
        if not SysMgr.thresholdData:
            return False

        # define shortcut #
        td = SysMgr.thresholdData

        # check attribute #
        if not "file" in td:
            return False

        for path, value in td["file"].items():
            # check apply #
            if not "apply" in value or value["apply"] != "true":
                continue

            # exist / none #
            for attr in ["exist", "none"]:
                if not attr in value or value[attr] != "true":
                    continue

                if UtilMgr.convPath(path):
                    (
                        oneshot,
                        goneshot,
                        refresh,
                        lock,
                    ) = TaskAnalyzer.getThresholdAttr(value)

                    # set threshold #
                    self.setThresholdEvent(
                        value,
                        attr,
                        "FILE",
                        None,
                        target=True,
                        attr=path,
                        oneshot=oneshot,
                        goneshot=goneshot,
                        refresh=refresh,
                        lock=lock,
                    )

            # check bigger / lesser #
            if "big" in value:
                comp = "big"
            elif "less" in value:
                comp = "less"
            else:
                comp = None

            if comp:
                files = UtilMgr.convPath(path)
                if files:
                    # convert size #
                    try:
                        value[comp] = UtilMgr.convUnit2Size(value[comp])
                    except SystemExit:
                        sys.exit(0)
                    except:
                        sys.exit(0)

                    size = 0
                    for item in files:
                        size += UtilMgr.getFileSize(item, False)

                    (
                        oneshot,
                        goneshot,
                        refresh,
                        lock,
                    ) = TaskAnalyzer.getThresholdAttr(value)

                    check = "big" if comp == "big" else "less"

                    # set threshold #
                    self.setThresholdEvent(
                        value,
                        comp,
                        "FILE",
                        check,
                        target=size,
                        attr=path,
                        oneshot=oneshot,
                        goneshot=goneshot,
                        refresh=refresh,
                        lock=lock,
                    )

            # TODO: handle dir #

    def checkThreshold(
        self,
        resource,
        item,
        event,
        comp=None,
        target=None,
        attr="SYSTEM",
        intval=None,
        addval=None,
    ):

        # check threshold #
        if not SysMgr.thresholdData:
            return False

        # define shortcut #
        td = SysMgr.thresholdData

        # check attribute #
        if not resource in td or not attr in td[resource]:
            return False

        # get threshold attributes #
        comval = td[resource][attr]

        # get previous usages #
        if intval:
            pass
        elif resource in self.intervalData:
            intval = self.intervalData[resource]
        else:
            intval = []

        # get current usage #
        if target is None:
            if (
                resource == "gpumem"
                and item == "total"
                and not "total" in self.reportData[resource]
            ):
                try:
                    target = self.reportData[resource]["0"]["size"] >> 20
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printWarn(
                        "failed to check '%s' of '%s'" % (item, resource),
                        True,
                        True,
                    )
                    return False
            else:
                target = self.reportData[resource][item]

        # check conditions and trigger events #
        if type(comval) is dict:
            # check apply attribute #
            if "apply" in comval and comval["apply"] == "false":
                return False
            # check except attribute #
            elif "except" in comval:
                if attr == "TASK":
                    pid = next(iter(addval["task"]))
                    comm = addval["task"][pid]["comm"].lstrip("*")

                    if type(comval["except"]) is list:
                        elist = comval["except"]
                    else:
                        elist = [comval["except"]]

                    if UtilMgr.isValidStr(comm, elist):
                        return False
                elif attr == "DEVICE":
                    if type(comval["except"]) is list:
                        elist = comval["except"]
                    else:
                        elist = [comval["except"]]

                    if UtilMgr.isValidStr(addval["dev"], elist):
                        return False

            # check oneshot flag #
            oneshot, goneshot, refresh, lock = TaskAnalyzer.getThresholdAttr(
                comval
            )

            # set threshold #
            self.setThresholdEvent(
                comval,
                item,
                event,
                comp,
                target,
                attr,
                intval,
                addval,
                oneshot,
                goneshot,
                refresh,
                lock,
            )
        elif type(comval) is list:
            for comitem in comval:
                # check apply attribute #
                if "apply" in comitem and comitem["apply"] == "false":
                    continue
                # check except attribute #
                elif "except" in comitem:
                    if attr == "TASK":
                        pid = next(iter(addval["task"]))
                        comm = addval["task"][pid]["comm"].lstrip("*")

                        if type(comitem["except"]) is list:
                            elist = comitem["except"]
                        else:
                            elist = [comitem["except"]]

                        if UtilMgr.isValidStr(comm, elist):
                            continue
                    elif attr == "DEVICE":
                        if type(comitem["except"]) is list:
                            elist = comitem["except"]
                        else:
                            elist = [comitem["except"]]

                        if UtilMgr.isValidStr(addval["dev"], elist):
                            return False

                # check oneshot flag #
                (
                    oneshot,
                    goneshot,
                    refresh,
                    lock,
                ) = TaskAnalyzer.getThresholdAttr(comitem)

                # set threshold #
                self.setThresholdEvent(
                    comitem,
                    item,
                    event,
                    comp,
                    target,
                    attr,
                    intval,
                    addval,
                    oneshot,
                    goneshot,
                    refresh,
                    lock,
                )

    def checkTaskThreshold(self):
        if not SysMgr.thresholdData:
            return
        elif not SysMgr.taskThresholdEnable:
            return

        # init variables #
        td = SysMgr.thresholdData
        tt = SysMgr.thresholdTarget

        # mapping table between thresholds and stats #
        maps = []
        # CPU #
        if "cpu" in tt and tt["cpu"]:
            maps += [["cpu", "total", "ttime", "cpuInt", "CPU", "big"]]
        # mem #
        if "mem" in tt and tt["mem"]:
            maps += [["mem", "rss", "rss", "rssInt", "MEM", "big"]]
        # gpumem #
        if "gpumem" in tt and tt["gpumem"]:
            maps += [["gpumem", "size", None, None, "GPUMEM", "big"]]
        # fd #
        if "fd" in tt and tt["fd"]:
            maps += [["fd", "fdSize", "fdSize", None, "FD", "big"]]
        # swap #
        if "swap" in tt and tt["swap"]:
            maps += [["swap", "swap", "swap", "swapInt", "SWAP", "big"]]
        # block #
        if "block" in tt and tt["block"]:
            maps += [
                ["block", "read", "read", "blockInt", "BLOCK", "big"],
                ["block", "write", "write", "blockInt", "BLOCK", "big"],
            ]

        # check exit condition #
        if not maps:
            return

        # set task type #
        if SysMgr.processEnable:
            mode = "process"
        else:
            mode = "thread"

        # traverse all tasks #
        for pid, data in self.procData.items():
            comm = data["comm"].lstrip("*")

            # skip Guider #
            if comm == __module__:
                continue

            for item in maps:
                try:
                    res, cattr, pattr, intname, event, comp = item

                    # check skip condition #
                    if not res in td:
                        continue
                    elif pattr and not pattr in data:
                        continue
                    elif res in ("mem", "gpumem", "fd"):
                        if self.isKernelThread(pid):
                            continue

                    # get stat #
                    if res == "gpumem":
                        if not pid in self.gpuMemData:
                            continue
                        else:
                            value = self.gpuMemData[pid]["size"] >> 20
                    else:
                        value = data[pattr]

                    # get interval #
                    if intname in data:
                        intval = data[intname]
                    else:
                        intval = None

                    # check interval #
                    if not value:
                        if not intval:
                            continue
                        elif set(intval) == set([0]):
                            continue

                    # add task info #
                    if False and pid in SysMgr.jsonData[mode]:
                        append = {"task": {pid: SysMgr.jsonData[mode][pid]}}
                    else:
                        append = {"task": {pid: data}}

                    # get task condition list #
                    if "TASK" in td[res]:
                        taskCondList = td[res]["TASK"]
                        if type(taskCondList) is dict:
                            taskCondList = [taskCondList]
                    else:
                        taskCondList = []

                    # check apply flags updated by oneshot flag #
                    for taskItem in taskCondList:
                        try:
                            enabled = False
                            if taskItem["apply"] == "true":
                                enabled = True
                        except SystemExit:
                            sys.exit(0)
                        except:
                            pass

                        # check a task #
                        try:
                            if enabled:
                                self.checkThreshold(
                                    res,
                                    cattr,
                                    event,
                                    comp,
                                    value,
                                    "TASK",
                                    intval,
                                    append,
                                )
                        except SystemExit:
                            sys.exit(0)
                        except:
                            SysMgr.printWarn(
                                "failed to check task thresholds", reason=True
                            )

                    # check a specific task #
                    if comm in td[res]:
                        self.checkThreshold(
                            res,
                            cattr,
                            event,
                            comp,
                            value,
                            comm,
                            intval,
                            append,
                        )
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printWarn(
                        "failed to check task thresholds", reason=True
                    )

    def reportSystemStat(self):
        # initialize report event list #
        """
        CPU
        MEM
        SWAP
        IO
        STORAGE
        NETIN
        NETOUT
        """

        convTime = UtilMgr.convTime

        # add per-process stats #
        if SysMgr.rankProcEnable:

            def _setDefaultInfo(data, pid, comm, runtime=None):
                data["pid"] = long(pid)
                data["comm"] = comm
                if runtime:
                    data["runtime"] = runtime

            # add CPU status #
            if "cpu" in self.reportData:
                rank = 1
                self.reportData["cpu"]["procs"] = {}

                try:
                    sortedProcData = sorted(
                        self.procData.items(),
                        key=lambda e: e[1]["ttime"],
                        reverse=True,
                    )
                except SystemExit:
                    sys.exit(0)
                except:
                    # to handle corrupted data #
                    sortedProcData = {}

                for pid, data in sortedProcData:
                    comm = data["comm"]

                    # check the number of items #
                    if SysMgr.filterGroup:
                        # check comm #
                        if not UtilMgr.isValidStr(comm):
                            continue
                    else:
                        # check rank #
                        if rank > SysMgr.nrTopRank:
                            break
                        # check usage #
                        elif not SysMgr.showAll and data["ttime"] == 0:
                            break

                    # set default #
                    evtdata = self.reportData["cpu"]["procs"]
                    evtdata[rank] = {}
                    runtime = convTime(data["runtime"])
                    _setDefaultInfo(evtdata[rank], pid, comm, runtime)

                    # total #
                    if "ttimeDiff" in data:
                        evtdata[rank]["total"] = long(data["ttimeDiff"])
                    else:
                        evtdata[rank]["total"] = data["ttime"]

                    # user #
                    if "utimeDiff" in data:
                        evtdata[rank]["user"] = long(data["utimeDiff"])
                    else:
                        evtdata[rank]["user"] = data["utime"]

                    # system #
                    if "stimeDiff" in data:
                        evtdata[rank]["kernel"] = long(data["stimeDiff"])
                    else:
                        evtdata[rank]["kernel"] = data["stime"]

                    rank += 1

            # add memory & swap status #
            if "mem" in self.reportData:
                rank = 1
                self.reportData["mem"]["procs"] = {}

                try:
                    sortedProcData = sorted(
                        self.procData.items(),
                        key=lambda e: long(e[1]["rss"]),
                        reverse=True,
                    )
                except SystemExit:
                    sys.exit(0)
                except:
                    # to handle corrupted data #
                    sortedProcData = {}

                for pid, data in sortedProcData:
                    comm = data["comm"]

                    # check the number of items #
                    if SysMgr.filterGroup:
                        # check comm #
                        if not UtilMgr.isValidStr(comm):
                            continue
                    else:
                        # check rank #
                        if rank > SysMgr.nrTopRank:
                            break

                    try:
                        text = (
                            long(data["stat"][self.ecodeIdx])
                            - long(data["stat"][self.scodeIdx])
                        ) >> 20
                    except SystemExit:
                        sys.exit(0)
                    except:
                        text = 0

                    # set default #
                    evtdata = self.reportData["mem"]["procs"]
                    evtdata[rank] = {}
                    runtime = convTime(data["runtime"])
                    _setDefaultInfo(evtdata[rank], pid, comm, runtime)
                    evtdata[rank]["rss"] = data["rss"]
                    evtdata[rank]["text"] = text

                    # add more stats #
                    if "pss" in data:
                        evtdata[rank]["pss"] = data["pss"]
                    if "uss" in data:
                        evtdata[rank]["uss"] = data["uss"]

                    # save status info #
                    path = "%s/%s" % (SysMgr.procPath, pid)
                    self.saveProcStatusData(path, pid)

                    # swap #
                    try:
                        if "swap" in data:
                            swap = data["swap"]
                        else:
                            swap = long(data["status"]["VmSwap"].split()[0])
                            swap = swap >> 10

                        evtdata[rank]["swap"] = swap
                        self.reportData["mem"]["procs"][pid]["swap"] = swap
                    except:
                        pass

                    # shared #
                    try:
                        shm = long(data["statm"][self.shrIdx]) >> 8
                        evtdata[rank]["shared"] = shm
                        self.reportData["mem"]["procs"][pid]["shared"] = shm
                    except:
                        pass

                    rank += 1

            # add block status #
            if "block" in self.reportData:
                rank = 1
                self.reportData["block"]["procs"] = {}

                try:
                    if not SysMgr.blockEnable:
                        raise Exception("no block")

                    sortedProcData = sorted(
                        self.procData.items(),
                        key=lambda e: e[1]["rw"],
                        reverse=True,
                    )
                except SystemExit:
                    sys.exit(0)
                except:
                    # to handle corrupted data #
                    sortedProcData = {}

                for pid, data in sortedProcData:
                    comm = data["comm"]

                    # check the number of items #
                    if SysMgr.filterGroup:
                        # check comm #
                        if not UtilMgr.isValidStr(comm):
                            continue
                    else:
                        # check total I/O size #
                        if data["rw"] == 0:
                            break

                    # set default #
                    evtdata = self.reportData["block"]["procs"]
                    evtdata[rank] = {}
                    runtime = convTime(data["runtime"])
                    _setDefaultInfo(evtdata[rank], pid, comm, runtime)
                    evtdata[rank]["iowait"] = data["btime"]
                    evtdata[rank]["read"] = data["read"] >> 20
                    evtdata[rank]["write"] = data["write"] >> 20

                    rank += 1

            # add gpumem status #
            if "gpumem" in self.reportData:
                rank = 1
                procs = {}

                try:
                    sortedProcData = sorted(
                        self.reportData["gpumem"].items(),
                        key=lambda e: e[1]["size"],
                        reverse=True,
                    )
                except SystemExit:
                    sys.exit(0)
                except:
                    # to handle corrupted data #
                    sortedProcData = {}

                total = 0
                for pid, data in sortedProcData:
                    if pid == "0":
                        total = data["size"] >> 20
                        continue

                    comm = data["comm"]

                    # check the number of items #
                    if SysMgr.filterGroup:
                        # check comm #
                        if not UtilMgr.isValidStr(comm):
                            continue
                    else:
                        # check size #
                        if data["size"] == 0:
                            break

                    procs[rank] = {}
                    _setDefaultInfo(procs[rank], pid, comm)
                    procs[rank]["size"] = data["size"] >> 20

                    rank += 1

                # update gpumem #
                self.reportData["gpumem"] = {"total": total, "procs": procs}

            # add task status #
            if "task" in self.reportData:
                items = ["abnormalProcs", "newProcs", "dieProcs"]
                for item in items:
                    self.reportData["task"][item] = {}

                    # check item #
                    if item == "abnormalProcs":
                        tasks = set(self.abnormalTasks)
                    elif item == "newProcs":
                        tasks = set(self.procData) - set(self.prevProcData)
                    elif item == "dieProcs":
                        tasks = set(self.prevProcData) - set(self.procData)

                    # save status #
                    rank = 1
                    for pid in tasks:
                        if item == "dieProcs":
                            procData = self.prevProcData
                        else:
                            procData = self.procData

                        # check pid #
                        if not pid in procData:
                            continue

                        # set default #
                        evtdata = self.reportData["task"][item]
                        evtdata[rank] = {}

                        comm = procData[pid]["comm"]
                        runtime = convTime(procData[pid]["runtime"])
                        _setDefaultInfo(evtdata[rank], pid, comm, runtime)

                        status = procData[pid]["stat"][self.statIdx]
                        evtdata[rank]["status"] = status

                        rank += 1

        # check resource threshold #
        self.checkResourceThreshold()

        # print system status to file if condition is met #
        if (
            "event" in self.reportData
            and self.reportData["event"]
            and SysMgr.reportFileEnable
            and SysMgr.outPath
        ):

            # submit summarized report and details #
            TaskAnalyzer.printIntervalUsage()

            # sync and close output file #
            SysMgr.closePrintFd()

            # make output path #
            filePath = os.path.dirname(SysMgr.inputFile) + "/guider"
            for event in list(self.reportData["event"]):
                filePath = "%s_%s" % (filePath, event)
            filePath = "%s_%s.out" % (filePath, str(long(SysMgr.uptime)))

            # print output info #
            try:
                # rename output file #
                os.rename(SysMgr.inputFile, filePath)

                # get output size #
                fsize = UtilMgr.getFileSizeStr(filePath)

                SysMgr.printStat(
                    (
                        "saved the results based monitoring into "
                        "'%s'%s successfully"
                    )
                    % (filePath, fsize)
                )
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn(
                    "failed to rename %s to %s" % SysMgr.inputFile, filePath
                )

        # convert dict data to JSON string #
        pretty = not SysMgr.streamEnable
        jsonStr = UtilMgr.convDict2Str(
            self.reportData, pretty=pretty, ignore=True
        )
        if not jsonStr:
            SysMgr.printWarn("failed to convert report data to JSON format")
            return

        # transfer data to file or socket #
        self.tranData(jsonStr)

    def reportSystemStatElastic(self):
        """
        make data fields as the below list
        - metricset fields
        - beat fields (metricbeat, filebeat, guider, etc...)
        - system fields (cpu, process, memory, diskio, etc...)
        """

        reportElasticData = ""

        metricsetFields = {"metricset": {"module": "system", "name": ""}}

        # set beatstart flag for syncing timestamp
        if hasattr(self, "beatStart"):
            self.beatStart = False
        else:
            self.beatStart = True

        beatFields = {
            "beat": {
                "name": __module__,
                "hostname": SysMgr.localServObj.ip,
                "version": __version__,
                "beatstart": self.beatStart,
            }
        }

        # generate CPU status data #
        metricsetFields["metricset"]["name"] = "cpu"

        cpuData = self.reportData["cpu"]

        systemCpuFields = {
            "system": {
                "cpu": {
                    "total": {"pct": cpuData["total"]},
                    "idle": {"pct": cpuData["idle"]},
                    "user": {"pct": cpuData["user"]},
                    "kernel": {"pct": cpuData["kernel"]},
                    "irq": {"pct": cpuData["irq"]},
                    "iowait": {"pct": cpuData["iowait"]},
                    "cores": cpuData["nrCore"],
                }
            }
        }

        # merge CPU data dictionary #
        reportCpuData = metricsetFields.copy()
        reportCpuData.update(beatFields)
        reportCpuData.update(systemCpuFields)

        jstr = UtilMgr.convDict2Str(reportCpuData)
        if jstr:
            reportElasticData += jstr

        # generate memory status data #
        metricsetFields["metricset"]["name"] = "memory"

        memData = self.reportData["mem"]
        swapData = self.reportData["swap"]

        systemMemoryFields = {
            "system": {
                "memory": {
                    "total": memData["total"],
                    "free": memData["free"],
                    "available": memData["available"],
                    "anon": memData["anon"],
                    "file": memData["file"],
                    "slab": memData["slab"],
                    "swap": {
                        "total": swapData["total"],
                        "used": swapData["usage"],
                    },
                }
            }
        }

        # merge momory data dictionary #
        reportMemoryData = metricsetFields.copy()
        reportMemoryData.update(beatFields)
        reportMemoryData.update(systemMemoryFields)

        jstr = UtilMgr.convDict2Str(reportMemoryData)
        if jstr:
            reportElasticData += jstr

        # generate network status data #
        metricsetFields["metricset"]["name"] = "network"

        networkData = self.reportData["net"]

        systemNetworkFields = {
            "system": {
                "network": {
                    "in": {"byte": networkData["inbound"]},
                    "out": {"byte": networkData["outbound"]},
                }
            }
        }

        # merge network data dictionary #
        reportNetworkData = metricsetFields.copy()
        reportNetworkData.update(beatFields)
        reportNetworkData.update(systemNetworkFields)

        jstr = UtilMgr.convDict2Str(reportNetworkData)
        if jstr:
            reportElasticData += jstr

        # generate network status data #
        metricsetFields["metricset"]["name"] = "diskio"

        systemDiskioFields = {
            "system": {
                "diskio": {
                    "name": "",
                    "read": {"bytes": 0},
                    "write": {"bytes": 0},
                    "used": {"pct": 0},
                }
            }
        }

        diskioData = systemDiskioFields["system"]["diskio"]

        # get read/write bytes on each devices #
        for dev, value in sorted(self.reportData["storage"].items()):
            diskioData["name"] = dev
            diskioData["read"]["bytes"] = value["read"]
            diskioData["write"]["bytes"] = value["read"]
            diskioData["used"]["pct"] = value["usagePer"]

            # merge diskio data dictionary #
            reportDiskioData = metricsetFields.copy()
            reportDiskioData.update(beatFields)
            reportDiskioData.update(systemDiskioFields)

            jstr = UtilMgr.convDict2Str(reportDiskioData)
            if jstr:
                reportElasticData += jstr

        # generate process status data #
        metricsetFields["metricset"]["name"] = "process"

        strProcessData = ""
        systemProcessFields = {
            "system": {
                "process": {
                    "name": "",
                    "state": "",
                    "pid": 0,
                    "cpu": {
                        "user": {"pct": 0},
                        "kernel": {"pct": 0},
                        "total": {"pct": 0},
                        "runtime": "",
                    },
                    "memory": {"rss": {"bytes": 0}, "text": 0},
                }
            }
        }

        sortedProcData = sorted(
            self.procData.items(), key=lambda e: e[1]["ttime"], reverse=True
        )

        processData = systemProcessFields["system"]["process"]

        for pid, data in sortedProcData:
            if not (SysMgr.showAll or data["ttime"] > 0):
                break

            processData["pid"] = long(pid)
            processData["name"] = data["comm"]
            processData["cpu"]["user"]["pct"] = data["utime"]
            processData["cpu"]["kernel"]["pct"] = data["stime"]
            processData["cpu"]["total"]["pct"] = data["ttime"]
            processData["cpu"]["runtime"] = UtilMgr.convTime(data["runtime"])

            rss = long(data["stat"][self.rssIdx]) >> 8

            text = (
                long(data["stat"][self.ecodeIdx])
                - long(data["stat"][self.scodeIdx])
            ) >> 20

            processData["memory"]["rss"]["bytes"] = rss
            processData["memory"]["text"] = text

            # merge process data dictionary #
            reportProcessData = metricsetFields.copy()
            reportProcessData.update(beatFields)
            reportProcessData.update(systemProcessFields)

            jstr = UtilMgr.convDict2Str(reportProcessData)
            if jstr:
                reportElasticData += jstr

        # transfer data to file or socket #
        self.tranData(reportElasticData)

    def tranData(self, data):
        # report to the file #
        if SysMgr.reportObject:
            UtilMgr.writeJsonObject(
                data, fd=SysMgr.reportObject, trunc=SysMgr.truncEnable
            )

        # report to sockets #
        addrlist = dict(SysMgr.addrListForReport)
        for addr, cli in addrlist.items():
            if cli.request != "REPORT":
                continue
            elif cli.status == "SENT" and cli.ignore > 1:
                SysMgr.printInfo(
                    "unregistered %s:%d for REPORT" % (cli.ip, cli.port)
                )
                del SysMgr.addrListForReport[addr]
            else:
                ret = cli.send(data)
                if not ret:
                    del SysMgr.addrListForReport[addr]
                else:
                    cli.ignore += 1

    def printSimpleStat(self):
        pass

    def checkPrintCond(self):
        try:
            cond = SysMgr.printCond
            if (
                cond["CPUCOND"] < self.reportData["cpu"]["total"]
                and cond["MEMFREECOND"] > self.reportData["mem"]["free"]
                and cond["MEMAVLCOND"] > self.reportData["mem"]["available"]
                and cond["BLKRDCOND"] < self.reportData["block"]["read"]
                and cond["BLKWRCOND"] < self.reportData["block"]["write"]
            ):
                return True
            else:
                return False
        except:
            return True

    def printSystemStatGen(self, idIndex=False, target="task"):
        title = "[Top Info]"

        if not self.taskStreamEnable:
            # print default stats #
            self.printDefaultUsage(title)

            # print system stat #
            self.printSystemUsage()

            # print disk stat #
            self.printDiskUsage()

            # print network stat #
            self.printNetworkUsage()

        # print process stat #
        self.printTaskUsageGen(idIndex=idIndex)

        # flush print buffer #
        if self.reportData:
            if self.checkPrintCond():
                SysMgr.printTopStats()
            else:
                SysMgr.clearPrint()
        else:
            SysMgr.printTopStats()

    def checkTermCond(self):
        def _searchTask(self, termCond, taskList, msg):
            for pid in taskList:
                if pid in self.prevProcData:
                    comm = self.prevProcData[pid]["comm"].lstrip("*")
                elif pid in self.procData:
                    comm = self.procData[pid]["comm"].lstrip("*")
                else:
                    comm = ""

                # check termination condition #
                if pid in termCond or (
                    comm and UtilMgr.isValidStr(comm, termCond)
                ):
                    SysMgr.printInfo("%s(%s) is %s" % (comm, pid, msg))
                    sys.exit(0)

        # terminated tasks #
        if "EXITCONDTERM" in SysMgr.environList:
            termCond = SysMgr.environList["EXITCONDTERM"]
            taskList = set(self.prevProcData) - set(self.procData)
            msg = "terminated"
            _searchTask(self, termCond, taskList, msg)

        # new tasks #
        if "EXITCONDNEW" in SysMgr.environList:
            termCond = SysMgr.environList["EXITCONDNEW"]
            taskList = set(self.procData) - set(self.prevProcData)
            msg = "executed"
            _searchTask(self, termCond, taskList, msg)

        # new files #
        if "EXITCONDFILE" in SysMgr.environList:
            for fpath in SysMgr.environList["EXITCONDFILE"]:
                if os.path.isfile(fpath):
                    SysMgr.printInfo("'%s' is found" % os.path.realpath(fpath))
                    sys.exit(0)

        # removed files #
        if "EXITCONDNOFILE" in SysMgr.environList:
            for fpath in SysMgr.environList["EXITCONDNOFILE"]:
                if not os.path.isfile(fpath):
                    SysMgr.printInfo("no '%s'" % os.path.realpath(fpath))
                    sys.exit(0)

        # check functions #
        if "EXITCONDFUNC" in SysMgr.environList:
            for item in SysMgr.environList["EXITCONDFUNC"]:
                # get function info #
                try:
                    values = item.split(":")
                    path, func = values[:2]
                    if len(values) > 2:
                        args = values[2:]
                    else:
                        args = []
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(
                        "failed to parse function info from '%s'" % item, True
                    )
                    sys.exit(0)

                # call function #
                ret = UtilMgr.callPyFunc(path, func, args)
                if ret:
                    SysMgr.printInfo(
                        "%s(%s) in %s returned %s" % (func, args, path, ret)
                    )
                    sys.exit(0)

    def printSystemStat(self, idIndex=False, target="task"):
        title = "[Top Info]"
        nrIndent = len(title)

        if not self.taskStreamEnable:
            # print default stats #
            self.printDefaultUsage(title)

            # print memory stats #
            self.printMemoryUsage(nrIndent)

            # print slab stats #
            self.printSlabUsage(nrIndent)

            # print vm stats #
            self.printVmInfo(nrIndent)

            # print LMK stats #
            self.printLMKStat(nrIndent)

            # print zone stats #
            self.printZoneUsage(nrIndent)

            # print irq stats #
            self.printIrqUsage(nrIndent)

            # print PMU stat #
            self.printPerfUsage(nrIndent)

            # print system stat #
            self.printSystemUsage()

            # print disk stat #
            self.printDiskUsage()

            # print network stat #
            self.printNetworkUsage()

        # print process stat #
        if target == "task":
            self.printTaskUsage(idIndex=idIndex)
        elif target == "cgroup":
            self.printCgroupUsage()
        else:
            SysMgr.printErr("wrong monitor target for '%s'" % target)
            sys.exit(-1)

        # update session #
        SysMgr.updateSession()

        # flush print buffer #
        if self.reportData:
            if self.checkPrintCond():
                SysMgr.printTopStats()
            else:
                SysMgr.clearPrint()
        else:
            SysMgr.printTopStats()


def decoratorFunc(origFunc):
    def wrapper(*args, **kwargs):
        return origFunc(*args, **kwargs)

    return wrapper


def main(args=None):
    # update arguments #
    if UtilMgr.isString(args):
        sys.argv = [__module__] + args.split()
    elif type(args) is list or type(args) is tuple:
        if sys.version_info < (3, 0, 0):
            args = list(map(lambda x: x.encode(), args))
        sys.argv = [__module__] + list(args)

    # init environment #
    SysMgr.initEnvironment()

    # launch commands #
    if not SysMgr.isRecordMode():
        SysMgr.checkCmdMode()

    # init system context #
    SysMgr.initSystemContext()

    # ==================== RECORD PART ====================#

    if SysMgr.isRecordMode():
        SysMgr.setRecordAttr()

        # wait for input #
        if SysMgr.waitEnable:
            SysMgr.waitUserInput(SysMgr.waitEnable, msg="DEFAULT", force=True)

        # set normal signal #
        SysMgr.setNormalSignal()

        # SYSTEM MODE #
        if SysMgr.isSystemMode():
            SysMgr.execSystemView()
            sys.exit(0)
        # FILE MODE #
        elif SysMgr.isFileMode():
            SysMgr.execFileAnalysis()
            sys.exit(0)

        # register exit handler #
        atexit.register(SysMgr.stopRecording)

        # start recording #
        SysMgr.sysInstance.startRecording()

        # THREAD & FUNCTION MODE #
        try:
            SysMgr.execRecordLoop()
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("terminated recording", reason=True)

    # ==================== ANALYSIS PART ====================#

    # register exit handler #
    atexit.register(SysMgr.doExit)

    # REPORT MODE #
    if SysMgr.checkMode("report"):
        SysMgr.setReportAttr()
    # VISUAL MODE #
    elif SysMgr.isDrawMode():
        SysMgr.setVisualAttr()

    # parse analysis option #
    SysMgr.parseAnalOption()

    # REALTIME MODE #
    if SysMgr.isTopMode():
        SysMgr.execTopCmd()
        sys.exit(0)
    # FUNCTION GRAPH MODE #
    elif SysMgr.graphEnable and SysMgr.isRecordMode() and SysMgr.isFuncMode():
        FunctionAnalyzer(SysMgr.inputFile)

    # set handler for exit #
    signal.signal(signal.SIGINT, SysMgr.exitHandler)

    # check log file is recoginizable #
    TaskAnalyzer.getInitTime(SysMgr.inputFile)

    # apply launch option from data file #
    if not SysMgr.isRecordMode():
        SysMgr.applyLaunchOption()

    # get mount info from file #
    SysMgr.getMountInfo()

    # print analysis option #
    SysMgr.printAnalOption()

    # FUNCTION MODE #
    if SysMgr.isFuncMode():
        FunctionAnalyzer(SysMgr.inputFile).printUsage()
    # DRAW MODE #
    elif SysMgr.isDrawMode():
        origInputFile = SysMgr.inputFile
        origInterval = SysMgr.intervalEnable

        # check svgwrite object #
        svgwrite = SysMgr.getPkg("svgwrite")

        # prepare for timeline segment #
        SysMgr.graphEnable = False
        SysMgr.intervalEnable = 0
        tobj = TaskAnalyzer(origInputFile)
        outputPath = UtilMgr.prepareForImageFile(SysMgr.inputFile, "timeline")

        # check absolute timeline option #
        if "ABSTIME" in SysMgr.environList:
            start = float(SysMgr.startTime)
        else:
            start = 0

        # minimize system info for annotation #
        if SysMgr.systemInfoBuffer:
            annotation = SysMgr.systemInfoBuffer
            annotation = annotation.replace("%s\n" % twoLine, "")
        else:
            annotation = None

        # update name table #
        itemInfoList = {}
        taskList = {x: None for x in tobj.threadData.keys()}
        if "PERTASK" in SysMgr.environList:
            tobj.timelineData["names"] = {
                y: x for x, y in tobj.timelineIdx.items()
            }

            # get task usage #
            tasks = tobj.timelineData["names"]
            for key, value in tobj.threadData.items():
                if not key in tobj.timelineIdx:
                    continue

                # calculate total task usage percentage #
                try:
                    usagePercent = value["usage"] / float(tobj.totalTime) * 100
                except:
                    usagePercent = 0

                itemInfoList[key] = "%s: %d%%" % (value["comm"], usagePercent)
        else:
            # get core usage #
            for key, value in tobj.threadData.items():
                if not key.startswith("0["):
                    continue

                try:
                    coreId = str(key[key.find("[") + 1 : -1])
                except:
                    continue

                # calculate total core usage percentage #
                try:
                    idle = value["usage"] / float(tobj.totalTime)
                    usagePercent = long(100 - (idle * 100))
                except:
                    usagePercent = 0

                itemInfoList[coreId] = "Core%s: %d%%" % (coreId, usagePercent)

        # draw timeline segment #
        SysMgr.drawTimeline(
            inputData=tobj.timelineData,
            outputPath=outputPath,
            taskList=taskList,
            start=start,
            annotation=annotation,
            yval=itemInfoList,
        )

        # draw resource graph #
        SysMgr.graphEnable = True
        SysMgr.intervalEnable = origInterval
        TaskAnalyzer(origInputFile).printUsage()
    # THREAD MODE #
    else:
        TaskAnalyzer(SysMgr.inputFile).printUsage()

    # print event info #
    EventAnalyzer.printEventInfo()


# define line variables #
oneLine = "-" * SysMgr.lineLength
twoLine = "=" * SysMgr.lineLength
splitLine = ">" * SysMgr.lineLength
underLine = "_" * SysMgr.lineLength

# define print method for debugging #
def dbgp(msg):
    SysMgr.printWarn(msg, True)


# main #
if __name__ == "__main__":
    # set main environment #
    os.environ["ISMAIN"] = "True"

    main(args=None)
