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

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





# import essential packages #
try:
    import os
    import re
    import gc
    import sys
    import time
    import errno
    import signal
    import atexit
    import struct
    from copy import deepcopy
    #from ctypes import *
except ImportError:
    err = sys.exc_info()[1]
    print("[ERROR] fail to import essential packages: %s" % err.args[0])
    sys.exit(0)

# to convert an unsupported type #
try:
    long
except:
    long = int

# to prevent MemoryError in python2 #
try:
    xrange
except:
    xrange = range





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

    # Define 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])

    # Define color #
    if (sys.platform.startswith('linux') or \
        sys.platform.startswith('freebsd')) and \
        not 'REMOTERUN' in os.environ:
        WARNING = '\033[95m'
        OKBLUE = '\033[94m'
        OKGREEN = '\033[92m'
        SPECIAL = '\033[93m'
        FAIL = '\033[91m'
        ENDC = '\033[0m'
        BOLD = '\033[1m'
        UNDERLINE = '\033[4m'
    else:
        WARNING = ''
        OKBLUE = ''
        OKGREEN = ''
        SPECIAL = ''
        FAIL = ''
        ENDC = ''
        BOLD = ''
        UNDERLINE = ''

    # Define config info #
    confData = {}

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

    # Define 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',
        'OKGREEN': '\033[92m',
        'SPECIAL': '\033[93m',
        'OKBLUE': '\033[94m',
        'WARNING': '\033[95m',
    }

    # Define 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',
    ]

    # Define cgroup stat #
    CGROUP_STAT = [
        'cpuacct.usage',
        'memory.usage_in_bytes',
        'tasks',
        'cgroup.procs',
    ]

    # Define 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',
    }

    # Define 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+
    ]

    # Define 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",
    }

    # Define 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",
    }

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

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

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

    # Define 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",
    }

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

    # Define 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",
    }

    # Define 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
    }

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

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

    # Define 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",
    }

    # Define 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",
    }

    # Define open flags type #
    OPEN_TYPE = {
        0o0: "O_RDONLY",
        0o1: "O_WRONLY",
        0o2: "O_RDWR",
        0o100: "O_CREAT",
        0o200: "O_EXCL",
        0o400: "O_NOCTTY",
        0o1000: "O_TRUNC",
        0o2000: "O_APPEND",
        0o4000: "O_NONBLOCK",
        0o10000: "O_SYNC",
        0o20000: "O_ASYNC",
        0o40000: "O_DIRECT",
        0o100000: "O_LARGEFILE",
        0o200000: "O_DIRECTORY",
        0o400000: "O_NOFOLLOW",
        0o1000000: "O_NOATIME",
        0o2000000: "O_CLOEXEC",
        0o10000000: "O_PATH",
        0o20200000: "O_TMPFILE",
    }

    # Define 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",    # Explicity 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
    }

    # Define 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,
     }

    # Define 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 */
    }

    # Define 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
    }

    # Define 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"),
        )),
        "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"),
        )),
        "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"),
            ("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_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"),
        )),
        "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", (
            ("char *", "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"),
            ("char *", "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"),
        )),
        "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 *", "list"),
            ("size_t", "size"),
        )),
        "llistxattr": ("long", (
            ("const char *", "path"),
            ("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", (
            ("char *", "dev_name"),
            ("char *", "dir_name"),
            ("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 *", "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"),
            ("char *", "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"),
        )),
        "read": ("long", (
            ("unsigned int", "fd"),
            ("char *", "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", (
            ("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", (
            ("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"),
            ("char *", "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"),
            ("char *", "shmaddr"),
            ("int", "shmflg"),
        )),
        "shmctl": ("long", (
            ("int", "shmid"),
            ("int", "cmd"),
            ("struct shmid_ds *", "buf"),
        )),
        "shmdt": ("long", (
            ("char *", "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"),
        )),
        "statx": ("long", (
            ("int", "dfd"),
            ("const char *", "path"),
            ("unsigned", "flags"),
            ("unsigned", "mask"),
            ("struct statx *", "buf"),
        )),
        "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 *", "buffer"),
        )),
        "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", (
            ("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", (
            ("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", (
            ("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/strace/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)
    '''

    # Define 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',
    ]

    # Define common syscalls from 424 ~ 435 #
    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',
    ]

    # Define 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

    # Define 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 range(295, 423, 1)] + SYSCALL_COMMON + \
        ['close_range', 'openat2', 'pidfd_getfd', 'pidfd_getfd', 'faccessat2']

    # Define 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

    # Define 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 range(335, 423, 1)] + SYSCALL_COMMON

    # Define default syscall list #
    sysList = []

    # Define default register list #
    regList = []

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

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

    REGS_ARM = ['r%d' % idx for idx in range(0, 16, 1)]

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

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

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

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

    # Define signal #
    SIG_LIST = [
        'ZERO', '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 range(0, 32, 1)]
    SIGKILL = SIG_LIST.index('SIGKILL')

    # stat list 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' #43#
        'STARTDATA', 'ENDDATA', 'STARTBRK', 'ARGSTART', 'ARGEND', #48#
        'ENVSTART', 'ENVEND', 'EXITCODE', #51#
    ]

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

    # Define statm of process #
    STATM_TYPE = [
        'TOTAL',    # 0 #
        'RSS',      # 1 #
        'SHR',      # 2 #
        'TEXT',     # 3 #
        'DATA',     # 4 #
        'LIB',      # 5 #
        'DIRTY',    # 6 #
    ]

    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 #
    ]

    # Define rlimit of process #
    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'
    ]

    # Define udp/tcp format of system #
    UDP_ATTR = [
        'sl',
        'local_address',
        'rem_address',
        'st',
        'tx_rx_queue',
        'tr_tm->when',
        'retrnsmt',
        'uid',
        'timeout',
        'inode',
        'ref',
        'pointer',
        'drops'
    ]

    # Define uds format of system #
    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'
    ]

    # Define 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',
    ]

    # Define 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',
    ]

    # Define 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",
    }

    # Define 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#
    ]

    # Define ptrace event type #
    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 range(0, 120, 1)] + ['PTRACE_EVENT_STOP']

    # Define perf event types #
    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 ConfigMgr.sysList.index('sys_mmap2')
        else:
            return ConfigMgr.sysList.index('sys_mmap')



    @staticmethod
    def openConfFile(path):
        path += '.tc'
        if os.path.isfile(path):
            SysMgr.printWarn(
                "%s already exists so that make new one" % path)

        try:
            fd = open(path, 'w')
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenErr(path)
            return None

        return fd



    @staticmethod
    def writeConfData(fd, line):
        if not fd:
            SysMgr.printErr("fail to get file descriptor")
            return None

        fd.write(line)



    def __init__(self, mode):
        pass



    def __del__(self):
        pass





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

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



    @staticmethod
    def setTime():
        UtilMgr.curTime = time.time()



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

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

        return string



    @staticmethod
    def printTime(name=None, update=False):
        # get current time #
        now = time.time()
        diff = now - UtilMgr.curTime

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

        # add name #
        if name:
            prefix = '[%s]' % name
        else:
            prefix = ''

        # print time diff #
        string = '\n%s[Elapsed: %f]' % (prefix, diff)
        print(UtilMgr.convColor(string, 'RED'))



    @staticmethod
    def compareSyscallSuperset():
        # initialize ignore list #
        ignoreList = set([
            'sys_ppoll_time64', 'sys_nfsservctl', 'sys_null',
            'sys_setfsgid32', 'sys_ftime', 'sys_geteuid32',
            'sys_clock_adjtime64', 'sys_timerfd_settime64',
            'sys_epoll_ctl_old', 'sys_setfsuid32', 'sys_getresgid32',
            'sys_iopl', 'sys_chown32', 'sys_rt_sigtimedwait_time64',
            'sys_gtty', 'sys_setresgid32', 'sys_reserved', 'sys_unused',
        ])

        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.keys()])

        # print final diff list #
        print("--- no prototype ---")
        print(list(syscallList - protoList - ignoreList))

        print("\n--- no define ---")
        print(list(protoList - syscallList))



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

        try:
            num = long(num)
        except:
            num = long(num, 16)

        try:
            bits = long(bits)
        except:
            bits = long(bits, 16)

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



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

        if targetType is str:
            targetStr = ''
            for val in targetList:
                if val: targetStr = '%s%s' % (targetStr, val)
            return targetStr
        elif targetType is list:
            # remove redundant values #
            if union:
                targetList = list(set(targetList))

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

            return newList
        else:
            return targetList



    @staticmethod
    def printHist(table, title, unit):
        if not table:
            return

        convNum = UtilMgr.convNum

        # pop stats #
        statmin = table.pop('min', None)
        statmax = table.pop('max', None)
        statcnt = table.pop('cnt', None)

        SysMgr.printPipe(
            '\n[%s Histogram] (unit:%s)\n%s' % (title, unit, twoLine))
        SysMgr.printPipe('{0:^21}   {1:^17}'.format('Range', 'Count'))
        SysMgr.printPipe(oneLine)

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

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

            SysMgr.printPipe(
                '{0:10}-{1:>10}   {2:>10}({3:5.1f}%)'.format(
                    convNum(srange), convNum(erange), convNum(cnt),
                    cnt/float(statcnt)*100))

        SysMgr.printPipe(oneLine)
        SysMgr.printPipe('{0:^21}   {1:>17}'.format('Min', convNum(statmin)))
        SysMgr.printPipe('{0:^21}   {1:>17}'.format('Max', convNum(statmax)))
        SysMgr.printPipe('{0:^21}   {1:>17}'.format('Cnt', convNum(statcnt)))
        SysMgr.printPipe(oneLine)



    @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)
        }

        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 convList2Dict(optList, sep=':'):
        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

                # set values #
                if key in newDict:
                    newDict[key].append(value)
                else:
                    newDict[key] = [value]
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn(
                    "fail to parse %s by seperator %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')
        std_dev = math.sqrt(var)
        return std_dev



    @staticmethod
    def getRealTime():
        return time.asctime(time.gmtime(time.time()))



    @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):
        # 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)
        else:
            outputPath = UtilMgr.prepareForImageFile(
                inputPath, 'flamegraph')

        return outputPath



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

        print(bufstring)

        print('total: %s' % len(systable))

        sys.exit(0)



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

        if not key:
            return True

        if ignCap:
            string = string.lower()

        for cond in list(key):
            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 drawGraph(inFile, outFile=None):
        instance = TaskAnalyzer(onlyInstance=True)
        instance.drawStats(inFile, outFile=outFile, onlyGraph=True)



    @staticmethod
    def drawChart(inFile, outFile=None):
        instance = TaskAnalyzer(onlyInstance=True)
        instance.drawStats(inFile, outFile=outFile, onlyChart=True)



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



    @staticmethod
    def getFiles(path, incFile=True, incDir=False):
        flist = list()

        for r, d, f in os.walk(path):
            if incFile:
                for sfile in f:
                    flist.append(os.path.join(r, sfile))
            if incDir:
                for sdir in d:
                    flist.append(os.path.join(r, sdir))

        return flist



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

        rlist = list()
        for item in flist:
            if item.startswith('-'):
                break

            # apply regular expression for path #
            ilist = UtilMgr.convPath(item)
            if 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)

        # 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:]



    @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('fail 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(
                    "fail to get %s in [%s]" % \
                        (flag, '|'.join(list(vlist.keys()))))
                sys.exit(0)

        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.keys()):
            try:
                if numVal - bit < 0:
                    break
                elif numVal & bit:
                    string = '%s%s|' % (string, flist[bit])
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn(
                    "fail 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 len(string) > 0:
            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
        for b in obj:
            value = (value << 7) + (ord(b) & 0x7F)
            if (ord(b) & 0x80) == 0:
                break
            size += 1
        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:
            if (ord(b) & 0x80) == 0:
                break
            size += 1

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

        return value, size



    @staticmethod
    def isCompressed(fname=None, fd=None):
        if fname:
            try:
                fd = open(fname, 'rb')
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenErr(fname)
                sys.exit(0)

        if fd:
            data = fd.read(2)
            fd.seek(0, 0)
            if struct.unpack('BB', data) == (0x1f, 0x8b):
                return True
            else:
                return False
        else:
            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
        else:
            if 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 type(value) is int or \
            type(value) is 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, verbose=False, retfd=False):
        buf = []

        if verbose:
            if retfd:
                SysMgr.printStat(
                    r"start checking '%s'..." % fname)
            else:
                SysMgr.printStat(
                    r"start loading '%s'..." % fname)

        # check gzip #
        try:
            fd = None
            with open(fname, 'rb') as fd:
                data = fd.read(2)
                if struct.unpack('BB', data) != (0x1f, 0x8b):
                    raise Exception()

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

        # open a 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 = long(0)

        # read data from a file #
        while 1:
            try:
                data = fd.readline()
                curSize = fd.tell()
                if not data:
                    break
                buf.append(data)
            except SystemExit:
                sys.exit(0)
            except:
                break

            if verbose:
                UtilMgr.printProgress(curSize, totalSize)

        if verbose:
            UtilMgr.deleteProgress()

        try:
            fd.close()
        except:
            pass

        return buf



    @staticmethod
    def convPath(value, retStr=False, isExit=False, separator=' '):
        value = value.strip()
        glob = SysMgr.getPkg('glob', False)
        if glob:
            # 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(
                    "fail to find a file matching '%s'" % value)
                sys.exit(0)

            # str #
            if retStr:
                return separator.join(res)
            # list #
            else:
                return res
        else:
            # 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(
                "fail 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):
        try:
            if type(string) is long:
                return string
            elif string.isdigit():
                string = long(string)
            else:
                string = long(string, 16)
        except SystemExit:
            sys.exit(0)
        except:
            if verb:
                SysMgr.printErr(
                    "fail to convert %s to number" % string, True)
            return None

        return string



    @staticmethod
    def convNum(number):
        try:
            return format(long(number), ",")
        except SystemExit:
            sys.exit(0)
        except:
            return number



    @staticmethod
    def getRealLen(string):
        ansi = r'(?:\x1B[@-_]|[\x80-\x9F])[0-?]*[ -/]*[@-~]'
        ansiObj = re.compile(ansi)
        return len(ansiObj.sub('', string))



    @staticmethod
    def convColor(string, color='LIGHT', size=1, align='right'):
        if not SysMgr.colorEnable or not color or \
            SysMgr.outPath or SysMgr.outputFile or \
            not SysMgr.isLinux or SysMgr.remoteRun:
            return string

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

        try:
            return (ConfigMgr.COLOR_LIST[color] + string + ConfigMgr.ENDC)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn(
                'fail to convert color for %s' % color, reason=True)



    @staticmethod
    def convSize2Unit(size, isInt=False):
        sizeKB = long(1024)
        sizeMB = sizeKB << 10
        sizeGB = sizeMB << 10
        sizeTB = sizeGB << 10

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

        # Int type #
        if isInt:
            try:
                if 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 >= 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 convTime(time):
        # 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" % (d, h, m, s)
        except SystemExit:
            sys.exit(0)
        except:
            ctime = "%s%02s:%02s:%02s" % ('', '?', '?', '?')

        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(
                "fail 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(
                "fail to convert '%s' to seconds" % data)

        return ret



    @staticmethod
    def convUnit2Size(value):
        sizeKB = long(1024)
        sizeMB = sizeKB << 10
        sizeGB = sizeMB << 10
        sizeTB = sizeGB << 10
        sizePB = sizeTB << 10

        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)

            SysMgr.printErr(
                "fail to convert %s to size" % value)

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



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

                fd.write(jsonObj)

                fd.flush()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn(
                    "fail 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(
                "fail to write JSON format data to %s" % path, True)
            sys.exit(0)



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

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

        # disable compression for performance #
        SysMgr.compressEnable = False

        # compress by gzip #
        if SysMgr.compressEnable:
            compressor = SysMgr.getPkg('gzip', False)
        else:
            compressor = None

        # 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)
            return True
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn(
                "fail 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

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

        # disable compression for performance #
        SysMgr.compressEnable = False

        # decompress by gzip #
        if SysMgr.compressEnable:
            decompressor = SysMgr.getPkg('gzip')
        else:
            decompressor = None

        try:
            if decompressor:
                with decompressor.open(path, 'rb') as fd:
                    return pickle.load(fd)
            else:
                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

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

            percent = long(div)

            mod = percent & 3

            sys.stdout.write('%3d%% %s%s' % \
                (percent, UtilMgr.progressChar[mod], '\b' * 6))

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



    @staticmethod
    def writeFlamegraph(path, samples, title):
        # flamegraph from https://github.com/rbspy/rbspy/tree/master/src/ui/flamegraph.rs #
        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="1200" height="230" onload="init(evt)" viewBox="0 0 1200 230"
        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(230,0,230)';
var fluiddrawing = true;
var truncate_text_right = false;]]>
                <![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.nodeValue = nametype + " " + g_to_text(target);
}, false)
// clear
window.addEventListener("mouseout", function(e) {
    var target = find_group(e.target);
    if (target) details.nodeValue = ' ';
}, false)
// ctrl-F for search
window.addEventListener("keydown",function (e) {
    if (e.keyCode === 114 || (e.ctrlKey && e.keyCode === 70)) {
        e.preventDefault();
        search_prompt();
    }
}, 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(/\([^(]*\)$/,"");
    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")
    }
    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");
        searchbtn.firstChild.nodeValue = "Search"
        matchedtxt.classList.add("hide");
        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.attributes.fill.value = searchcolor;
            // 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");
    searchbtn.firstChild.nodeValue = "Reset Search";
    // 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);
    matchedtxt.firstChild.nodeValue = "Matched: " + pct + "%";
}
function format_percent(n) {
    return n.toFixed(4) + "%";
}
]]>
        </script>
'''
        attrCode = '''
    <rect x="0" y="0" width="100%%" height="230" fill="url(#background)"/>
    <text id="title" x="50.0000%%" y="24.00">Guider Flamegraph</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</text>
    <text id="search" x="1090" y="24.00">Search</text>
    <text id="matched" x="1090" y="213.00"></text>
    <svg id="frames" x="10" y="20" width="1180">
''' % ('\r\n%s' % title if title else '')

        # 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)

            # get output size #
            fsize = UtilMgr.getFileSize(path)
            if fsize and fsize != '0':
                fsize = ' [%s]' % fsize
            else:
                fsize = ''

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



    @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(
                "fail 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)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "fail to print %s" % path, reason=True)



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

        sys.stdout.write(' ' * 6)

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



    @staticmethod
    def which(file):
        pathList = []
        for path in os.environ["PATH"].split(os.pathsep):
            if os.path.exists(os.path.join(path, file)):
                pathList.append(os.path.join(path, file))
        if not pathList:
            return None
        else:
            return pathList



    @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(
                "fail 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(
                    "fail to convert %s to dict" % [strObj],
                        always=verb, reason=True)
                return None





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

    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 = long(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(
                "fail 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
                    self.socket = socket(
                        AF_NETLINK, SOCK_RAW,
                            ConfigMgr.NETLINK_TYPE['NETLINK_GENERIC'])
                except:
                    SysMgr.printWarn(
                        "fail 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 = long(0)
            timeval = struct.pack('ll', sec, usec)
            self.socket.setsockopt(SOL_SOCKET, SO_SNDTIMEO, timeval)
            '''

            # 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 = long(0)
                elif not port:
                    self.port = SysMgr.defaultPort

                # bind #
                if bind:
                    try:
                        self.socket.bind((self.ip, self.port))
                    except OSError as e:
                        if e.errno == errno.EADDRINUSE:
                            self.port = long(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(
                    "fail 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 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, time=3):
        if 'TIMEOUT' in SysMgr.environList:
            try:
                time = float(SysMgr.environList['TIMEOUT'][0])
            except:
                SysMgr.printErr(
                    'fail to get TIMEOUT variable', True)
                sys.exit(0)

        self.socket.settimeout(time)



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

        ret = self.socket.connect(addr)

        self.connected = True

        return ret



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

            receiver = self
            targetIp = self.ip
            targetPort = self.port
            addr = '%s:%s' % (targetIp, targetPort)

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

            # receive file #
            try:
                curSize = long(0)
                totalSize = None
                dirPos = targetPath.rfind('/')
                if dirPos >= 0 and not os.path.isdir(targetPath[:dirPos]):
                    os.makedirs(targetPath[:dirPos])

                # receive file size #
                while 1:
                    size = receiver.recv(receiver.recvSize)
                    if not size:
                        continue
                    else:
                        totalSize = long(size.decode())
                        receiver.send('ACK'.encode())
                        break

                # receive file #
                with open(targetPath, 'wb') as fd:
                    while 1:
                        selectObj.select([receiver.socket], [], [], 3)

                        buf = receiver.recv(receiver.recvSize)
                        if buf:
                            curSize += len(buf)
                            fd.write(buf)
                        else:
                            break

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

                UtilMgr.deleteProgress()

                SysMgr.printInfo(
                    "downloaded %s [%s] from %s:%s:%s successfully\n" % \
                    (targetPath, UtilMgr.getFileSize(targetPath),
                        targetIp, targetPort, origPath))

                res = True
            except:
                SysMgr.printErr(
                    'fail to download %s from %s in %s' % \
                        (origPath, targetPath, addr), True)
                res = False
            finally:
                receiver.close()
                return res

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

            sender = self
            targetIp = self.ip
            targetPort = self.port
            addr = '%s:%s' % (targetIp, targetPort)

            # check file #
            if not os.path.isfile(origPath):
                SysMgr.printErr(
                    'failed to find %s to transfer' % origPath)
                return

            try:
                # receive file size #
                stat = os.stat(origPath)
                st_size = '%s' % stat.st_size
                sender.send(st_size)

                # read for ACK #
                while 1:
                    ret = sender.recv(3)
                    if ret is None:
                        continue
                    elif ret is False:
                        sys.exit(0)
                    else:
                        break

                # transfer file #
                curSize = long(0)
                totalSize = long(st_size)
                with open(origPath, 'rb') as fd:
                    buf = fd.read(sender.sendSize)

                    while buf:
                        # print progress #
                        UtilMgr.printProgress(curSize, totalSize)

                        assert sender.send(buf)

                        curSize = len(buf)

                        buf = fd.read(sender.sendSize)

                UtilMgr.deleteProgress()

                SysMgr.printInfo(
                    "uploaded %s [%s] to %s:%s successfully\n" % \
                        (origPath, UtilMgr.getFileSize(origPath),
                            addr, targetPath))

                res = True
            except:
                SysMgr.printErr(
                    "fail to upload %s to %s in %s" % \
                        (origPath, targetPath, addr), True)
                res = False
            finally:
                sender.close()
                return res

        def _onList(req):
            SysMgr.printInfo(req.lstrip('LIST:'))
            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:
                    [readSock, writeSock, errorSock] = \
                        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('ERROR'):
                err = req.split('|', 1)[1]
                errToken = err.find("':")
                errMsg = "%s' from %s" % (err[:errToken], err[errToken+2:])
                SysMgr.printErr(errMsg)

            else:
                SysMgr.printErr(
                    "fail 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(
                "fail to use IP address for client because it is not set")
            return False
        elif not self.socket:
            SysMgr.printErr(
                "fail to use socket for client because it is not set")
            return False

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

        try:
            # check protocol #
            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))

            if ret < 0:
                raise Exception('send error')

            if self.status != 'ALWAYS':
                self.status = 'SENT'
            return True
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "fail 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(
                "fail to use IP address for client because it is not set")
            return False
        elif not self.socket:
            SysMgr.printErr(
                "fail 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(
                "fail 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(
                "fail to use IP address for server because it is not set")
            return False
        elif not self.socket:
            SysMgr.printErr(
                "fail 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(
                "fail 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 = 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(
                "fail 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, verbose=True):
        if self.ip is None or self.port is None:
            SysMgr.printWarn(
                "fail to use IP address for server because it is not set")
            return False
        elif not self.socket:
            SysMgr.printErr(
                "fail 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(
                    "fail 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 verbose:
                    SysMgr.printWarn(
                        "fail 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):
        return NetworkMgr.execRemoteCmd("PING:PING", addr=addr, verb=verb)



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

        # define valid request list #
        requestList = {
            'DOWNLOAD': None,
            'UPLOAD': None,
            'RUN': None,
            'BROADCAST': None,
            'NEW': None,
            'PING': None,
            'LIST': None,
        }

        # add command prefix #
        reqList = cmd.upper().split(':')
        if reqList[0] in requestList:
            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(msg.strip('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,)
        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(
                "fail 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()

            # connect with handling CLOSE_WAIT #
            while 1:
                try:
                    connObj.connect()
                    break
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printWarn(
                        "fail to connect to %s:%s" % (ip, port),
                            reason=True, always=verb)
                    et, err, to = sys.exc_info()
                    if err.args and err.args[0] == 99:
                        time.sleep(0.1)
                        continue
                    else:
                        raise Exception(err.args[0])

            return connObj
        except SystemExit:
            sys.exit(0)
        except:
            if verb:
                SysMgr.printErr(
                    "fail 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 len(addrList[0]) > 0:
                    ip = addrList[0]
                if len(addrList[1]) > 0:
                    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):
        # 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 not port:
            port = SysMgr.defaultPort

        # 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 "
                "with %s:%s") % (ip, port))
            sys.exit(0)

        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(0)

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

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

        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(0)

        if not port:
            port = SysMgr.defaultPort

        networkObject = NetworkMgr('client', ip, port)
        if not networkObject.ip:
            sys.exit(0)
        else:
            networkObject.status = 'ALWAYS'
            networkObject.request = service
            naddr = '%s:%s' % (ip, str(port))

            if service == 'PRINT':
                SysMgr.addrListForPrint[naddr] = networkObject
            elif service.startswith('REPORT_'):
                SysMgr.reportEnable = True
                SysMgr.addrListForReport[naddr] = networkObject
            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):

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

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

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

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

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

        if tcp:
            proto = 'TCP'
        else:
            proto = 'UDP'

        SysMgr.localServObj = networkObject
        SysMgr.printInfo(
            "use %s:%d(%s) as local address" % \
            (SysMgr.localServObj.ip,
                SysMgr.localServObj.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 getRepMacAddr():
        dirPath = '/sys/class/net'

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

        for dev in devices:
            if dev == 'lo':
                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():
        effectiveList = {}
        connPaths = \
            ['%s/net/udp' % SysMgr.procPath,
            '%s/net/tcp' % SysMgr.procPath]

        for path in connPaths:
            try:
                with open(path, 'r') as fd:
                    ipList = fd.readlines()

                # remove title #
                ipList.pop(0)

                for line in ipList:
                    items = line.split()
                    ip = SysMgr.convertCIDR(items[1].split(':')[0])
                    effectiveList[ip] = None
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenWarn(path)

        return list(effectiveList.keys())



    @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.keys())



    @staticmethod
    def getMainIp():
        ipList = {}

        ipList = NetworkMgr.getUsingIps()

        # remove invaild ip #
        try:
            ipList.remove('0.0.0.0')
        except:
            pass

        if not ipList or 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.convertCIDR(items[1])])

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



    @staticmethod
    def getPublicIp():
        # 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("fail to get public IP address")

        if not ret:
            ret = NetworkMgr.getMainIp()

        return ret



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





class Timeline(object):
    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._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"]



    class Config(object):
        def _conv_palette(self, palette):
            # get svgwrite object #
            svgwrite = SysMgr.getPkg('svgwrite')

            plist = []
            for palette_entry in palette:
                rgb = [int(rgb_value) for rgb_value in \
                    re.findall("\d+", palette_entry)]
                plist.append(svgwrite.rgb(rgb[0], rgb[1], rgb[2]))
            return plist

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

            # set font size #
            if 'FONTSIZE' in SysMgr.environList:
                try:
                    val = SysMgr.environList['FONTSIZE'][0]
                    self.FONT_SIZE = long(val)
                except:
                    SysMgr.printErr(
                        "fail to set font size to '%s'" % val, True)
                    sys.exit(0)
            else:
                self.FONT_SIZE = 3

            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(file_name=None, data=None):
            if file_name:
                with open(file_name) as fd:
                    data = fd.read()
                    data = UtilMgr.convStr2Dict(data)
            elif not data:
                SysMgr.printErr('no path or data for timeline config')
                sys.exit(0)

            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.LABEL_SIZE_MIN = data.get("label_size_min", 5)
            config.PALETTE = config._conv_palette(data.get("palette", []))
            config.TIMEUNIT = data.get("time_unit", None)
            config.TIMEFACTOR = data.get("time_factor", 1)

            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 = set(s.group for s in self.segments)
        self.groups = len(self.segment_groups)
        self.group_list = list(self.segment_groups)
        self.scaled_height = self.config.HEIGHT / self.groups

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

        self.tasks = tasks
        self.last_group_segment = dict()
        self.last_group_time = dict()
        self.height_group_pos = dict()
        self.last_iogroup_segment = dict()
        self.last_iogroup_time = dict()
        self.height_iogroup_pos = dict()

        # 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 range(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_axis(self, dwg):
        dwg.add(dwg.rect(
            (0, 0),
            (self.config.TIME_AXIS_HEIGHT, self.config.HEIGHT), fill='black'))

        idx = 0
        groupList = list(self.segment_groups)
        for y_tick in range(0, 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=0.1))

            dwg.add(dwg.text(
                name, (self.config.FONT_SIZE, y_tick+self.scaled_height),
                font_size=self.scaled_height/2,
                fill='rgb(220,220,220)'))



    def _draw_time_axis(self, dwg):
        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

        for x_tick_time in range(0, self.config.WIDTH, self.config.TICKS):
            tick_time = "{:10}".format(long(x_tick_time * (1 / self.ratio)))
            dwg.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 Chart'

        # 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(230,230,230)'))



    def _draw_segments(self, dwg):
        for idx, segment in enumerate(self.segments):
            UtilMgr.printProgress(idx, len(self.segments))
            self._draw_segment(segment, dwg)
        UtilMgr.deleteProgress()



    def _draw_segment(self, segment, dwg):
        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)

        # 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[colorid]
            except:
                color = self.color_map[list(self.color_map.keys())[0]]

        # draw bold line for core off #
        if segment.state == 'OFF':
            dwg.add(dwg.line(
                (x0, y0), (x1, y0),
                stroke='black', stroke_width=1.5))
            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

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

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

        # check duration #
        duration = segment.time_end - segment.time_start
        if not SysMgr.showAll and \
            (scaled_width < self.config.LABEL_SIZE_MIN or duration == 0):
            return

        # convert duration to text #
        if duration == 0:
            duration = '~'
        else:
            duration = '~%s' % (UtilMgr.convNum(duration))

        # 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 = duration
                    font_size = self.config.FONT_SIZE - 1
                else:
                    segment_label = "> %s | %s" % (segment.text, duration)
                    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 = duration
                    font_size = self.config.FONT_SIZE - 1
                else:
                    segment_label = "> %s | %s" % (segment.text, duration)
                    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 #
        else:
            # 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 = duration
                color = 'rgb(50,50,50)'
                font_size = self.config.FONT_SIZE - 1
            # set text attributes for new task #
            else:
                segment_label = "> %s | %s" % (segment.text, duration)
                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

        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):
        self._draw_background(dwg)
        self._draw_grid(dwg)
        self._draw_group_axis(dwg)
        self._draw_time_axis(dwg)
        self._draw_segments(dwg)



    @staticmethod
    def load(file_name=None, data=None, config=None, tasks=None):
        if file_name:
            with open(file_name) 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(0)

        # 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 title #
        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 == 'ns':
                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 == 'ns':
                    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

        if time_unit:
            SysMgr.printInfo(
                "apply '%s' in timeunit" % time_unit)

        # load segments #
        segments = Timeline._load_segments(data, time_factor)

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



    @staticmethod
    def _load_segments(data, time_factor=1):
        segments = []
        for segment_data in sorted(
            data["segments"], key=lambda e: e['time_start']):
            # apply core filter #
            if SysMgr.perCoreDrawList:
                if not segment_data['group'] 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

            time_start = long(segment_data["time_start"] * time_factor)
            time_end = long(segment_data["time_end"] * time_factor)

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

        return segments





'''
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(
                "fail to load GLES object")
            sys.exit(0)

        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):
        try:
            if not pid:
                raise Exception('no pid')
            elif type(pid) is not list or len(pid) != 1:
                raise Exception('wrong pid')

            pids = SysMgr.getPids(pid[0], isThread=False)
            if not pid:
                raise Exception('no task')
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "fail to recognize target", reason=True)
            sys.exit(0)

        for pid in sorted(pids):
            comm = SysMgr.getComm(pid)

            if not vaddr:
                PageAnalyzer.printMemoryArea(
                    pid, comm=comm, showall=SysMgr.showAll)
                SysMgr.printPipe(oneLine)
                continue

            SysMgr.checkRootPerm()

            vrange = vaddr.split('-')
            rangeCnt = len(vrange)

            if rangeCnt > 2:
                SysMgr.printErr(
                    "fail to recognize address, "
                    "input address such as 102400 or 0x1234a-0x123ff")
                sys.exit(0)
            else:
                try:
                    if vrange[0].startswith("0x"):
                        addrs = long(vrange[0], base=16)
                        addre = addrs
                    else:
                        addrs = long(vrange[0])
                        addre = addrs
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(
                        "fail to recognize address, "
                        "input address such as 0xabcd or 78901234")
                    sys.exit(0)

                try:
                    if rangeCnt == 2:
                        if vrange[1].startswith("0x"):
                            addre = long(vrange[1], base=16)
                        else:
                            addre = long(vrange[1])

                        offset = long(0)
                    else:
                        offset = SysMgr.pageSize

                    if addrs > addre:
                        SysMgr.printErr(
                            "fail to recognize address, "
                            "input bigger second address than first address")
                        sys.exit(0)
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(
                        "fail to recognize address, "
                        "input address such as 0x1234-0x4444")
                    sys.exit(0)

            SysMgr.printPipe(
                "\n[ TASK: %s(%s) ] [ AREA: %s ] [ HELP: %s ]" % \
                    (comm, pid, vaddr, "kernel/Documentation/vm/pagemap.txt"))

            PageAnalyzer.printMemoryArea(pid, addrs, addre)
            SysMgr.printPipe(twoLine)

            SysMgr.printPipe((
                "{0:^18}|{1:^16}|{2:^9}|{3:^6}|{4:^6}|{5:^5}|"
                "{6:^8}|{7:^7}| {8}({9})\n{10}").\
                format("VADDR", "PFN", "PRESENT", "SWAP", "FILE", "REF",
                "SDRT", "EXMAP", "FLAG", "FLAGS", oneLine))

            for addr in range(addrs, addre + offset, SysMgr.pageSize):
                entry = PageAnalyzer.getPagemapEntry(pid, addr)

                pfn = PageAnalyzer.getPfn(entry)

                isPresent = PageAnalyzer.isPresent(entry)

                isSwapped = PageAnalyzer.isSwapped(entry)

                isSoftdirty = PageAnalyzer.isSoftdirty(entry)

                isExmapped = PageAnalyzer.isExmapped(entry)

                isFile = PageAnalyzer.isFilePage(entry)

                bflags = hex(PageAnalyzer.getPageFlags(pfn)).rstrip('L')

                sflags = PageAnalyzer.getFlagTypes(bflags)

                SysMgr.printPipe((
                    "{0:^18}|{1:^16}|{2:^9}|{3:^6}|{4:^6}|{5:^5}|"\
                    "{6:^8}|{7:^7}| {8}({9} )").format(
                    hex(addr).rstrip('L'), hex(pfn).rstrip('L'), isPresent,
                    isSwapped, isFile,PageAnalyzer.getPagecount(pfn),
                    isSoftdirty, isExmapped, bflags, sflags))

            SysMgr.printPipe("%s\n" % oneLine)



    @staticmethod
    def printMemoryArea(
        pid, start=-1, end=-1, comm=None, lastLine=False, showall=True):

        count = long(0)
        switch = long(0)
        fpath = '%s/%s/maps' % (SysMgr.procPath, pid)

        if start == end == -1 and not showall:
            printSummary = True
        else:
            printSummary = False

        # read all map info #
        try:
            # summary #
            if printSummary:
                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(0)

        if start == end == -1:
            if not comm:
                comm = SysMgr.getComm(pid)

            # get mem stat #
            convert = UtilMgr.convSize2Unit
            mlist = SysMgr.getMemStat(pid)
            vssIdx = ConfigMgr.STATM_TYPE.index("TOTAL")
            vss = convert(long(mlist[vssIdx]) << 12)
            rssIdx = ConfigMgr.STATM_TYPE.index("RSS")
            rss = convert(long(mlist[rssIdx]) << 12)
            SysMgr.printPipe(
                "\n[ TASK: %s(%s) ] [ VSS: %s ] [ RSS: %s ]" % \
                    (comm, pid, vss, rss))

        start = hex(start)
        end = hex(end)
        all = hex(-1)

        # print menu #
        menuStr = ''
        if printSummary:
            menuList = \
                ['AREA', 'PERM', '%8s' % 'OFFSET', '%6s' % 'DEV', '%7s' % 'INODE']
            menuBuf = menuList
        else:
            menuList = ['AREA', 'PERM', 'OFFSET', 'DEV', '%12s' % 'INODE']
            menuBuf = str(buf[-1]).split()

        for idx, value in enumerate(menuBuf):
            if idx < 5:
                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 = '%s %s' % (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 printSummary:
            for fname, info in sorted(buf.items(),
                key=lambda e: e[1]['vstart']):
                try:
                    soffset = hex(info['vstart']).rstrip('L')
                    eoffset = hex(info['vend']).rstrip('L')
                    if not fname.startswith('/'):
                        fname = '[%s]' % fname
                    SysMgr.printPipe('%18s %18s %4s %8s %6s %7s %s' % \
                        (soffset, eoffset, info['perm'], info['offset'],\
                        info['devid'], info['inode'], fname))
                except SystemExit:
                    sys.exit(0)
                except:
                    pass
            return

        # print all map info #
        for line in buf:
            tmplist = line.split()
            soffset, eoffset = tmplist[0].split('-')

            if start == end == all:
                switch = long(0)
            elif '-' in line:
                soffset = hex(long(soffset, base=16))
                eoffset = hex(long(eoffset, base=16))

                if (start >= soffset and start < eoffset):
                    switch = 1
                elif switch == 0:
                    continue
                elif end < eoffset:
                    break

            try:
                target = line[:-1].split()

                target[4] = '%12s' % target[4]

                if not soffset.startswith('0x'):
                    soffset = '0x%s' % soffset

                if not eoffset.startswith('0x'):
                    eoffset = '0x%s' % eoffset

                SysMgr.printPipe('%18s %18s %s' % \
                    (soffset, eoffset, ' '.join(target[1:])))
            except SystemExit:
                sys.exit(0)
            except:
                pass

            count += 1

            if switch == 1 and end <= eoffset:
                break

        if count == 0:
            SysMgr.printPipe('no involved memory area')
        elif 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 = "%s%s|" % (sflags, val[4:])

        return sflags[:-1]



    @staticmethod
    def readEntry(path, offset, size=8):
        with open(path, 'rb') as f:
            f.seek(offset, 0)
            try:
                return struct.unpack('Q', f.read(size))[0]
            except:
                SysMgr.printErr(
                    "fail to read %s byte from %s of %s" % \
                    (size, offset, path))
                sys.exit(0)



    @staticmethod
    def getPagemapEntry(pid, addr):
        maps_path = "{0}/{1}/pagemap".format(SysMgr.procPath, pid)
        if not os.path.isfile(maps_path):
            SysMgr.printErr("fail to find %s process" % pid)
            sys.exit(0)

        pageSize = os.sysconf("SC_PAGE_SIZE")
        pagemap_entry_size = 8
        offset = long(addr / pageSize) * pagemap_entry_size

        return PageAnalyzer.readEntry(maps_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):
        file_path = "%s/kpagecount" % SysMgr.procPath
        offset = pfn * 8
        return PageAnalyzer.readEntry(file_path, offset)



    @staticmethod
    def getPageFlags(pfn):
        file_path = "%s/kpageflags" % SysMgr.procPath
        offset = pfn * 8
        return PageAnalyzer.readEntry(file_path, offset)





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 = long(0)
        self.totalTick = long(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 = long(0)
        self.savedCnt = long(0)
        self.nestedCnt = long(0)
        self.nowArg = long(0)
        self.savedArg = long(0)
        self.nestedArg = long(0)

        self.duplicatedPos = long(0)
        self.periodicEventCnt = long(0)
        self.periodicContEventCnt = long(0)
        self.periodicEventInterval = long(0)
        self.heapExpEventCnt = long(0)
        self.heapExpSize = long(0)
        self.heapRedEventCnt = long(0)
        self.heapRedSize = long(0)
        self.pageAllocEventCnt = long(0)
        self.pageAllocCnt = long(0)
        self.pageFreeEventCnt = long(0)
        self.pageFreeCnt = long(0)
        self.pageUnknownFreeCnt = long(0)
        self.pageUsageCnt = long(0)
        self.blockRdEventCnt = long(0)
        self.blockRdUsageCnt = long(0)
        self.blockWrEventCnt = long(0)
        self.blockWrUsageCnt = long(0)
        self.lockTryEventCnt = long(0)
        self.unlockEventCnt = long(0)
        self.customCnt = long(0)
        self.customTotal = long(0)
        self.syscallCnt = long(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': long(0),
            'die': False, 'new': False, 'nrPages': long(0), 'userPages': long(0),
            'cachePages': long(0), 'kernelPages': long(0), 'heapSize': long(0),
            'eventCnt': long(0), 'nrWrBlocks': long(0), 'customCnt': long(0),
            'nrUnknownFreePages': long(0), 'nrKnownFreePages': long(0),
            'nrRdBlocks': long(0), 'nrLockTry': long(0), 'nrUnlock': long(0),
            'customTotal': long(0), 'nrSyscall': long(0), 'syscallTable': None,
            'lastNrSyscall': long(-1)}

        self.init_posData = \
            {'symbol': '', 'binary': '', 'origBin': '', 'offset': hex(0),
            'posCnt': long(0), 'userPageCnt': long(0), 'cachePageCnt': long(0),
            'kernelPageCnt': long(0), 'totalCnt': long(0), 'blockRdCnt': long(0),
            'blockWrCnt': long(0), 'pageCnt': long(0), 'heapSize': long(0),
            'unknownPageFreeCnt': long(0), 'src': '', 'customCnt': long(0),
            'customTotal': long(0), 'lockTryCnt': long(0), 'unlockCnt': long(0),
            'syscallCnt': long(0)}

        self.init_symData = \
            {'pos': '', 'origBin': '', 'tickCnt': long(0), 'blockRdCnt': long(0),
            'pageCnt': long(0), 'unknownPageFreeCnt': long(0), 'stack': None,
            'symStack': None, 'userPageCnt': long(0), 'cachePageCnt': long(0),
            'kernelPageCnt': long(0), 'heapSize': long(0), 'blockWrCnt': long(0),
            'customCnt': long(0), 'customTotal': long(0), 'pagePair': None,
            'pagePairCnt': long(0), 'pagePairTotal': float(0),
            'pagePairMin': float(0), 'pagePairMax': float(0),
            'pagePairAvr': float(0), 'pageRemainMin': float(0),
            'pageRemainMax': float(0), 'pageRemainAvr': float(0),
            'pageRemainTotal': float(0), 'lockTryCnt': long(0),
            'unlockCnt': long(0), 'syscallCnt': long(0), 'totalTickCnt': long(0)}

        self.init_ctxData = \
            {'nestedEvent': None, 'savedEvent': None, 'nowEvent': None,
            'nested': long(0), 'recStat': False, 'nestedCnt': long(0),
            'savedCnt': long(0), 'nowCnt': long(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': long(0), 'ksym': '0',
            'ksubStackAddr': long(0), 'type': '0', 'time': '0'}

        self.init_heapSegData = \
            {'tid': '0', 'size': long(0), 'sym': '0',
            'subStackAddr': long(0), 'ksym': '0', 'ksubStackAddr': long(0),
            'time': float(0), 'core': '0'}

        self.init_pageData = \
            {'tid': '0', 'page': '0', 'flags': '0', 'type': '0', 'time': '0'}

        self.init_glueData = \
            {'count': long(0), 'size': long(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 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) ]')

        self.parseLogs(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(0)
        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(
                "fail 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 range(0, pageFreeCnt):
            pfnv = pfn + cnt
            subStackPageInfoIdx = long(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 = long(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 = long(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 = long(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 range(0, pageAllocCnt):
            pfnv = pfn + cnt
            subStackPageInfoIdx = long(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 = long(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 = long(0)
        kstackAddr = long(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 = long(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 kenel 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 not list(stackSet - subStackSet) and \
                        not list(subStackSet - stackSet):
                        found = True

                        stackInfo[eventIndex] += eventCnt
                        stackAddr = id(stackInfo[subStackIndex])

                        break

                # New stack related to this symbol #
                if found == False:
                    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 not list(kerStackSet - kerSubStackSet) and \
                        not list(kerSubStackSet - kerStackSet):
                        found = True
                        stackInfo[eventIndex] += eventCnt
                        kstackAddr = id(stackInfo[subStackIndex])
                        break

                # New stack related to this symbol #
                if found == False:
                    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("fail 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(0)

        # 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 = long(0)
        nrNoFile = long(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'])

        # Get symbols and source path from last binary #
        if binPath != '':
            if self.getFileSymbolInfo(binPath, offsetList) == -1:
                nrNoFile += 1

        UtilMgr.deleteProgress()

        if nrNoFile > 0:
            SysMgr.printWarn(
                "fail 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(
                        "fail 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 = list()
                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(
                    "fail to get symbol from %s" % binPath, True)

            return None

            # get system addr2line path #
            addr2linePath = UtilMgr.which('addr2line')

            if not addr2linePath:
                SysMgr.printErr((
                    "fail to find addr2line to analyze user-level functions, "
                    "use -q option with ADDR2LINE to set binary path"))
                sys.exit(0)

            SysMgr.printInfo(
                "use %s as addr2line path" % ', '.join(addr2linePath))
        else:
            for path in SysMgr.environList['ADDR2LINE']:
                if not os.path.isfile(path):
                    SysMgr.printErr(
                        "fail to find %s to use addr2line" % path)
                    sys.exit(0)

        # get subprocess object #
        subprocess = SysMgr.getPkg('subprocess')
        if not subprocess:
            sys.exit(0)

        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 = long(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(
                        "fail to execute %s to pick symbols from binary" % \
                            path)
                    sys.exit(0)

                # 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 len(err) > 0:
                        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(
                "fail to save full stacks", True)
            sys.exit(0)



    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'] = long(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(
                'fail 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(
                'fail to set address of heap segment %s of %s(%s) at %s' % \
                    (addr, self.threadData[tid]['comm'], tid,
                    SysMgr.dbgEventLine))



    def parseLogs(self, lines, desc):
        curIdx = long(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']] = long(0)

        # start parsing logs #
        for liter in lines:
            curIdx += 1
            SysMgr.logSize += len(liter)
            SysMgr.curLine += 1
            SysMgr.dbgEventLine += 1

            ret = self.parseEventLog(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)

        # update finish time #
        if self.finishTime == '0':
            self.finishTime = self.lastTime

        UtilMgr.deleteProgress()

        # Save stack of last events per core #
        for idx in list(self.coreCtx.keys()):
            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((
                "fail to analyze stack data "\
                "because of corruption (overflow) at %s line\n"\
                "\tso report 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 len(self.customEventTable) > 0 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 range(0, 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(
                    "fail 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 range(0, 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("fail 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()

                nr = b['nr']

                self.threadData[tid]['lastNrSyscall'] = long(nr)

                # syscall event #
                if SysMgr.sysEnable:
                    self.sysEnabled = True

                    nrSyscall = long(b['nr'])
                    syscallList = SysMgr.syscallList

                    if not syscallList or nrSyscall 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'][nrSyscall] += 1
                        except:
                            self.threadData[tid]['syscallTable'][nrSyscall] = 1

                        self.saveEventParam(
                            'SYSCALL', 1, [nrSyscall, args, time, core, tid])

                        return False

                # heap increasement event #
                elif long(b['nr']) == 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 long(b['nr']) == ConfigMgr.sysList.index('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 long(b['nr']) == ConfigMgr.sysList.index('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:]
                        flist = ConfigMgr.FUTEX_TYPE
                        try:
                            event = flist[maskedOp]
                        except:
                            event = 'LOCK'

                        # try to lock #
                        if maskedOp == flist.index("FUTEX_LOCK_PI") or \
                            maskedOp == flist.index("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 maskedOp == flist.index("FUTEX_WAIT") or \
                            maskedOp == flist.index("FUTEX_WAIT_REQUEUE_PI") or \
                            maskedOp == flist.index("FUTEX_WAIT_BITSET"):
                            self.lockEnabled = True

                            self.threadData[tid]['nrLockTry'] += 1

                            self.saveEventParam(
                                'LOCK_TRY', 1, [event, addr, time, core, tid])

                            return False
                        # try to unlock #
                        elif maskedOp == flist.index("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(
                    "fail 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 == ConfigMgr.sysList.index('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(
                    "fail 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*(?P<operation>\S+)\s*'
                r'(?P<address>\S+)\s+\+\s+(?P<size>[0-9]+)'), args)
            if m:
                b = m.groupdict()

                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("fail 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("fail 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]+) code=(?P<code>.*) '
                r'sa_handler=(?P<handler>.*) 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((
                    "fail to analyze stack data "
                    "because of corruption (underflow) at %s line\n"\
                    "\tso report results may differ from actual") % \
                    SysMgr.dbgEventLine, True)

            return True

        # custom event #
        elif not isFixedEvent:
            try:
                if len([event for event in self.customEventTable \
                    if event.endswith(func[:-1])]) == 0:
                    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] = dict()
                    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 parseEventLog(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

            # 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

            # 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(
            "fail to get the binary info of %s in mapping table" % addr)



    def printSyscallSummary(self):
        # no effective syscall event #
        if self.syscallCnt == 0:
            return

        convertNum = UtilMgr.convNum

        SysMgr.clearPrint()
        SysMgr.printPipe(
            '[Function Syscall Info] [Cnt: %s]' % \
            convertNum(self.syscallCnt))
        SysMgr.printPipe(twoLine)
        SysMgr.printPipe(
            '{0:>16}({1:>7}/{2:>7}) {3:>30}({4:>3}) {5:>12}'.format(
            "Name", "TID", "PID", "Syscall", "SID", "Count"))
        SysMgr.printPipe(twoLine)

        outputCnt = long(0)
        for key, value in sorted(self.threadData.items(),
            key=lambda e: e[1]['nrSyscall'], reverse=True):
            threadInfo = ''
            syscallInfo = ''

            if key[0:2] == '0[':
                continue

            try:
                if len(value['syscallTable']) > 0:
                    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(
                        "fail to get syscall name by number %s" % sysId)
                    syscall = sysId

                syscallInfo = \
                    ('{0:1} {1:>30}({2:>3}) {3:>12}\n').format(
                    '%s%s' % (syscallInfo, ' ' * len(threadInfo)),
                    syscall, sysId, convertNum(val))

            if syscallInfo != '':
                outputCnt += 1
                SysMgr.printPipe(threadInfo)
                SysMgr.printPipe('%s%s' % (syscallInfo, oneLine))

        if outputCnt == 0:
            SysMgr.printPipe('\tNone\n%s' % oneLine)

        SysMgr.printPipe('\n\n')



    def printUsage(self):
        targetCnt = long(0)
        self.totalTime = \
            float(self.finishTime) - float(SysMgr.startTime)

        convertFunc = UtilMgr.convSize2Unit
        convertNum = 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 ]" % \
            ('Function Thread Info', 'Elapsed', round(self.totalTime, 7),
            'Start', round(float(SysMgr.startTime), 7),
             len(self.threadData), convertFunc(SysMgr.logSize)))
        SysMgr.printPipe(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}|{1:^7}|{2:^7}|{3:^6}|{4:^6}|{5:^7}|"
            "{6:^9}{7:^8}{8:^8}{9:^12}|{10:^8}|{11:^7}|{12:^8}|"
            "{13:^8}|{14:^9}|{15:^6}|{16:^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' % convertNum(value['nrSyscall'])
            elif self.heapEnabled:
                cval = '%s' % convertFunc(value['heapSize'])
            else:
                cval = '-'

            if self.memEnabled:
                allocMem = '%s' % convertFunc(value['nrPages'] << 12)
                userMem = '%s' % convertFunc(value['userPages'] << 12)
                cacheMem = '%s' % convertFunc(value['cachePages'] << 12)
                kernelMem = '%s' % convertFunc(value['kernelPages'] << 12)
                knownFreeMem = '%s' % \
                    convertFunc(value['nrKnownFreePages'] << 12)
                unknownFreeMem = '%s' % \
                    convertFunc(value['nrUnknownFreePages'] << 12)
            else:
                allocMem = '-'
                userMem = '-'
                cacheMem = '-'
                kernelMem = '-'
                knownFreeMem = '-'
                unknownFreeMem = '-'

            if self.breadEnabled:
                readBlock = '%s' % convertFunc(value['nrRdBlocks'] << 9)
            else:
                readBlock = '-'

            if self.bwriteEnabled:
                writeBlock = '%s' % convertFunc(value['nrWrBlocks'] << 9)
            else:
                writeBlock = '-'

            if self.lockEnabled:
                nrLock = convertNum(value['nrLockTry'])
            else:
                nrLock = '-'

            if self.customTotal > 0:
                nrCustom = convertNum(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, indentLen):
        symbolStack = ''
        stackIdx = long(0)
        appliedIndentLen = indentLen

        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 = appliedIndentLen + \
                    len(symbolStack[stackIdx:]) + len(symbolSet)
                if symbolStack != '' and lpos > SysMgr.lineLength:
                    stackIdx = len(symbolStack)
                    symbolStack = '%s\n%s' % (symbolStack, ' ' * indentLen)
                    appliedIndentLen = long(0)

                symbolStack = '%s%s' % (symbolStack, symbolSet)
        except SystemExit:
            sys.exit(0)
        except:
            pass

        return symbolStack



    def makeUserSymList(self, subStack, indentLen):
        symbolStack = ''
        stackIdx = long(0)
        appliedIndentLen = indentLen

        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 = appliedIndentLen + \
                    len(symbolStack[stackIdx:]) + len(symbolSet)
                if symbolStack != '' and lpos > SysMgr.lineLength:
                    stackIdx = len(symbolStack)
                    symbolStack = \
                        '%s\n%s' % (symbolStack, ' ' * indentLen)
                    appliedIndentLen = long(0)

                symbolStack = '%s%s' % (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')
        convertNum = UtilMgr.convNum

        # Print syscall event #
        SysMgr.clearPrint()
        SysMgr.printPipe(
            '[Function Syscall Info] [Cnt: %s] (USER)' % \
            convertNum(self.syscallCnt))

        SysMgr.printPipe(twoLine)
        SysMgr.printPipe("{0:_^9}|{1:_^47}|{2:_^49}|{3:_^46}".\
            format("Usage", "Function", "Binary", "Source"))
        SysMgr.printPipe(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(
                convertNum(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:
                    indentLen = len("\t" * 4 * 4) + 3
                    symbolStack = self.makeUserSymList(subStack, indentLen)

                SysMgr.printPipe(
                    "\t\t +{0:>7} |{1:32}".format(
                    convertNum(eventCnt), symbolStack))

            SysMgr.printPipe(oneLine)

        SysMgr.printPipe()

        # Print syscall file #
        SysMgr.printPipe(
            '[Function Syscall File Info] [Cnt: %s] (USER)' % \
            convertNum(self.syscallCnt))

        SysMgr.printPipe(twoLine)
        SysMgr.printPipe("{0:_^9}|{1:_^144}".\
            format("Usage", "Binary"))
        SysMgr.printPipe(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}".format(
                convertNum(value['syscallCnt']), idx))

            SysMgr.printPipe(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]' % \
            convertNum(self.syscallCnt))

        SysMgr.printPipe(twoLine)
        SysMgr.printPipe(
            "{0:_^32}|{1:_^17}({2:_^7})|{3:_^8}|{4:_^17}|".\
            format("Event", "COMM", "TID", "CORE", "TIME"))
        SysMgr.printPipe(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 #
            indentLen = 32
            nowLen = indentLen
            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 = '%s%s' % (userCall, nextCall)
                            nowLen += len(nextCall)
                        else:
                            userCall = '%s\n%s %s' % \
                                (userCall, ' ' * indentLen, nextCall)
                            nowLen = indentLen + 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(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')
        convertNum = UtilMgr.convNum

        # Make custom event list #
        customList = ', '.join(list(self.customEventTable.keys()))

        # Print custom event in user space #
        if SysMgr.userEnable:
            SysMgr.clearPrint()
            SysMgr.printPipe(
                '[Function %s Info] [Cnt: %s] [Total: %s] (USER)' % \
                (customList, convertNum(self.customTotal),
                convertNum(self.customCnt)))

            SysMgr.printPipe(twoLine)
            SysMgr.printPipe("{0:_^9}|{1:_^47}|{2:_^49}|{3:_^46}".\
                format("Usage", "Function", "Binary", "Source"))
            SysMgr.printPipe(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(
                    convertNum(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:
                        indentLen = len("\t" * 4 * 4) + 3
                        symbolStack = self.makeUserSymList(subStack, indentLen)

                    SysMgr.printPipe(
                        "\t\t +{0:>7} |{1:32}".format(
                        convertNum(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)' % \
                (customList, convertNum(self.customTotal),
                convertNum(self.customCnt)))

            SysMgr.printPipe(twoLine)
            SysMgr.printPipe("{0:_^9}|{1:_^144}".\
                format("Usage", "Binary"))
            SysMgr.printPipe(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}".format(
                    convertNum(value['customCnt']), idx))

                SysMgr.printPipe(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)' % \
            (customList, convertNum(self.customTotal),
            convertNum(self.customCnt)))

        SysMgr.printPipe(twoLine)
        SysMgr.printPipe(
            "{0:_^9}|{1:_^144}".format("Usage", "Function"))
        SysMgr.printPipe(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(
                convertNum(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:
                    indentLen = len("\t" * 4 * 4) + 3
                    symbolStack = self.makeKernelSymList(subStack, indentLen)

                SysMgr.printPipe(
                    "\t\t +{0:>7} |{1:32}".format(
                    convertNum(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]' % \
            (customList, convertNum(self.customTotal),
            convertNum(self.customCnt)))

        SysMgr.printPipe(twoLine)
        SysMgr.printPipe(
            "{0:_^32}|{1:_^17}({2:_^7})|{3:_^8}|{4:_^17}|".\
            format("Event", "COMM", "TID", "CORE", "TIME"))
        SysMgr.printPipe(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 #
            indentLen = 32
            nowLen = indentLen
            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 = '%s%s' % (userCall, nextCall)
                            nowLen += len(nextCall)
                        else:
                            userCall = '%s\n%s %s' % \
                                (userCall, ' ' * indentLen, nextCall)
                            nowLen = indentLen + len(nextCall)
                    except:
                        pass
            except SystemExit:
                sys.exit(0)
            except:
                pass

            # Make kernel call info #
            indentLen = 32
            nowLen = indentLen
            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 = '%s%s' % (kernelCall, nextCall)
                            nowLen += len(nextCall)
                        else:
                            kernelCall = \
                                '%s\n%s %s' % \
                                (kernelCall, ' ' * indentLen, nextCall)
                            nowLen = indentLen + 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}".format('[Kernel] ', kernelCall))
            SysMgr.printPipe(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(twoLine)
            SysMgr.printPipe("{0:_^9}|{1:_^47}|{2:_^96}".\
                format("Usage", "Function", "Binary"))
            SysMgr.printPipe(twoLine)

            for idx, value in sorted(self.userSymData.items(),
                key=lambda e: e[1]['tickCnt'], reverse=True):

                if value['tickCnt'] == 0:
                    break

                cpuPer = \
                    round(float(value['tickCnt']) / \
                    float(self.periodicEventCnt) * 100, 1)
                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 = \
                            round(float(cpuCnt) / float(value['tickCnt']) * 100, 1)
                        if cpuPer < 1 and not SysMgr.showAll:
                            break

                        indentLen = len("\t" * 4 * 4)
                        symbolStack = self.makeUserSymList(subStack, indentLen)

                    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)' % \
                (title, tCnt, self.periodicEventInterval * 1000))

            SysMgr.printPipe(twoLine)
            SysMgr.printPipe("{0:_^9}|{1:_^47}|{2:_^96}".\
                format("Usage", "Function", "Binary"))
            SysMgr.printPipe(twoLine)

            for idx, value in sorted(self.userSymData.items(),
                key=lambda e: e[1]['totalTickCnt'], reverse=True):

                if value['totalTickCnt'] == 0:
                    break

                cpuPer = \
                    round(float(value['totalTickCnt']) / \
                    float(self.periodicEventCnt) * 100, 1)
                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']))

                SysMgr.printPipe(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)' % \
                (title, tCnt, self.periodicEventInterval * 1000))

            SysMgr.printPipe(twoLine)
            SysMgr.printPipe("{0:_^9}|{1:_^144}".\
                format("Usage", "Binary"))
            SysMgr.printPipe(twoLine)

            for idx, value in sorted(self.userFileData.items(),
                key=lambda e: e[1]['tickCnt'], reverse=True):

                if value['tickCnt'] == 0:
                    break

                cpuPer = \
                    round(float(value['tickCnt']) / \
                    float(self.periodicEventCnt) * 100, 1)
                if cpuPer < 1 and not SysMgr.showAll:
                    break

                SysMgr.printPipe(
                    "{0:7.1f}% | {1:<142}".format(cpuPer, idx))

                SysMgr.printPipe(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()
        SysMgr.printPipe(
            '[%s] [Cnt: %s] [Interval: %dms] (KERNEL)' % \
            (title, tCnt, self.periodicEventInterval * 1000))

        SysMgr.printPipe(twoLine)
        SysMgr.printPipe(
            "{0:_^9}|{1:_^144}".format("Usage", "Function"))
        SysMgr.printPipe(twoLine)

        # 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, dict())

        # 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.keys()):
                        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:
                    indentLen = 10
                    symbolStack = self.makeKernelSymList(subStack, indentLen)

                try:
                    mergedSymbolChain[symbolStack] += cpuCnt
                except:
                    mergedSymbolChain[symbolStack] = cpuCnt

            # Print stacks by symbol #
            for chain, tick in sorted(
                mergedSymbolChain.items(), key=lambda e:e[1], reverse=True):
                cpuPer = \
                    round(tick / float(value['tickCnt']) * 100, 1)
                if cpuPer < 1 and not SysMgr.showAll:
                    break

                SysMgr.printPipe(
                    "{0:7.1f}% |{1:32}".format(cpuPer, chain))

            SysMgr.printPipe(oneLine)

            if self.periodicEventCnt == 0:
                SysMgr.printPipe('\tNone\n%s' % oneLine)

        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')
        convertFunc = UtilMgr.convSize2Unit
        size = convertFunc(self.pageUnknownFreeCnt << 12)

        if SysMgr.userEnable:
            # Print memory reduce by page free in user space #
            SysMgr.clearPrint()
            SysMgr.printPipe('[%s] [Size: %s] (USER)' % (title, size))

            SysMgr.printPipe(twoLine)
            SysMgr.printPipe("{0:_^9}|{1:_^47}|{2:_^49}|{3:_^46}".\
                format("Free", "Function", "Binary", "Source"))
            SysMgr.printPipe(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(convertFunc(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:
                        indentLen = len("\t" * 4 * 4)
                        symbolStack = self.makeUserSymList(subStack, indentLen)

                    SysMgr.printPipe("\t+ {0:>8} |{1:32}".\
                        format(convertFunc(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)' % (title, size))

        SysMgr.printPipe(twoLine)
        SysMgr.printPipe("{0:_^9}|{1:_^144}".format("FREE", "Function"))
        SysMgr.printPipe(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(convertFunc(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:
                    indentLen = len("\t" * 4 * 4)
                    symbolStack = self.makeKernelSymList(subStack, indentLen)

                SysMgr.printPipe("\t+ {0:>8} |{1:32}".\
                    format(convertFunc(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
        convertFunc = UtilMgr.convSize2Unit
        size = convertFunc(diff << 12)

        # Print page alloc-free pair in user space #
        if SysMgr.userEnable:
            SysMgr.clearPrint()
            SysMgr.printPipe('[%s] [Total: %s] (USER)' % (title, size))

            SysMgr.printPipe(twoLine)
            SysMgr.printPipe(
                "{0:^7}({1:^6}/{2:^6}/{3:^6})|{4:_^47}|{5:_^40}|{6:_^35}".\
                format("Usage", "Usr", "Buf", "Ker", "Function",
                "LifeTime", "Binary"))
            SysMgr.printPipe(twoLine)

            for idx, value in sorted(self.userSymData.items(),
                key=lambda e: e[1]['pagePairCnt'], reverse=True):

                if value['pagePairCnt'] == 0:
                    break

                typeList = \
                    {'USER': long(0), 'KERNEL': long(0), 'CACHE': long(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 = long(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(convertFunc(value['pagePairCnt'] << 12),
                    convertFunc(typeList['USER'] << 12),
                    convertFunc(typeList['CACHE'] << 12),
                    convertFunc(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 = long(0)
                    try:
                        cachePages = item['valueList']['CACHE']
                    except:
                        cachePages = long(0)
                    try:
                        kernelPages = item['valueList']['KERNEL']
                    except:
                        kernelPages = long(0)

                    # get user alloc and free call #
                    allocCall, freeCall = pairId.split('#')

                    printBuf = "{0:4}+ {1:>7}({2:>6}/{3:>6}/{4:>6})| ".\
                        format(' ', convertFunc(item['size'] << 12),
                        convertFunc(userPages << 12),
                        convertFunc(cachePages << 12),
                        convertFunc(kernelPages <<12))

                    indentLen = len(printBuf)
                    appliedIndentLen = indentLen

                    for seq, call in enumerate(allocCall.split(' <- ')):
                        if seq > 0 and \
                            appliedIndentLen + len(call) > lineLength:
                            printBuf = "%s\n%s" % (printBuf, ' ' * indentLen)
                            appliedIndentLen = indentLen
                        printBuf = "%s<- %s " % (printBuf, call)
                        appliedIndentLen += (len(call) + 4)

                    SysMgr.printPipe(printBuf)

                    printBuf = "{0:5}{1:>30}|".format(' ', '[FREE]')
                    indentLen = len(printBuf)
                    appliedIndentLen = indentLen

                    for index, call in enumerate(freeCall.split(' <- ')):
                        clen = len(call) + 4

                        if index == 0:
                            clen -= 4

                        if index > 0 and appliedIndentLen + clen > lineLength:
                            printBuf = "%s\n%s" % (printBuf, ' ' * indentLen)
                            appliedIndentLen = indentLen

                        if index == 0:
                            printBuf = "%s %s" % (printBuf, call)
                        else:
                            printBuf = "%s <- %s" % (printBuf, call)

                        appliedIndentLen += 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)' % (title, size))

        SysMgr.printPipe(twoLine)
        SysMgr.printPipe(
            "{0:^7}({1:^6}/{2:^6}/{3:^6})|{4:_^47}|{5:_^76}".\
            format("Usage", "Usr", "Buf", "Ker", "Function", "LifeTime"))
        SysMgr.printPipe(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': long(0), 'KERNEL': long(0), 'CACHE': long(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 = long(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(convertFunc(value['pagePairCnt'] << 12),
                convertFunc(typeList['USER'] << 12),
                convertFunc(typeList['CACHE'] << 12),
                convertFunc(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 = long(0)
                try:
                    cachePages = item['valueList']['CACHE']
                except:
                    cachePages = long(0)
                try:
                    kernelPages = item['valueList']['KERNEL']
                except:
                    kernelPages = long(0)

                # get kernel alloc and free call #
                allocCall, freeCall = pairId.split('#')

                printBuf = "{0:4}+ {1:>7}({2:>6}/{3:>6}/{4:>6})| ".\
                    format(' ', convertFunc(item['size'] << 12),
                    convertFunc(userPages << 12),
                    convertFunc(cachePages << 12),
                    convertFunc(kernelPages << 12))

                indentLen = len(printBuf)
                appliedIndentLen = indentLen

                for seq, call in enumerate(allocCall.split(' <- ')):
                    if seq > 0 and appliedIndentLen + len(call) > lineLength:
                        printBuf = "%s\n%s" % (printBuf, ' ' * indentLen)
                        appliedIndentLen = indentLen
                    printBuf = "%s<- %s " % (printBuf, call)
                    appliedIndentLen += (len(call) + 4)

                SysMgr.printPipe(printBuf)

                printBuf = "{0:5}{1:>30}|".format(' ', '[FREE]')
                indentLen = len(printBuf)
                appliedIndentLen = indentLen

                for index, call in enumerate(freeCall.split(' <- ')):
                    clen = len(call) + 4

                    if index == 0:
                        clen -= 4

                    if index > 0 and appliedIndentLen + clen > lineLength:
                        printBuf = "%s\n%s" % (printBuf, ' ' * indentLen)
                        appliedIndentLen = indentLen

                    if index == 0:
                        printBuf = "%s %s" % (printBuf, call)
                    else:
                        printBuf = "%s <- %s" % (printBuf, call)

                    appliedIndentLen += 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')

        convertFunc = UtilMgr.convSize2Unit
        userSize = convertFunc(self.pageUsageCnt << 12)
        allocSize = convertFunc(self.pageAllocCnt << 12)
        freeSize = convertFunc(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 = long(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)' % \
                (title, userSize, allocSize, allocCnt, freeSize, freeCnt))

            SysMgr.printPipe(twoLine)
            SysMgr.printPipe(
                "{0:^7}({1:^6}/{2:^6}/{3:^6})|{4:_^47}|{5:_^40}|{6:_^35}".\
                format("Usage", "Usr", "Buf", "Ker",
                    "Function", "LifeTime", "Binary"))
            SysMgr.printPipe(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 = long(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(convertFunc(value['pageCnt'] << 12),
                    convertFunc(value['userPageCnt'] << 12),
                    convertFunc(value['cachePageCnt'] << 12),
                    convertFunc(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:
                        indentLen = len("\t" * 4 * 9)
                        symbolStack = self.makeUserSymList(subStack, indentLen)

                    SysMgr.printPipe(
                        "\t+ {0:>7}({1:>6}/{2:>6}/{3:>6})|{4:32}".\
                        format(convertFunc(pageCnt << 12),
                        convertFunc(userPageCnt << 12),
                        convertFunc(cachePageCnt << 12),
                        convertFunc(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)' % \
            (title, userSize, allocSize, allocCnt, freeSize, freeCnt))

        SysMgr.printPipe(twoLine)
        SysMgr.printPipe(
            "{0:^7}({1:^6}/{2:^6}/{3:^6})|{4:_^47}|{5:_^76}".\
            format("Usage", "Usr", "Buf", "Ker", "Function", "LifeTime"))
        SysMgr.printPipe(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 = long(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(convertFunc(value['pageCnt'] << 12),
                convertFunc(value['userPageCnt'] << 12),
                convertFunc(value['cachePageCnt'] << 12),
                convertFunc(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:
                    indentLen = len("\t" * 4 * 9)
                    symbolStack = self.makeKernelSymList(subStack, indentLen)

                SysMgr.printPipe(
                    "\t+ {0:>7}({1:>6}/{2:>6}/{3:>6})|{4:32}".format(
                    convertFunc(pageCnt << 12),
                    convertFunc(userPageCnt << 12),
                    convertFunc(cachePageCnt << 12),
                    convertFunc(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')
        convertFunc = UtilMgr.convSize2Unit

        # Print heap usage in user space #
        SysMgr.clearPrint()
        SysMgr.printPipe(
            '[%s Info] [Total: %s] [Alloc: %s(%s)] [Free: %s(%s)] (USER)' % \
            (title,
            convertFunc(self.heapExpSize - self.heapRedSize),
            convertFunc(self.heapExpSize),
            UtilMgr.convNum(self.heapExpEventCnt),
            convertFunc(self.heapRedSize),
            UtilMgr.convNum(self.heapRedEventCnt)))

        SysMgr.printPipe(twoLine)
        SysMgr.printPipe("{0:_^9}|{1:_^47}|{2:_^49}|{3:_^46}".\
            format("Usage", "Function", "Binary", "Source"))
        SysMgr.printPipe(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(convertFunc(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:
                    indentLen = len("\t" * 4 * 4)
                    symbolStack = self.makeUserSymList(subStack, indentLen)

                SysMgr.printPipe("\t+ {0:>8} |{1:32}".\
                    format(convertFunc(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]' % \
            (title, UtilMgr.convNum(len(self.heapTable))))

        SysMgr.printPipe(twoLine)
        SysMgr.printPipe(
            "{0:_^32}|{1:_^12}|{2:_^17}({3:_^7})|{4:_^8}|{5:_^17}|".\
            format("VAddr", "Size", "COMM", "TID", "CORE", "TIME"))
        SysMgr.printPipe(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, convertFunc(size),
                self.threadData[tid]['comm'], tid, long(core), time)
            SysMgr.printPipe('%s\n%s' % (title, len(title) * '-'))

            # Make user call info #
            indentLen = 32
            nowLen = indentLen
            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 = '%s%s' % (userCall, nextCall)
                            nowLen += len(nextCall)
                        else:
                            userCall = '%s\n%s %s' % \
                                (userCall, ' ' * indentLen, nextCall)
                            nowLen = indentLen + len(nextCall)
                    except:
                        pass
            except:
                pass

            # Make kernel call info #
            indentLen = 32
            nowLen = indentLen
            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 = '%s%s' % (kernelCall, nextCall)
                            nowLen += len(nextCall)
                        else:
                            kernelCall = '%s\n%s %s' % \
                                (kernelCall, ' ' * indentLen, nextCall)
                            nowLen = indentLen + 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)' % (title, self.lockTryEventCnt))

        SysMgr.printPipe(twoLine)
        SysMgr.printPipe("{0:_^9}|{1:_^47}|{2:_^49}|{3:_^46}".\
            format("Usage", "Function", "Binary", "Source"))
        SysMgr.printPipe(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:
                    indentLen = len("\t" * 4 * 4)
                    symbolStack = self.makeUserSymList(subStack, indentLen)

                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)' % (title, self.lockTryEventCnt))

        SysMgr.printPipe(twoLine)
        SysMgr.printPipe("{0:_^9}|{1:_^144}".format("Usage", "Binary"))
        SysMgr.printPipe(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}".format(value['lockTryCnt'], idx))

            SysMgr.printPipe(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)' % (title, self.unlockEventCnt))

        SysMgr.printPipe(twoLine)
        SysMgr.printPipe("{0:_^9}|{1:_^47}|{2:_^49}|{3:_^46}".\
            format("Usage", "Function", "Binary", "Source"))
        SysMgr.printPipe(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:
                    indentLen = len("\t" * 4 * 4)
                    symbolStack = self.makeUserSymList(subStack, indentLen)

                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)' % (title, self.lockTryEventCnt))

        SysMgr.printPipe(twoLine)
        SysMgr.printPipe("{0:_^9}|{1:_^144}".\
            format("Usage", "Binary"))
        SysMgr.printPipe(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]' % \
            (title, self.lockTryEventCnt, self.unlockEventCnt))

        SysMgr.printPipe(twoLine)
        SysMgr.printPipe(
            "{0:_^32}|{1:_^16}|{2:_^17}({3:_^7})|{4:_^8}|{5:_^17}|".\
            format("Event", "TARGET", "COMM", "TID", "CORE", "TIME"))
        SysMgr.printPipe(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 #
            indentLen = 32
            nowLen = indentLen
            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 = '%s%s' % (userCall, nextCall)
                            nowLen += len(nextCall)
                        else:
                            userCall = '%s\n%s %s' % \
                                (userCall, ' ' * indentLen, nextCall)
                            nowLen = indentLen + len(nextCall)
                    except:
                        pass
            except SystemExit:
                sys.exit(0)
            except:
                pass

            SysMgr.printPipe(
                "{0:>32}|{1:<121}".format('[User] ', userCall))
            SysMgr.printPipe(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')
        convertFunc = UtilMgr.convSize2Unit
        convertNum = UtilMgr.convNum
        size = convertFunc(self.blockWrUsageCnt << 9)

        # Print block write in user space #
        if SysMgr.userEnable:
            SysMgr.clearPrint()
            SysMgr.printPipe(
                '[%s] [Size: %s] [Cnt: %s] (USER)' % \
                (title, size, convertNum(self.blockWrEventCnt)))

            SysMgr.printPipe(twoLine)
            SysMgr.printPipe("{0:_^9}|{1:_^47}|{2:_^49}|{3:_^46}".\
                format("Usage", "Function", "Binary", "Source"))
            SysMgr.printPipe(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(convertFunc(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:
                        indentLen = len("\t" * 4 * 4)
                        symbolStack = self.makeUserSymList(subStack, indentLen)

                    SysMgr.printPipe("\t+ {0:>8} |{1:32}".\
                        format(convertFunc(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)' % \
            (title, size, convertNum(self.blockWrEventCnt)))

        SysMgr.printPipe(twoLine)
        SysMgr.printPipe("{0:_^9}|{1:_^144}".format("Usage", "Function"))
        SysMgr.printPipe(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(convertFunc(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:
                    indentLen = len("\t" * 4 * 4)
                    symbolStack = self.makeKernelSymList(subStack, indentLen)

                SysMgr.printPipe("\t+ {0:>8} |{1:32}".\
                    format(convertFunc(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 function now #
        return exceptList

        for pos, value in self.posData.items():
            if value['symbol'] == 'None':
                try:
                    exceptList[pos]
                except:
                    exceptList[pos] = dict()

        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')
        convertFunc = UtilMgr.convSize2Unit
        convertNum = UtilMgr.convNum
        size = convertFunc(self.blockRdUsageCnt << 9)

        # Print block read in user space #
        if SysMgr.userEnable:
            SysMgr.clearPrint()
            SysMgr.printPipe(
                '[%s] [Size: %s] [Cnt: %s] (USER)' % \
                (title, size, convertNum(self.blockRdEventCnt)))

            SysMgr.printPipe(twoLine)
            SysMgr.printPipe("{0:_^9}|{1:_^47}|{2:_^49}|{3:_^46}".\
                format("Usage", "Function", "Binary", "Source"))
            SysMgr.printPipe(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(convertFunc(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:
                        indentLen = len("\t" * 4 * 4)
                        symbolStack = self.makeUserSymList(subStack, indentLen)

                    SysMgr.printPipe("\t+ {0:8} |{1:32}".\
                        format(convertFunc(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)' % \
            (title, size, convertNum(self.blockRdEventCnt)))

        SysMgr.printPipe(twoLine)
        SysMgr.printPipe("{0:_^9}|{1:_^144}".format("Usage", "Function"))
        SysMgr.printPipe(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(convertFunc(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:
                    indentLen = len("\t" * 4 * 4)
                    symbolStack = self.makeKernelSymList(subStack, indentLen)

                SysMgr.printPipe("\t+ {0:>8} |{1:32}".\
                    format(convertFunc(blockRdCnt << 9), symbolStack))

            SysMgr.printPipe(oneLine)

        SysMgr.printPipe('\n\n')





class LeakAnalyzer(object):
    """ Analyzer for leaktracing """

    # use SIGRT1 and SIGRT2 as default signals #
    startSig = 35
    stopSig = 36



    def __init__(self, file=None, pid=None):

        self.pid = pid
        self.posData = {}
        self.symData = {}
        self.fileData = {}
        self.callData = []
        self.totalLeakSize = long(0)

        self.init_posData = \
            {'offset': long(0), 'path': None, 'lastPosCnt': long(0),
                'callList': None, 'count': long(0), 'size': long(0),
                'lastPosSize': long(0), 'sym': '??'}

        self.init_symData = \
            {'offset': long(0), 'path': None, 'lastPosCnt': long(0),
                'substack': None, 'count': long(0), 'size': long(0),
                'lastPosSize': long(0)}

        self.init_fileData = \
            {'lastPosCnt': long(0), 'count': long(0),
                'size': long(0), 'lastPosSize': long(0)}

        # Get file size #
        try:
            stat = os.stat(file)
            size = UtilMgr.convSize2Unit(stat.st_size)
        except SystemExit:
            sys.exit(0)
        except:
            size = '??'

        # Open log file #
        try:
            SysMgr.printInfo(
                "start loading '%s' [%s]" % (file, size))

            fd = open(file, 'r')
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenErr(file)
            sys.exit(0)

        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(
                "fail to analyze leakage", True)

        SysMgr.printInfo("start resolving symbols...")

        # Resolve symbols #
        self.resolveSymbols(proc)

        SysMgr.printInfo("start merging symbols...")

        # Merge symbols #
        self.mergeSymbols()



    def printLeakage(self, runtime, profiletime):
        convert = UtilMgr.convSize2Unit

        try:
            mlist = SysMgr.getMemStat(self.pid)
            vssIdx = ConfigMgr.STATM_TYPE.index("TOTAL")
            vss = convert(long(mlist[vssIdx]) << 12)
            rssIdx = ConfigMgr.STATM_TYPE.index("RSS")
            rss = convert(long(mlist[rssIdx]) << 12)
        except:
            vss = rss = '?'

        proc = '%s(%s)' % (SysMgr.getComm(self.pid), self.pid)
        # function leakage info #
        title = 'Function Leakage Info'
        SysMgr.printPipe((
            '\n[%s] [Process: %s] [Runtime: %s] [ProfileTime: %s] '
            '[VSS: %s] [RSS: %s] [LeakSize: %s] [NrCall: %s]') % \
                (title, proc, runtime, profiletime, vss, rss,
                convert(self.totalLeakSize),
                convert(len(self.callData))))

        SysMgr.printPipe(twoLine)
        SysMgr.printPipe(
                "{0:^7} | {1:^7} | {2:^7} | {3:^122} |".\
                format("Size", "Count", "Avg", "Function"))
        SysMgr.printPipe(oneLine)

        count = long(0)
        for sym, val in sorted(self.symData.items(),
            key=lambda e: long(e[1]['lastPosSize']), reverse=True):
            if val['lastPosSize'] == 0:
                break

            SysMgr.printPipe(
                "{0:>7} | {1:>7} | {2:>7} | {3:<122} ".\
                    format(convert(val['lastPosSize']), convert(val['count']),
                    convert(long(val['lastPosSize'] / val['count'])),
                    '%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('', convert(size), substack))

            count += 1

            SysMgr.printPipe(oneLine)

        if count == 0:
            SysMgr.printPipe('\tNone\n%s' % oneLine)

        # file leakage info #
        title = 'File Leakage Info'
        SysMgr.printPipe((
            '\n[%s] [Process: %s] [Runtime: %s]  [ProfileTime: %s] '
            '[VSS: %s] [RSS: %s] [LeakSize: %s] [NrCall: %s]') % \
                (title, proc, runtime, profiletime, vss, rss,
                convert(self.totalLeakSize),
                convert(len(self.callData))))

        SysMgr.printPipe(twoLine)
        SysMgr.printPipe(
            "{0:^7} | {1:^7} | {2:^7} | {3:^122} |".format(
            "Size", "Count", "Avg", "Path"))
        SysMgr.printPipe(oneLine)

        count = long(0)
        for file, val in sorted(self.fileData.items(),
            key=lambda e: long(e[1]['lastPosSize']), reverse=True):
            if val['lastPosSize'] == 0:
                break

            SysMgr.printPipe(
                "{0:>7} | {1:>7} | {2:>7} | {3:<122} |".format(
                    convert(val['lastPosSize']), convert(val['count']),
                    convert(long(val['lastPosSize'] / val['count'])), file))

            count += 1

        if count == 0:
            SysMgr.printPipe('\tNone')
        SysMgr.printPipe(oneLine)

        if not SysMgr.showAll or not self.callData:
            return

        # leakage history #
        title = 'Leakage History'
        SysMgr.printPipe(
            '\n[%s] [Total: %s] [CallCount: %s]' % \
                (title, convert(self.totalLeakSize, True),
                    convert(len(self.callData), True)))

        SysMgr.printPipe(twoLine)
        SysMgr.printPipe(
            "{0:^16} | {1:^6} |{2:^50}| {3:^73} |".\
            format("Time", "Size", "Data", "Stack"))
        SysMgr.printPipe(oneLine)

        for time, items in sorted(self.callData.items(),
            key=lambda e: e[0], reverse=False):

            stack = list(items['symstack'])

            SysMgr.printPipe(
                "{0:>16} | {1:>6} |{2:50}| {3:<73} |".\
                    format(time,
                    convert(long(items['size'])),
                    items['data'][:-1], ' <- '.join(stack)))
            count += 1
        SysMgr.printPipe(oneLine)



    def mergeSymbols(self):
        cnt = long(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:
                self.symData[sym]['count'] += val['count']
                self.symData[sym]['size'] += val['size']
                self.symData[sym]['lastPosCnt'] += val['lastPosCnt']
                self.symData[sym]['lastPosSize'] += val['lastPosSize']
            except SystemExit:
                sys.exit(0)
            except:
                self.symData[sym] = dict(self.init_symData)
                self.symData[sym]['offset'] = val['offset']
                self.symData[sym]['path'] = val['path']
                self.symData[sym]['count'] = val['count']
                self.symData[sym]['size'] = val['size']
                self.symData[sym]['lastPosCnt'] = val['lastPosCnt']
                self.symData[sym]['lastPosSize'] = val['lastPosSize']
                self.symData[sym]['substack'] = dict()

            if val['callList']:
                for time in list(val['callList'].keys()):
                    callinfo = self.callData[time]
                    substack = dobj.getBacktraceStr(callinfo['symstack'][1:])
                    dobj.btStr = None

                    try:
                        self.symData[sym]['substack'][substack] += \
                            long(callinfo['size'])
                    except:
                        self.symData[sym]['substack'][substack] = \
                            long(callinfo['size'])

            # merge by file #
            path = val['path']
            try:
                self.fileData[path]['count'] += val['count']
                self.fileData[path]['size'] += val['size']
                self.fileData[path]['lastPosCnt'] += val['lastPosCnt']
                self.fileData[path]['lastPosSize'] += val['lastPosSize']
            except SystemExit:
                sys.exit(0)
            except:
                self.fileData[path] = dict(self.init_fileData)
                self.fileData[path]['count'] = val['count']
                self.fileData[path]['size'] = val['size']
                self.fileData[path]['lastPosCnt'] = val['lastPosCnt']
                self.fileData[path]['lastPosSize'] = val['lastPosSize']

            self.totalLeakSize += val['lastPosSize']

        UtilMgr.deleteProgress()



    def resolveSymbols(self, proc):
        cnt = long(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(
                    "fail 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'] = dict()
                self.posData[posid]['callList'][pos] = None

        UtilMgr.deleteProgress()



    def parseLines(self, fd):
        callinfo = {}

        while 1:
            try:
                line = fd.readline()
            except SystemExit:
                sys.exit(0)
            except:
                continue

            if not line:
                break

            # print progress #
            cur = fd.tell()
            total = os.fstat(fd.fileno()).st_size
            UtilMgr.printProgress(cur, total)

            items = line.split(', ')

            if items[0] != 'leak':
                continue

            time = None
            item = dict()

            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 #
                    item[name] = body.split()
                else:
                    item[name] = body

            if not item or \
                not 'size' in item or \
                not item['size'].isdigit():
                continue

            # save pos in common area #
            for pos in item['stack']:
                try:
                    self.posData[pos]['count'] += 1
                    self.posData[pos]['size'] += long(item['size'])
                except SystemExit:
                    sys.exit(0)
                except:
                    self.posData[pos] = dict(self.init_posData)
                    self.posData[pos]['count'] = 1
                    self.posData[pos]['size'] = long(item['size'])
                    self.posData[pos]['callList'] = dict()

            try:
                lastPos = item['stack'][0]
            except:
                continue

            self.posData[lastPos]['lastPosSize'] += long(item['size'])

            callinfo[time] = item

        UtilMgr.deleteProgress()

        return callinfo





class FileAnalyzer(object):
    """ Analyzer for file profiling """

    init_mapData = \
        {'offset': long(0), 'size': long(0), 'pageCnt': long(0),
        'fd': None, 'totalSize': long(0), 'fileMap': None, 'pids': None,
        'linkCnt': long(0), 'inode': None, 'accessTime': None,
        'devid': None, 'isRep': True, 'perm': None,
        'repFile': None, 'hardLink': long(1), 'linkList': None,
        'vstart': long(0), 'vend': long(0), 'elfInfo': None}



    def __init__(self):
        self.profSuccessCnt = long(0)
        self.profFailedCnt = long(0)
        self.profPageCnt = long(0)
        self.procData = {}
        self.fileData = {}
        self.inodeData = {}
        self.target = ['']

        self.procList = {}
        self.fileList = {}

        self.intervalProcData = []
        self.intervalFileData = []

        self.init_procData = \
            {'tids': None, 'pageCnt': long(0), 'procMap': None, 'comm': ''}
        self.init_threadData = {'comm': ''}
        self.init_inodeData = {}

        # 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

        # set system maximum fd number #
        SysMgr.setMaxFd()

        while 1:
            # scan proc directory and save map information of processes #
            self.scanProcs()

            # merge maps of processes into a integrated file map #
            self.mergeFileMapInfo()

            # get file map info on memory #
            self.getFilePageMaps()

            # fill file map of each processes #
            self.fillFileMaps()

            if SysMgr.intervalEnable > 0:
                # 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 = long(0)
                self.profFailedCnt = long(0)

                # check exit condition for interval profile #
                if not SysMgr.condExit:
                    SysMgr.waitEvent()
                else:
                    break
            else:
                break



    def __del__(self):
        pass



    def printIntervalInfo(self):
        # Merge process info into a global list #
        for procData in self.intervalProcData:
            for pid, procInfo in procData.items():
                try:
                    if self.procList[pid]['pageCnt'] < procInfo['pageCnt']:
                        self.procList[pid]['pageCnt'] = procInfo['pageCnt']
                except:
                    self.procList[pid] = dict(self.init_procData)
                    self.procList[pid]['tids'] = {}
                    self.procList[pid]['pageCnt'] = procInfo['pageCnt']
                    self.procList[pid]['comm'] = procInfo['comm']

                for tid, val in procInfo['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(0)

        # Merge file info into a global list #
        for fileData in self.intervalFileData:
            for fileName, fileStat in fileData.items():
                try:
                    fl = self.fileList[fileName]
                    if fl['pageCnt'] < fileStat['pageCnt']:
                        fl['pageCnt'] = fileStat['pageCnt']
                except:
                    self.fileList[fileName] = dict(FileAnalyzer.init_mapData)
                    self.fileList[fileName]['pageCnt'] = fileStat['pageCnt']
                    self.fileList[fileName]['totalSize'] = fileStat['totalSize']

        if not self.fileList:
            SysMgr.printErr('no file profiled')
            sys.exit(0)

        SysMgr.printLogo(big=True)

        # Print system information #
        SysMgr.printInfoBuffer()

        # define alias #
        pageSize = SysMgr.pageSize
        convert = UtilMgr.convSize2Unit
        convColor = UtilMgr.convColor

        # Print process list #
        SysMgr.printPipe((
            "[%s] [ Process : %d ] [ LastRAM: %s ]"
            " [ Keys: Foward/Back/Save/Quit ] [ Capture: Ctrl+\\ ]") % \
                ('File Process Info', len(self.procList),
                convert(self.profPageCnt * 4 << 10)))
        SysMgr.printPipe(twoLine)
        SysMgr.printPipe(
            "{0:_^16}({1:_^6})|{2:_^12}|{3:_^16}({4:_^5}) |".\
            format("Process", "PID", "MaxRAM", "ThreadName", "TID"))
        SysMgr.printPipe(twoLine)

        procInfo = "{0:_^16}({1:^6})|{2:11} |".format('', '', '')
        threadInfo = " {0:^16}({1:^6}) |".format('', '')
        procLength = len(procInfo)
        threadLength = len(threadInfo)
        lineLength = SysMgr.lineLength

        for pid, val in sorted(self.procList.items(),
            key=lambda e: long(e[1]['pageCnt']), reverse=True):
            try:
                rsize = val['pageCnt'] * pageSize
            except:
                SysMgr.printWarn(
                    'fail to get total mapped size for %s' % val['comm'],
                    reason=True)
                continue

            if rsize > 0:
                rsize = convColor(convert(rsize), 'YELLOW', 11)

            printMsg = "{0:>16}({1:>6})|{2:>11} |".\
                format(val['comm'][:SysMgr.commLen], pid, rsize)
            linePos = len(printMsg)

            for tid, threadVal in sorted(val['tids'].items(), reverse=True):
                threadInfo = \
                    "{0:>16}({1:>6}) |".format(
                        threadVal['comm'][:SysMgr.commLen], tid)

                linePos += threadLength

                if linePos > lineLength:
                    linePos = procLength + threadLength
                    printMsg += "\n" + (' ' * (procLength - 1)) + '|'

                printMsg += threadInfo

            SysMgr.printPipe(printMsg)

        SysMgr.printPipe("%s\n\n" % oneLine)

        # Print file list #
        SysMgr.printPipe((
            "[%s] [ File: %d ] [ LastRAM: %s ] "
            "[ Keys: Foward/Back/Save/Quit ]") % \
                ('File Usage Info', len(self.fileList),
                convert(self.profPageCnt * 4 << 10)))
        SysMgr.printPipe(twoLine)

        printMsg = "{0:_^11}|{1:_^8}|{2:_^3}|".format(
            "InitRAM", "File", "%")

        if len(self.intervalFileData) > 1:
            for idx in range(1, len(self.intervalFileData)):
                printMsg += "{0:_^15}|".format(str(idx))

        printMsg += "{0:_^11}|{1:_^3}|".format("LastRAM", "%")

        lineLength = SysMgr.lineLength

        printMsg += '_' * (long((lineLength - len(printMsg)) / 2) - 2)
        printMsg += 'Library'
        printMsg += '_' * (lineLength - len(printMsg))

        SysMgr.printPipe(printMsg)

        SysMgr.printPipe(twoLine)

        # print interval usage #
        for fileName, val in sorted(self.fileList.items(),
            key=lambda e: long(e[1]['pageCnt']), reverse=True):
            try:
                memSize = \
                    self.intervalFileData[0][fileName]['pageCnt'] * pageSize
            except:
                memSize = long(0)

            try:
                idx = val['totalSize'] + pageSize - 1
                fileSize = long(idx / pageSize) * pageSize
            except:
                fileSize = long(0)

            # set percentage #
            if fileSize != 0:
                per = long(long(memSize) / float(fileSize) * 100)
                if per >= SysMgr.cpuPerHighThreshold:
                    per = UtilMgr.convColor(per, 'RED', 3)
                else:
                    per = UtilMgr.convColor(per, 'YELLOW', 3)
            else:
                per = long(0)

            if memSize > 0:
                memSize = convColor(convert(memSize), 'YELLOW', 10)

            # 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:>10} |{1:>7} |{2:>3}|".format(
                            memSize, convert(fileSize), per)
                    isRep = True
                    break

            if not isRep:
                continue

            # calculate diff of on-memory file size #
            if len(self.intervalFileData) > 1:
                for idx in range(1, len(self.intervalFileData)):
                    diffNew = long(0)
                    diffDel = long(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 range(len(nowFileMap)):
                                    if nowFileMap[i] > prevFileMap[i]:
                                        diffNew += 1
                                    elif nowFileMap[i] < prevFileMap[i]:
                                        diffDel += 1

                    if diffNew > 0:
                        diffNew = convColor(
                            convert(diffNew * pageSize), 'RED', 6)
                    else:
                        diffNew = ' '

                    if diffDel > 0:
                        diffDel = convColor(
                            convert(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)
                if per >= SysMgr.cpuPerHighThreshold:
                    per = UtilMgr.convColor(per, 'RED', 3)
                else:
                    per = UtilMgr.convColor(per, 'YELLOW', 3)
            else:
                per = long(0)

            if totalMemSize > 0:
                totalMemSize = convColor(
                    convert(totalMemSize), 'YELLOW', 11)

            printMsg += \
                "{0:11}|{1:3}| {2:1}".format(totalMemSize, per, fileName)

            SysMgr.printPipe(printMsg)

        SysMgr.printPipe("%s\n\n\n" % oneLine)



    def makeReadaheadList(self):
        pass



    @staticmethod
    def getMapAddr(pid, fname, fd=None):
        if not fname:
            SysMgr.printWarn(
                "no memory-mapped file name to be searched")
            return

        if not fd:
            fd = FileAnalyzer.getMapFd(pid)
            if not fd:
                return None

        # read maps #
        fd.seek(0, 0)
        mapBuf = fd.readlines()
        for item in mapBuf:
            mdict = FileAnalyzer.parseMapLine(item)
            if mdict and mdict['binName']:
                if mdict['binName'].endswith(fname):
                    return str(mdict['startAddr']), str(mdict['endAddr'])
        return None



    @staticmethod
    def getMapFilePath(pid, fname, fd=None):
        if not fname:
            SysMgr.printWarn(
                "no file name to be searched on memory-map")
            return

        if not fd:
            fd = FileAnalyzer.getMapFd(pid)
            if not fd:
                return None

        # read maps #
        fd.seek(0, 0)
        mapBuf = fd.readlines()
        for item in mapBuf:
            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 #
        mapBuf = fd.readlines()
        for item in mapBuf:
            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 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 getProcMapInfo(pid, fd=None, onlyExec=False, saveAll=False):
        if not fd:
            fd = FileAnalyzer.getMapFd(pid, True)
            if not fd:
                comm = SysMgr.getComm(pid)
                SysMgr.printErr(
                    'fail to get memory map for %s(%s)' % (comm, pid))
                sys.exit(0)

        # read maps #
        fd.seek(0, 0)
        mapBuf = fd.readlines()

        # parse and merge lines in maps #
        fileMap = dict()
        for val in mapBuf:
            FileAnalyzer.mergeMapLine(val, fileMap, saveAll=saveAll)

        # remove non-executable files #
        if onlyExec:
            for fname in list(fileMap.keys()):
                if fname != 'stack' and not fileMap[fname]['exec']:
                    fileMap.pop(fname, None)

        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



    @staticmethod
    def parseMapLine(string):
        m = re.match((
            r'^(?P<startAddr>.\S+)-(?P<endAddr>.\S+) (?P<perm>.\S+) '
            r'(?P<offset>.\S+) (?P<devid>.\S+) (?P<inode>0|.\S+).\s*'
            r'(?P<binName>.+)'), string)
        if not m:
            return None

        return m.groupdict()



    @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

        fileName = d['binName']
        if fileName.startswith('['):
            fileName = fileName[1:-1]
        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 printUsage(self):
        if not self.procData:
            SysMgr.printErr('no process profiled')
            sys.exit(0)
        if not self.fileData:
            SysMgr.printErr('no file profiled')
            sys.exit(0)

        SysMgr.printLogo(big=True)

        # print system information #
        SysMgr.printInfoBuffer()

        # define alias #
        convert = UtilMgr.convSize2Unit
        convColor = UtilMgr.convColor
        pageSize = SysMgr.pageSize

        # Print process list #
        SysMgr.printPipe((
            "[%s] [ Process : %d ] [ RAM: %s ]"
            "[ Keys: Foward/Back/Save/Quit ] [ Capture: Ctrl+\\ ]") % \
                ('File Process Info', len(self.procData),
                convert(self.profPageCnt * 4 << 10)))
        SysMgr.printPipe(twoLine)
        SysMgr.printPipe(
            "{0:_^16}({1:_^6})|{2:_^13}|{3:_^16}({4:_^6}) |".\
            format("Process", "PID", "RAM", "Thread", "TID"))
        SysMgr.printPipe(twoLine)

        procInfo = "{0:^16}({0:^6})|{0:12} |".format('')
        threadInfo = " {0:^16}({0:^6}) |".format('')
        procLength = len(procInfo)
        threadLength = len(threadInfo)
        lineLength = SysMgr.lineLength

        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(
                    'fail to get total mapped size for %s' % val['comm'],
                    reason=True)
                continue

            if rsize > 0:
                rsize = convColor(convert(rsize), 'YELLOW', 12)

            printMsg = "{0:>16}({1:>6})|{2:>12} |".\
                format(val['comm'][:SysMgr.commLen], pid, rsize)
            linePos = len(printMsg)

            for tid, threadVal in sorted(val['tids'].items(), reverse=True):
                threadInfo = \
                    "{0:^16}({1:>6}) |".format(
                        threadVal['comm'][:SysMgr.commLen], tid)

                linePos += threadLength

                if linePos > lineLength:
                    linePos = procLength + threadLength
                    printMsg += "\n" + (' ' * (procLength - 1)) + '|'

                printMsg += threadInfo

            SysMgr.printPipe(printMsg)

        SysMgr.printPipe("%s\n\n" % oneLine)

        # Print file list #
        SysMgr.printPipe(
            "[%s] [ File: %d ] [ RAM: %s ] [ Keys: Foward/Back/Save/Quit ]" % \
            ('File Usage Info', len(self.fileData),
            convert(self.profPageCnt * 4 << 10)))
        SysMgr.printPipe(twoLine)
        SysMgr.printPipe("{0:_^12}|{1:_^10}|{2:_^6}|{3:_^123}".\
            format("RAM", "File", "%", "Library & Process"))
        SysMgr.printPipe(twoLine)

        for fileName, val in sorted(self.fileData.items(),
            key=lambda e: long(e[1]['pageCnt']), reverse=True):
            memSize = val['pageCnt'] * pageSize

            idx = val['totalSize'] + pageSize - 1

            fileSize = long(idx / pageSize) * pageSize

            if fileSize != 0:
                per = long(long(memSize) / float(fileSize) * 100)
                if per >= SysMgr.cpuPerHighThreshold:
                    per = UtilMgr.convColor(per, 'RED', 5)
                else:
                    per = UtilMgr.convColor(per, 'YELLOW', 5)
            else:
                per = long(0)

            if memSize > 0:
                memSize = convColor(convert(memSize), 'YELLOW', 11)

            if not val['isRep']:
                continue
            else:
                SysMgr.printPipe((
                    "{0:>11} |{1:>9} |{2:>5} | {3:1} "
                    "[Proc: {4:1}] [Link: {5:1}]").\
                    format(memSize, convert(fileSize), per, fileName,
                    len(val['pids']), val['hardLink']))

            # prepare for printing process list #
            pidInfo = ''
            lineLength = SysMgr.lineLength
            pidLength = len(" %16s (%6s) |" % ('', ''))
            indentLength = len("{0:>11} |{1:>9} |{2:>5} ".format('','',''))
            linePos = indentLength + pidLength

            # print hard-linked list #
            if val['hardLink'] > 1:
                for fileLink, tmpVal in val['linkList'].items():
                    if fileName != fileLink:
                        SysMgr.printPipe(
                            (' ' * indentLength) + '| -> ' + fileLink)

            # print process list #
            for pid, comm in val['pids'].items():
                if linePos > lineLength:
                    linePos = indentLength + pidLength
                    pidInfo += '\n' + (' ' * indentLength) + '|'

                pidInfo += " %16s (%6s) |" % \
                    (comm[:SysMgr.commLen], pid)

                linePos += pidLength

            SysMgr.printPipe((' ' * indentLength) + '|' + pidInfo)
            SysMgr.printPipe(oneLine)

        SysMgr.printPipe('\n\n\n')



    def scanProcs(self):
        # get process list in proc filesystem #
        try:
            pids = os.listdir(SysMgr.procPath)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenErr(SysMgr.procPath)
            sys.exit(0)

        # scan comms include words in target list #
        for pid in pids:
            try:
                long(pid)
            except:
                continue

            # make path of comm #
            procPath = "%s/%s" % (SysMgr.procPath, pid)
            commPath = "%s/%s" % (procPath, 'comm')
            pidComm = ''

            # make comm path of process #
            try:
                self.procData[pid]['comm']
            except:
                try:
                    fd = open(commPath, 'r')
                    pidComm = fd.readline()
                    pidComm = pidComm[0:len(pidComm) - 1]
                    fd.close()
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printOpenWarn(commPath)
                    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

            # make thread list in process object #
            for tid in tids:
                try:
                    long(tid)
                except:
                    continue

                # make comm path of thread #
                threadPath = "%s/%s" % (taskPath, tid)
                commPath = "%s/%s" % (threadPath, 'comm')

                try:
                    fd = open(commPath, 'r')
                    comm = fd.readline()
                    comm = comm[0:len(comm) - 1]
                    fd.close()
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printOpenWarn(commPath)
                    continue

                # save process info #
                for val in self.target:
                    if val in comm or tid == val:
                        # access procData #
                        try:
                            self.procData[pid]
                        except:
                            self.procData[pid] = dict(self.init_procData)
                            self.procData[pid]['tids'] = {}
                            self.procData[pid]['procMap'] = {}
                            self.procData[pid]['comm'] = pidComm

                            # make or update mapInfo per process #
                            self.procData[pid]['procMap'] = \
                                FileAnalyzer.getProcMapInfo(pid)

                        # access threadData #
                        try:
                            self.procData[pid]['tids'][tid]
                        except:
                            self.procData[pid]['tids'][tid] = \
                                dict(self.init_threadData)
                            self.procData[pid]['tids'][tid]['comm'] = comm



    def fillFileMaps(self):
        self.profPageCnt = long(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 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):
        for pid, val in self.procData.items():
            for fileName, scope in val['procMap'].items():
                newOffset = scope['offset']
                newSize = scope['size']

                # merge map line #
                FileAnalyzer.addMapLine(
                    self.fileData, fileName, newOffset, newSize)

                # add pid into file info #
                if not self.fileData[fileName]['pids']:
                    self.fileData[fileName]['pids'] = dict()
                if not pid in self.fileData[fileName]['pids']:
                    self.fileData[fileName]['pids'][pid] = val['comm']



    def getFilePageMaps(self):
        pageSize = SysMgr.pageSize
        self.profSuccessCnt = long(0)
        self.profFailedCnt = long(0)

        for fileName, val in self.fileData.items():
            if not fileName.startswith('/'):
                continue
            elif fileName.startswith('/dev'):
                SysMgr.printWarn(
                    "skip analyzing %s because it is device node" % fileName)
                continue

            if len(self.intervalFileData) > 0:
                # 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, fileDevid in self.inodeData[inode].items():
                            # this hard-lined file was already profiled #
                            if devid == fileDevid:
                                found = True

                                # add file into same file list #
                                fileList[fileName] = True
                                fileList[fileIdx] = True

                                # merge process list related to this file #
                                procList = \
                                    dict(procList.items() + \
                                    self.fileData[fileIdx]['pids'].items())

                                if self.fileData[fileIdx]['isRep']:
                                    repFile = fileIdx

                        if found:
                            self.inodeData[inode][fileName] = devid
                            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']:
                                linkList = self.fileData[repFile]['linkList']
                                self.fileData[repFile]['linkList'] = \
                                    dict(linkList.items() + fileList.items())
                            else:
                                self.fileData[repFile]['linkList'] = fileList

                            continue
                        else:
                            self.inodeData[inode][fileName] = devid
                    else:
                        self.inodeData[inode] = dict(self.init_inodeData)
                        self.inodeData[inode][fileName] = devid

                    size = stat.st_size
                    linkCnt = stat.st_nlink
                    time = stat.st_atime

                    val['inode'] = inode
                    val['totalSize'] = size
                    val['linkCnt'] = linkCnt
                    val['accessTime'] = time

                    fd = open(fileName, "r")
                    val['fd'] = fd
                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('fail to mmap %s' % fileName)
                continue

            # prepare variables for mincore syscall #
            fd = val['fd'].fileno()
            offset = val['offset']
            size = val['size']

            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) # pylint: disable=no-member

                # call mincore syscall by standard libc library #
                pagemap = SysMgr.guiderObj.mincore(mm, size) # pylint: disable=no-member

                # unmap #
                SysMgr.guiderObj.munmap(mm, size) # pylint: disable=no-member
            else:
                # get ctypes object #
                SysMgr.importPkgItems('ctypes')

                # 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)

                # get the size of the table to map file segment #
                tsize = long((size + pageSize - 1) / pageSize);

                # 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 \
                            range(long(size / pageSize))]
                    else:
                        val['fileMap'] = \
                            [pagemap[i] for i in range(long(size / pageSize))]

                    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('fail to access %s' % fileName)
                    val['fileMap'] = None
                    self.profFailedCnt += 1
            else:
                val['fd'].close()
                val['fd'] = None

        if len(self.fileData) > 0:
            SysMgr.printGood(
                'profiled a total of %d files' % self.profSuccessCnt)
        else:
            SysMgr.printErr('fail to profile files')
            sys.exit(0)

        if self.profFailedCnt > 0:
            SysMgr.printWarn(
                'fail to open a total of %d files' % self.profFailedCnt)





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'):
        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')
                self.error = True
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "fail 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((
                    'fail to make %s directory because %s '
                    'so that use /tmp dir') % \
                        (SysMgr.cacheDirPath, err), True)
                SysMgr.cacheDirPath = '/tmp'

        # set file path for error log #
        errorFile = '%s/guider.err' % SysMgr.cacheDirPath
        if not SysMgr.isWritable(errorFile):
            SysMgr.printWarn((
                'fail to get write permission for %s '
                'so that use /tmp/guider.err') % errorFile, True)
            SysMgr.cacheDirPath = '/tmp'
            errorFile = '%s/guider.err' % SysMgr.cacheDirPath

        try:
            if not self.notified:
                SysMgr.printErr((
                    'please report %s file to '
                    'https://github.com/iipeace/guider/issues') % \
                        errorFile)
                self.notified = True

            with open(errorFile, 'a') as fd:
                SysMgr.writeErr(fd, message)
        except SystemExit:
            sys.exit(0)
        except:
            self.error = True
            SysMgr.printOpenErr(errorFile)



    def flush(self):
        pass



    def __getattr__(self, attr):
        return getattr(self.terminal, attr)



    @staticmethod
    def lock(fd):
        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] fail to get lock for %s because %s' % \
                (name, reason))



    @staticmethod
    def unlock(fd):
        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] fail to free lock for %s because %s' % \
                (name, reason))



    @staticmethod
    def printSyslog(console=False):
        # open syslog file #
        try:
            if not SysMgr.syslogFd:
                SysMgr.syslogFd = open(SysMgr.syslogPath, 'r')
        except:
            SysMgr.printOpenErr(SysMgr.syslogPath)
            sys.exit(0)

        SysMgr.printInfo(
            "start printing syslog... [ STOP(Ctrl+c) ]")

        # set file posiion #
        SysMgr.syslogFd.seek(0)

        while 1:
            log = SysMgr.syslogFd.readline()

            if not UtilMgr.isValidStr(log):
                continue

            if SysMgr.outPath and console:
                print(log)

            SysMgr.printPipe(log, newline=False)


    @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(
                "fail to print journal", True)
            sys.exit(0)

        # 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(
                "fail 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(
                "fail to print journal because no journal head")
            return

        # initialize variables #
        data = c_void_p(0)
        size = c_size_t(0)
        usec = c_uint64(0)
        timeout = c_uint64(10000)

        # 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 or ret == 1 or ret == 2:
                        continue
                    elif ret < 0:
                        break
                elif res < 1:
                    break

                # 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')

                        if not UtilMgr.isValidStr(decstr):
                            raise Exception()

                        if SysMgr.outPath and console:
                            print(decstr)

                        SysMgr.printPipe(decstr, flush=True)
                    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 = list()
        while 1:
            try:
                data = os.read(fd, SysMgr.pageSize).decode()
                logs.append(data)
            except SystemExit:
                sys.exit(0)
            except:
                break

        # convert logs #
        retList = list()
        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')
        except:
            SysMgr.printOpenErr(SysMgr.kmsgPath)
            sys.exit(0)

        SysMgr.printInfo(
            "start printing kernel log... [ STOP(Ctrl+c) ]")

        # 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
                    SysMgr.printPipe(line)

            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:
            pass

        # kmsg node #
        while 1:
            jsonResult = dict()
            log = SysMgr.kmsgFd.readline()

            if not UtilMgr.isValidStr(log):
                continue

            # 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:]

                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: %s' % (ltime, level, name, log)

            # apply filter #
            if SysMgr.filterGroup:
                found = False
                for string in SysMgr.filterGroup:
                    if string in log:
                        found = True
                        break

                if not found:
                    continue

            if SysMgr.jsonEnable:
                jsonResult = UtilMgr.convDict2Str(jsonResult)
                SysMgr.printPipe(jsonResult)
            else:
                if SysMgr.outPath and console:
                    print(log[:-1])

                SysMgr.printPipe(log[:-1])



    @staticmethod
    def doLogKmsg(msg=None, level=None):
        # open kmsg device node #
        try:
            if not SysMgr.kmsgFd:
                SysMgr.kmsgFd = open(SysMgr.kmsgPath, 'w')
        except:
            SysMgr.printOpenErr(SysMgr.kmsgPath)
            sys.exit(0)

        try:
            SysMgr.kmsgFd.write(msg)
            SysMgr.kmsgFd.flush()
        except:
            SysMgr.printWarn(
                "fail to write kmsg", reason=True)

        return 0



    @staticmethod
    def doLogSyslog(msg=None, level=None):
        if not msg:
            return

        # load libc #
        SysMgr.loadLibcObj(exit=True)

        if level is None:
            level = LogMgr.LOG_NOTICE

        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

        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:
            SysMgr.printErr(
                "fail to log journal", True)
            sys.exit(0)

        return SysMgr.systemdObj.sd_journal_print(level, msg.encode())





class SysMgr(object):
    """ Manager for system """

    arch = None
    origArgs = []
    kernelVersion = None
    isLinux = True
    isAndroid = False
    drawMode = False
    archOption = None

    # page size #
    try:
        pageSize = os.sysconf("SC_PAGE_SIZE")
    except:
        pageSize = 4096

    HZ = 250 # 4ms tick #
    try:
        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)

    startTime = long(0)
    startRunTime = long(0)
    blockSize = 512
    bufferSize = -1
    termGetId = None
    termSetId = None
    ttyRows = 43
    ttyRowsMargin = 2
    ttyCols = 156
    encoding = None
    encodeEnable = True
    encodeB64Enable = False
    remoteRun = False
    magicStr = '@@@@@'
    launchBuffer = ''
    lineLength = 154
    pid = long(0)
    comm = __module__
    commLen = 16
    masterPid = long(0)
    parentPid = long(0)
    prio = None
    funcDepth = long(0)
    maxPid = 32768
    maxRdCnt = 1024
    pidDigit = 5
    stdlog = None
    stderr = sys.stderr
    packetSize = 32767
    defaultPort = 5555
    bgProcList = None
    waitDelay = 0.5
    repeatInterval = long(0)
    repeatCount = long(0)
    progressCnt = long(0)
    wordSize = 4
    maxInterval = 0

    # threshold #
    cpuPerHighThreshold = 80
    cpuPerLowThreshold = 10
    memAvailPerThreshold = 10
    memHighThreshold = 1024
    memLowThreshold = 100
    swapPerThreshold = 90
    diskPerHighThreshold = 90

    # 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'
    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'
    libdemanglePath = libcppPath
    environList = {}
    environ = {}
    eventLogPath = None
    inputFile = None
    outputFile = None
    inputParam = None
    outPath = None

    signalCmd = "trap 'kill $$' INT\nsleep 1d\n"
    saveCmd = None
    boundaryLine = None
    demangleEnable = True
    compressEnable = False
    generalInfoEnable = True
    nrTop = None
    pipeForPager = None
    printFd = None
    fileSuffix = None
    parsedAnalOption = False
    optionList = []
    customCmd = []
    userCmd = []
    kernelCmd = []
    udpListCache = None
    tcpListCache = None
    customEventList = []
    userEventList = []
    kernelEventList = []
    perfEventChannel = {}
    perfTargetEvent = []
    ignoreItemList = []
    idList = []
    perfEventData = {}
    commCache = {}
    commFdCache = {}
    fdCache = {}
    libCache = {}
    netAddrCache = {}
    cmdFileCache = {}
    cmdAttachCache = {}
    thresholdData = {}
    thresholdEventList = {}
    thresholdEventHistory = {}

    impPkg = {}
    impGlbPkg = {}
    skipImpPkg = {}
    exitFuncList = []
    dltObj = None
    dltCtx = None
    shmObj = None
    systemdObj = None
    libcObj = None
    libgioObj = None
    libdbusObj = None
    libgObj = None
    libglesObj = None
    statvfsObj = None
    guiderObj = None
    libcppObj = None
    libdemangleObj = None
    matplotlibVersion = long(0)
    matplotlibDpi = 500
    sigsetObj = None
    sigsetOldObj = None

    localServObj = None
    remoteServObj = None
    netlinkObj = None
    geAttr = [0] * 9
    addrListForPrint = {}
    addrListForReport = {}

    maxCore = long(0)
    nrCore = long(0)
    utilProc = long(0)
    logSize = long(0)
    kmsgLine = long(100)
    curLine = long(0)
    totalLine = long(0)
    dbgEventLine = long(0)
    uptime = long(0)
    prevUptime = long(0)
    uptimeDiff = long(0)
    diskStats = []
    prevDiskStats = []
    netstat = ''
    prevNetstat = ''
    loadavg = ''
    netInIndex = -1

    # log #
    printStreamEnable = False
    loggingEnable = False
    dltEnable = False
    kmsgEnable = False
    syslogEnable = False
    journalEnable = False
    terminalOver = False
    logoEnable = True
    colorEnable = True

    cpuAvgEnable = True
    reportEnable = False
    truncEnable = True
    countEnable = False
    reportObject = None
    reportFileEnable = False
    graphEnable = False
    procBuffer = []
    fixedProcList = {}
    topInstance = None
    procInstance = {}
    fileInstance = {}
    sysInstance = None
    procBufferSize = long(0)
    bufferOverflowed = False
    bufferString = ''
    bufferList = []
    bufferRows = long(0)
    systemInfoBuffer = ''
    kerSymTable = {}
    jsonData = {}
    nrTopRank = 10
    layout = None
    avgEnable = False

    showAll = False
    optStrace = False
    disableAll = False
    intervalNow = long(0)
    recordStatus = False
    bgStatus = False
    condExit = False
    sort = None
    sortCond = None

    # file descriptor #
    maxFd = 512
    maxKeepFd = maxFd - 16
    statFd = None
    memFd = None
    zoneFd = None
    lmkFd = None
    irqFd = None
    softirqFd = None
    vmstatFd = None
    swapFd = None
    uptimeFd = None
    netstatFd = None
    netdevFd = None
    shmFd = None
    msgqFd = None
    semFd = None
    loadavgFd = None
    cmdFd = None
    diskStatsFd = None
    mountFd = None
    nullFd = None
    eventLogFd = None
    kmsgFd = None
    syslogFd = None

    # flags #
    fixTargetEnable = False
    irqEnable = False
    cpuEnable = True
    cloneEnable = True
    execEnable = None
    latEnable = cpuEnable
    gpuEnable = True
    memEnable = False
    rssEnable = False
    pssEnable = False
    ussEnable = False
    vssEnable = False
    oomEnable = False
    leakEnable = False
    wssEnable = False
    diskEnable = False
    heapEnable = False
    floatEnable = False
    fileTopEnable = False
    dltTopEnable = False
    dbusTopEnable = False
    ueventEnable = False
    keventEnable = False
    networkEnable = False
    schedEnable = False
    delayEnable = False
    stackEnable = False
    wchanEnable = False
    sigHandlerEnable = False
    wfcEnable = False
    affinityEnable = False
    freeMemEnable = False
    blockEnable = False
    lockEnable = False
    userEnable = True
    userRecordEnable = True
    userEnableWarn = True
    printEnable = True
    bufferLossEnable = False
    jsonEnable = False
    powerEnable = False
    binderEnable = False
    wqEnable = False
    i2cEnable = False
    pipeEnable = False
    depEnable = False
    sysEnable = False
    waitEnable = False
    inWaitStatus = False
    cmdEnable = False
    perfEnable = False
    perfGroupEnable = False
    resetEnable = False
    warnEnable = False
    logEnable = True
    ttyEnable = False
    selectEnable = True
    cgroupEnable = False
    cgTopEnable = False
    cmdlineEnable = False
    schedstatEnable = True
    intervalEnable = long(0)
    forceEnable = False
    functionEnable = False
    systemEnable = False
    fileEnable = False
    threadEnable = False
    nsEnable = False
    termFlag = True
    exitFlag = False
    tgidEnable = True
    taskEnable = True
    exceptCommFilter = False
    processEnable = True
    totalEnable = False
    groupProcEnable = False
    rankProcEnable = True
    inotifyEnable = False
    dwarfEnable = False
    barGraphEnable = False

    # Elastic Stack #
    elasticEnable = False

    cmdList = {}
    rcmdList = {}
    savedProcTree = {}
    savedProcComm = {}
    savedMountTree = {}
    preemptGroup = []
    filterGroup = []
    schedFilter = []
    affinityFilter = []
    killFilter = []
    syscallList = []
    perCoreList = []
    perCoreDrawList = []
    childList = {}
    pidFilter = None



    def __init__(self):
        if not SysMgr.isLinux:
            return

        SysMgr.sysInstance = self

        self.cpuInfo = {}
        self.cpuCacheInfo = {}
        self.memInfo = {}
        self.devInfo = {}
        self.diskInfo = {}
        self.mountInfo = {}
        self.networkInfo = {}
        self.systemInfo = {}
        self.partitionInfo = {}

        self.cpuData = None
        self.gpuData = {}
        self.memData = {}
        self.diskData = {}
        self.storageData = {}
        self.prevStorageData = {}
        self.ipcData = {}
        self.prevIpcData = {}
        self.userData = {}
        self.mountData = None
        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 = []

        # update starttime #
        SysMgr.updateUptime()
        if SysMgr.startTime == 0:
            SysMgr.startTime = \
                SysMgr.startRunTime = \
                    SysMgr.uptime

        # resource update time #
        self.netUpdate = None
        self.storageUpdate = None
        self.ipcUpdate = None

        # 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 loadLibcObj(exit=False):
        if SysMgr.libcObj:
            return True

        try:
            ret = SysMgr.loadLib(SysMgr.libcPath)
            if ret:
                SysMgr.libcObj = ret
                return True
            else:
                SysMgr.printErr('fail to load libc')
                if exit:
                    sys.exit(0)
                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

        if not hasattr(SysMgr.libcObj, 'malloc_trim'):
            SysMgr.printWarn(
                'no malloc_trim in %s' % SysMgr.libcPath)
            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(0)

        # set alarm #
        if SysMgr.intervalEnable:
            signal.signal(signal.SIGALRM, SysMgr.onAlarm)
            signal.alarm(SysMgr.intervalEnable)

        while 1:
            ret = func(msg=msg)
            if ret == 0:
                SysMgr.printInfo(
                    "logged a %s message '%s' successfully" % (mtype, msg))
            else:
                SysMgr.printErr(
                    "fail to log a %s message" % mtype)
                break

            if SysMgr.intervalEnable:
                SysMgr.waitEvent(forceExit=True)
            else:
                os._exit(0)



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

        '''
        maxFdPath = '%s/sys/fs/file-max' % SysMgr.procPath
        try:
            with open(maxFdPath, 'r') as fd:
                availMaxFd = long(fd.read())
        except:
            availMaxFd = SysMgr.maxFd

        if availMaxFd == SysMgr.maxFd:
            return
        '''

        # try to set maxFd with hard limit #
        try:
            resource = SysMgr.getPkg('resource', False, True)
            if resource:
                resource.setrlimit(resource.RLIMIT_NOFILE, (1048576, 1048576))
                soft, hard = resource.getrlimit(resource.RLIMIT_NOFILE)
                SysMgr.maxFd = hard
                SysMgr.maxKeepFd = SysMgr.maxFd - 16
                return
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # try to get maxFd by native call #
        try:
            func = SysMgr.guiderObj.getrlimit # pylint: disable=no-member
            SysMgr.maxFd = \
                func(ConfigMgr.RLIMIT_TYPE.index('RLIMIT_NOFILE'))
            SysMgr.maxKeepFd = SysMgr.maxFd - 16
            return
        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 #
            SysMgr.loadLibcObj()

            SysMgr.libcObj.getrlimit.argtypes = (c_int, POINTER(rlimit))
            SysMgr.libcObj.getrlimit.restype = c_int

            rlim = rlimit()
            rlim.rlim_cur = c_ulong(1048576)
            rlim.rlim_max = c_ulong(1048576)

            ret = SysMgr.libcObj.setrlimit(
                ConfigMgr.RLIMIT_TYPE.index('RLIMIT_NOFILE'), byref(rlim))

            ret = SysMgr.libcObj.getrlimit(
                ConfigMgr.RLIMIT_TYPE.index('RLIMIT_NOFILE'), byref(rlim))

            SysMgr.maxFd = rlim.rlim_cur
            SysMgr.maxKeepFd = SysMgr.maxFd - 16
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn(
                "fail 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 user input #
        SysMgr.waitEvent()

        # save system info #
        SysMgr.sysInstance.saveSysStat()

        # get and remove process tree from data file #
        SysMgr.getProcTreeInfo()

        SysMgr.printLogo(big=True)

        # print system information #
        SysMgr.printPipe(SysMgr.systemInfoBuffer)



    @staticmethod
    def setRecordAttr():
        # function #
        if SysMgr.checkMode('funcrec'):
            SysMgr.functionEnable = True

        # file #
        elif SysMgr.checkMode('filerec'):
            SysMgr.fileEnable = True

        # syscall #
        elif SysMgr.checkMode('sysrec'):
            SysMgr.sysEnable = True
            SysMgr.cpuEnable = False

        # general #
        elif SysMgr.checkMode('genrec'):
            SysMgr.systemEnable = True

        # update record status #
        SysMgr.recordStatus = True
        SysMgr.inputFile = '/sys/kernel/debug/tracing/trace'

        # change priority for process #
        if not SysMgr.prio:
            SysMgr.setPriority(SysMgr.pid, 'C', -20)

        SysMgr.parseRecordOption()
        SysMgr.printProfileOption()
        SysMgr.printProfileCmd()



    @staticmethod
    def getFd(fname, perm='rb'):
        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:
            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])
        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.isThreadMode():
                pass
            elif SysMgr.isFuncMode():
                SysMgr.printErr(
                    "fail to draw because this data is for function")
                sys.exit(0)
            else:
                SysMgr.printErr(
                    "fail to draw because this data is not supported")
                sys.exit(0)

            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(
                "fail to analyze memory-mapped files", reason=True)
            sys.exit(0)

        # save system info #
        SysMgr.sysInstance.saveSysStat()

        # 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():
        while SysMgr.repeatInterval > 0:
            # set alarm #
            signal.alarm(SysMgr.repeatInterval)

            # get init time in buffer for verification #
            initTime = TaskAnalyzer.getInitTime(SysMgr.inputFile)

            # wait for timer #
            try:
                for cnt in range(0, 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:
                    SysMgr.copyPipeToFile(
                        '%s%s' % (SysMgr.inputFile, '_pipe'),
                        SysMgr.outputFile)
                else:
                    SysMgr.printErr(
                        "wrong option used, "
                        "use also -s option to save data")

                sys.exit(0)

            # check counter #
            if SysMgr.repeatCount <= SysMgr.progressCnt and \
                SysMgr.termFlag:
                sys.exit(0)

            # compare init time with now time for buffer verification #
            if initTime < TaskAnalyzer.getInitTime(SysMgr.inputFile):
                SysMgr.printErr(
                    "buffer size is not enough (%sKB)" % \
                    SysMgr.getBufferSize())
                sys.exit(0)
            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(0)

        if not SysMgr.graphEnable:
            # get init time from buffer for verification #
            initTime = TaskAnalyzer.getInitTime(SysMgr.inputFile)

        # wait for user input #
        while 1:
            if SysMgr.recordStatus:
                SysMgr.condExit = True

                SysMgr.waitEvent()
                if SysMgr.condExit:
                    break
            else:
                break

        if not SysMgr.graphEnable:
            # 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(0)

            # save system info #
            SysMgr.sysInstance.saveSysStat()



    @staticmethod
    def execTopCmd():
        # check background processes #
        SysMgr.checkBgProcs()

        # set tty setting automatically #
        if not SysMgr.ttyEnable:
            SysMgr.setTTYAuto(True, False)

        # write user command #
        SysMgr.writeTraceCmd('BEFORE')

        # thread #
        if SysMgr.checkMode('ttop'):
            SysMgr.processEnable = False

        # file #
        elif SysMgr.checkMode('ftop'):
            SysMgr.fileTopEnable = True

        # cgroup #
        elif SysMgr.checkMode('cgtop'):
            SysMgr.cgTopEnable = True

        # stack #
        elif SysMgr.checkMode('stacktop'):
            if SysMgr.checkStackTopCond():
                SysMgr.processEnable = False
                SysMgr.stackEnable = True
            else:
                sys.exit(0)

        # perf #
        elif SysMgr.checkMode('ptop'):
            if SysMgr.checkPerfTopCond():
                SysMgr.perfEnable = True
                if SysMgr.findOption('g'):
                    SysMgr.processEnable = False
                    SysMgr.perfGroupEnable = True
            else:
                sys.exit(0)

        # mem #
        elif SysMgr.checkMode('mtop'):
            if SysMgr.checkMemTopCond():
                SysMgr.memEnable = True
                SysMgr.sort = 'm'
            else:
                sys.exit(0)

        # WSS (working set size) #
        elif SysMgr.checkMode('wtop'):
            if SysMgr.checkWssTopCond():
                SysMgr.memEnable = True
                SysMgr.wssEnable = True
                SysMgr.sort = 'm'
            else:
                sys.exit(0)

        # disk #
        elif SysMgr.checkMode('disktop'):
            if SysMgr.checkDiskTopCond():
                SysMgr.diskEnable = True
                SysMgr.blockEnable = True
                SysMgr.sort = 'b'
            else:
                sys.exit(0)

        # 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 path for config file #
            if not SysMgr.getOption('C'):
                if not SysMgr.loadConfig(SysMgr.confFileName):
                    SysMgr.printErr(
                        'input effective file path for config')
                    sys.exit(0)

            # ignore output #
            if not SysMgr.outPath:
                SysMgr.outPath = SysMgr.nullPath
                SysMgr.bufferSize = -1

        # 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')

        # network #
        elif SysMgr.checkMode('ntop'):
            SysMgr.networkEnable = True

        # background #
        elif SysMgr.checkMode('bgtop'):
            if not SysMgr.checkBgTopCond():
                sys.exit(0)

            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

            if SysMgr.isRoot():
                SysMgr.diskEnable = True
                SysMgr.networkEnable = True

                disableList = SysMgr.getOption('d')
                if disableList:
                    if 'd' in disableList:
                        SysMgr.diskEnable = False
                    if 'n' in disableList:
                        SysMgr.networkEnable = False
            else:
                SysMgr.printWarn(
                    "fail to get stats for disk and network "
                    "because of no root permission")

            if not SysMgr.checkRepTopCond():
                sys.exit(0)

        # print profile option #
        if not SysMgr.isDrawMode():
            SysMgr.printProfileOption()
            SysMgr.printProfileCmd()

        # set handler for exit #
        SysMgr.setNormalSignal()

        # run process / file monitoring #
        TaskAnalyzer()



    @staticmethod
    def loadLibCache():
        try:
            if not os.path.exists(SysMgr.ldCachePath):
                raise Exception("no %s" % SysMgr.ldCachePath)

            libDict = {}
            libList = UtilMgr.convBin2Str(SysMgr.ldCachePath)
            for idx, item in enumerate(libList):
                try:
                    if libList[idx+1].startswith('/'):
                        value = libList[idx+1]
                        libDict.setdefault(item, list())
                        libDict[item].append(value)
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

            SysMgr.libCache = libDict
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn('fail 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():
            if not key.startswith(lib):
                continue

            if inc and key.startswith(lib):
                return val

            if (key[len(lib)] == '.' or key[len(lib)] == '-'):
                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):
        if not SysMgr.importPkgItems('ctypes', False):
            return

        # absolute path #
        if path:
            return CDLL(lib)

        target = SysMgr.findLib(lib)
        if not target:
            target = ['%s.so' % lib]
            ret = FileAnalyzer.getMapFilePath(SysMgr.pid, lib)
            if ret:
                target.append(ret)

        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(0)

        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(
                    "fail to set signal", True)
                sys.exit(0)



    @staticmethod
    def parseAffinityOption(jobs, launch=False):
        if not jobs:
            SysMgr.printErr("wrong option value")
            sys.exit(0)

        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.getPids(tid, sibling=sibling)
                    targetList = list(map(long, targetList))
                    if targetList:
                        SysMgr.setAffinity(mask, targetList)
                    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(0)



    @staticmethod
    def doDump():
        # get argument #
        if SysMgr.hasMainArg():
            inputParam = SysMgr.getMainArg()
        elif SysMgr.inputParam:
            inputParam = SysMgr.inputParam
        else:
            SysMgr.printErr("no input for COMM or PID")
            sys.exit(0)

        if not inputParam:
            SysMgr.printErr("no input for memory info")
            sys.exit(0)
        elif not SysMgr.outPath:
            SysMgr.printErr("no input for path")
            sys.exit(0)

        # convert comm to pid #
        targetList = []
        for item in inputParam:
            targetList += SysMgr.getPids(item, isThread=False)
        targetList = list(set(targetList))

        # check target #
        if not targetList:
            SysMgr.printErr("no target process")
            sys.exit(0)
        elif len(targetList) > 1:
            SysMgr.printErr(
                "found multiple tasks [%s]" % \
                    SysMgr.getCommList(targetList))
            sys.exit(0)

        pid = targetList[0]
        meminfo = SysMgr.inputParam
        output = SysMgr.outPath

        # dump memory #
        Debugger.dumpTaskMemory(pid, meminfo, output)



    @staticmethod
    def doStrings():
        # get argument #
        if SysMgr.hasMainArg():
            inputParam = SysMgr.getMainArg()
        elif SysMgr.inputParam:
            inputParam = SysMgr.inputParam
            SysMgr.printErr("no input for path")
            sys.exit(0)

        SysMgr.setStream()

        SysMgr.printStat('start reading %s...' % inputParam)

        # convert binary file to string #
        clist = UtilMgr.convBin2Str(inputParam, pos=True)
        if not clist:
            SysMgr.printErr("no available string")
            return

        lastPos = sorted(clist.values())[-1]
        maxDigit = len(hex(lastPos))

        # print strings #
        for string, pos in sorted(clist.items(), key=lambda e:e[1]):
            SysMgr.printPipe(
                '{0:>{digit}} {1}'.format(hex(pos), string, digit=maxDigit))



    @staticmethod
    def doSetAffinity():
        SysMgr.warnEnable = True

        # get argument #
        if SysMgr.hasMainArg():
            value = SysMgr.getMainArg().split(',')
        elif SysMgr.filterGroup:
            value = SysMgr.filterGroup
        else:
            SysMgr.printErr(
                "fail to set CPU affinity of task because of no target")
            sys.exit(0)

        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 applyThreshold():
        def _getMaxInterval(node, maxVal=0):
            for key, item in node.items():
                if type(item) is list:
                    for subitem in item:
                        if type(subitem) is not dict:
                            continue
                        val = _getMaxInterval(subitem, maxVal)
                        if maxVal < val:
                            maxVal = val
                elif type(item) is dict:
                    val = _getMaxInterval(item, maxVal)
                    if maxVal < val:
                        maxVal = val
                elif key == 'interval' and UtilMgr.isNumber(item):
                    item = long(item)
                    if maxVal < item:
                        maxVal = item
            return maxVal

        def _checkResource(item):
            try:
                if item['apply'] == 'true':
                    return True
            except:
                pass

            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 _checkPerm(item):
            try:
                if item['apply'] == 'true' and \
                    item['perm'] == 'root':
                    SysMgr.checkRootPerm(msg=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)

        if not 'threshold' in ConfigMgr.confData:
            return

        confData = SysMgr.getConfigDict('threshold')
        if not confData:
            return

        if type(confData) is not dict:
            return

        SysMgr.reportEnable = True
        SysMgr.rankProcEnable = False
        SysMgr.thresholdData = confData

        # check permission #
        _checkPerm(SysMgr.thresholdData)

        # check storage option #
        try:
            if _checkResource(SysMgr.thresholdData['storage']):
                SysMgr.diskEnable = True
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # check network option #
        try:
            if _checkResource(SysMgr.thresholdData['net']):
                SysMgr.networkEnable = True
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # update maximum interval #
        maxInterval = _getMaxInterval(confData)
        if maxInterval > SysMgr.maxInterval:
            SysMgr.maxInterval = maxInterval

        SysMgr.printInfo(
            "applied for thresholds from %s" % SysMgr.confFileName)

        SysMgr.printWarn(UtilMgr.convDict2Str(confData))



    @staticmethod
    def doGetAffinity():
        SysMgr.warnEnable = True

        # get argument #
        if SysMgr.hasMainArg():
            value = SysMgr.getMainArg().split(',')
        elif SysMgr.filterGroup:
            value = SysMgr.filterGroup
        else:
            SysMgr.printErr(
                "fail to get CPU affinity of task because of no target")
            sys.exit(0)

        SysMgr.checkRootPerm()

        sibling = SysMgr.groupProcEnable
        targetList = []

        try:
            for item in value:
                targetList += SysMgr.getPids(item, sibling=sibling)

            if not targetList:
                SysMgr.printErr(
                    "no thread related to '%s'" % item)
                sys.exit(0)

            targetList = list(set(targetList))
            targetList = list(map(long, targetList))

            for tid in targetList:
                mask = SysMgr.getAffinity(tid)
                if not mask:
                    SysMgr.printErr(
                        "fail to get CPU affinity of %s(%s)" % \
                            (SysMgr.getComm(tid), tid))
                else:
                    SysMgr.printInfo(
                        'affinity of %s(%s) is %s' % \
                            (SysMgr.getComm(tid), tid, mask))
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "fail to get CPU affinity of task", True)
            sys.exit(0)



    @staticmethod
    def setStream(cut=True):
        if not cut:
            SysMgr.ttyCols = long(0)

        SysMgr.printStreamEnable = True
        SysMgr.encodeEnable = False



    @staticmethod
    def setAffinity(mask, pids, isProcess=False):
        # check root permission #
        if len(pids) == 1 and \
            str(pids[0]).isdigit() and \
            SysMgr.pid == long(pids[0]):
            pass
        elif not SysMgr.isRoot():
            SysMgr.printWarn(
                "no root permission to 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('fail to recognize pid %s' % pid)
                    return
        else:
            SysMgr.printErr('fail to recognize pid type')
            return

        # check mask type #
        try:
            mask = long(mask, 16)
            if mask == 0:
                SysMgr.printErr(
                    'fail to set mask to 0, use bit mask bigger than 0')
                return
        except:
            SysMgr.printErr('fail to recognize mask type')
            return

        # load libc #
        SysMgr.loadLibcObj(exit=True)

        # get the number of core #
        nrCore = SysMgr.getNrCore()

        for pid in pids:
            if isProcess:
                threadList = SysMgr.getThreadList(pid)
            else:
                threadList = [pid]

            for pid in 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:
                    SysMgr.libcObj.sched_setaffinity.argtypes = \
                        [c_int, c_ulong, POINTER(c_ulong)]

                    ret = SysMgr.libcObj.sched_setaffinity(
                        long(pid), nrCore,
                        byref(c_ulong(((0x1 << nrCore) - 1) & mask)))
                except SystemExit:
                    sys.exit(0)
                except:
                    ret = -1
                    SysMgr.printWarn(
                        "fail to set CPU affinity of tasks "
                        "because of sched_setaffinity fail")

                if ret >= 0:
                    SysMgr.printInfo(
                        'affinity of %s(%s) is changed to 0x%X' % \
                            (SysMgr.getComm(pid), pid, mask))
                else:
                    SysMgr.printErr(
                        'fail to set affinity of %s(%s) as 0x%X' % \
                            (SysMgr.getComm(pid), pid, mask))



    @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')

            SysMgr.libcObj.sched_getaffinity.argtypes = \
                [c_int, c_ulong, POINTER(c_ulong)]

            cpuset = c_ulong(0)

            size = long(1024 / (sizeof(c_ulong) * 8))
            ret = SysMgr.libcObj.sched_getaffinity(
                long(pid), size, pointer(cpuset))

            if ret >= 0:
                return hex(cpuset.value).rstrip('L')
            else:
                raise Exception('wrong affinity')
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn((
                "fail to get CPU affinity of tasks "
                "because of sched_getaffinity fail"))



    @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(
                "fail to read %s" % maxThdPath, reason=True)
            return None



    @staticmethod
    def setOOMAdj(pid='self', pri='-17'):
        if not SysMgr.isLinux:
            return

        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(
                "fail to write %s" % oomPath, reason=True)



    @staticmethod
    def ping(url=[], timeout=None, count=None):
        ICMP_ECHO_REQUEST = 8

        def _checksum(source):
            sum = 0
            countTo = (len(source)/2)*2
            count = 0
            while count < countTo:
                if type(source[count+1]) is long:
                    data1 = source[count+1]
                else:
                    data1 = ord(source[count+1])

                if type(source[count]) is long:
                    data2 = source[count]
                else:
                    data2 = ord(source[count])

                thisVal = data1*256 + data2
                sum = sum + thisVal
                sum = sum & 0xffffffff # Necessary?
                count = count + 2

            if countTo < len(source):
                sum = sum + ord(source[len(source) - 1])
                sum = sum & 0xffffffff # Necessary?

            sum = (sum >> 16)  +  (sum & 0xffff)
            sum = sum + (sum >> 16)
            answer = ~sum
            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 True:
                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 range(long(start), long(end)+1):
                            if not addrs:
                                newAddrs.append(idx)
                                continue

                            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, idx))
                elif item == '*':
                    for idx in range(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('fail to ping', True)
                return 0

            # define socket list #
            sockList = list()
            sockInfo = dict()

            # 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('fail 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': dict(), 'fail': dict()}

            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, dict())
                        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, dict())
                        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))
            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.isRoot():
            SysMgr.printErr(
                'fail to ping because of no root permission')
            return

        # get address list #
        urlList = []
        if url:
            urlList = url
        elif SysMgr.hasMainArg():
            urlList = SysMgr.getMainArg().split(',')
            urlList = UtilMgr.cleanItem(urlList)
        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(
                    "fail to read addresses from '%s'" % \
                        ','.join(files), True)
                sys.exit(0)

        # check input #
        if not urlList:
            SysMgr.printErr('no input for address')
            sys.exit(0)

        # convert addresses #
        urlList = _convAddrs(urlList)

        # set repeat count #
        if not count:
            if SysMgr.repeatInterval == 0:
                count = 1
            else:
                count = SysMgr.repeatInterval
        SysMgr.printInfo(
            'set repeat count to %s' % UtilMgr.convNum(count))

        # set timeout #
        if not timeout:
            timeout = SysMgr.getOption('T')
            if timeout:
                try:
                    timeout = float(timeout)
                except:
                    SysMgr.printErr(
                        "fail to set timeout '%s'" % timeout, True)
                    sys.exit(0)
            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(0, count):
            try:
                _doPing(urlList, timeout, seq=seq)
                time.sleep(interval)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    'fail to send ping to %s', True)



    @staticmethod
    def getExeCmd(pid):
        cmd = SysMgr.getCmdline(pid, retList=True)[:2]
        if cmd[1][0] != '/':
            pwd = SysMgr.getCwd(pid)
            cmd[1] = '%s/%s' % (pwd, cmd[1])
        return cmd



    @staticmethod
    def getConfigDict(name):
        confData = ConfigMgr.confData[name]
        if type(confData) is list:
            confData = UtilMgr.convStr2Dict('\n'.join(confData), True)

        if type(confData) is dict:
            return confData
        else:
            return None



    @staticmethod
    def getConfigList(name):
        confData = ConfigMgr.confData[name]
        if type(confData) is list:
            return confData
        else:
            return None



    @staticmethod
    def loadConfig(fname, verb=True):
        try:
            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, list())
                    targetList = ConfigMgr.confData[entry]
                    continue
                else:
                    targetList.append(line)

            return ConfigMgr.confData
        except SystemExit:
            sys.exit(0)
        except:
            if verb:
                SysMgr.printErr(
                    "fail to load config from '%s'" % fname, reason=True)
            return None
        finally:
            if fd:
                fd.close()



    @staticmethod
    def getCwd(pid):
        cwdPath = '%s/%s/cwd' % (SysMgr.procPath, pid)
        return os.readlink(cwdPath)



    @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(
                "fail to get path for python library", reason=True)



    @staticmethod
    def getExeName(pid):
        exePath = '%s/%s/exe' % (SysMgr.procPath, pid)
        try:
            return os.readlink(exePath)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn(
                "fail to get binary path for %s process" % pid, reason=True)
            return None



    @staticmethod
    def getCmdline(pid, retList=False):
        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):
        statusPath = \
            '%s/%s/status' % (SysMgr.procPath, pid)
        try:
            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(
                'fail to get UID for %s(%s)' % (comm, pid), reason=True)

        return 0



    @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

        return mmap.mmap(-1, size)



    @staticmethod
    def getCommList(pidList):
        try:
            commList = ['%s(%s)' % \
                (SysMgr.getComm(pid), pid) for pid in pidList]
            return ', '.join(commList)
        except:
            return ', '.join(pidList)



    @staticmethod
    def getPwd(pid):
        pwdPath = \
            '%s/%s/cwd' % (SysMgr.procPath, pid)
        pwd = None

        try:
            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]

        try:
            if pid in SysMgr.commFdCache:
                fd = SysMgr.commFdCache[pid]
                fd.seek(0)
                comm = fd.readline()[:-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')
                return psutil.Process(pid).name()
            except:
                pass

        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):
        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(
                "fail 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("fail 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(
                'fail to set 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 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].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(
                "fail to import python package: %s " % name, isExit)

            # register to blacklist #
            SysMgr.skipImpPkg[name] = True

            # check return condition #
            if isExit:
                sys.exit(0)
            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 = long(0)
        curWriteMsTotal = prevWriteMsTotal = long(0)
        curNrReadTotal = prevNrReadTotal = long(0)
        curNrWriteTotal = prevNrWriteTotal = long(0)
        curIoMsTotal = prevIoMsTotal = long(0)
        curWIoMsTotal = prevWIoMsTotal = long(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] = dict()
            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



    @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 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():
        if not SysMgr.pidFilter:
            cmd = ""
            for cond in list(SysMgr.filterGroup):
                try:
                    cmd += "common_pid == %s || " % long(cond)
                except:
                    try:
                        ldir = cond.find('>')
                        if ldir == 0:
                            cmd += "common_pid >= %s || " % long(cond[1:])
                        elif ldir == len(cond) - 1:
                            cmd += "common_pid <= %s || " % long(cond[:-1])

                        rdir = cond.find('<')
                        if rdir == 0:
                            cmd += "common_pid <= %s || " % long(cond[1:])
                        elif rdir == len(cond) - 1:
                            cmd += "common_pid >= %s || " % long(cond[:-1])
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass

            if cmd != "":
                cmd = "(" + cmd[:cmd.rfind('||')] + ")"

            SysMgr.pidFilter = cmd

        return SysMgr.pidFilter



    @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 in comm or \
                item == '' or \
                SysMgr.isValidTid(tid, item):
                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 == 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]+)\]\s+'
            r'(?P<time>\S+):\s+(?P<func>\S+)(?P<etc>.+)'), string)

        return m



    @staticmethod
    def isValidEnableOption(options):
        if not options:
            return False

        optionList = 'BCDEFGHILNPRSTWYabcdefghijklmnopqrrstuvwxy'
        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)
            else:
                pass
        except:
            pass

        # restore SIGINT handler #
        if SysMgr.waitEnable and block:
            signal.signal(signal.SIGINT, handle)



    @staticmethod
    def backupFile(origFile):
        if not os.path.isfile(origFile):
            return

        try:
            newFile = '%s.old' % origFile

            os.rename(origFile, newFile)

            SysMgr.printInfo(
                "renamed '%s' to '%s' for backup" % \
                    (origFile, newFile))
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "fail to backup '%s' to '%s'" % \
                    (origFile, newFile), True)



    @staticmethod
    def convRealPath(flist):
        if UtilMgr.isString(flist):
            flist = [flist]

        nlist = []
        for path in flist:
            path = path.strip()

            if path.startswith('^'):
                path = path[1:]
                exflag = True
            else:
                exflag = False

            try:
                rpath = os.readlink(path)
                if not rpath.startswith('/'):
                    dirname = os.path.dirname(path)
                    rpath = os.path.join(dirname, 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(
                        "fail to convert '%s' to real path" % path,
                            reason=True, always=True)

        return nlist



    @staticmethod
    def getErrReason():
        if not SysMgr.importPkgItems('ctypes', False):
            return

        err = get_errno()
        if err in errno.errorcode:
            return errno.errorcode[err]
        else:
            return None



    @staticmethod
    def getProcTree():
        procTree = {}

        # get process list in proc filesystem #
        try:
            pids = os.listdir(SysMgr.procPath)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenErr(SysMgr.procPath)
            return None

        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:
                    long(tid)

                    # update comm of thread #
                    SysMgr.getComm(tid, save=True)

                    if tid == pid:
                        procTree[tid] = '%s(%s)' % (pid, comm)
                    else:
                        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")
        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 == 'C':
            if not SysMgr.checkMode('ttop'):
                SysMgr.printErr(
                   "fail to sort by CONTEXTSWITCH because "
                    "it is supported on thread mode")
                sys.exit(0)
            SysMgr.printInfo("sorted by CONTEXTSWITCH")
        elif not value:
            value = None
        else:
            SysMgr.printErr(
                "wrong option value '%s' for sort" % value)
            return False

        # set values #
        SysMgr.sort = value
        SysMgr.sortCond = cond

        return True



    @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 getMainArg(path=False):
        if len(sys.argv) <= 2:
            return None
        else:
            if not path:
                return sys.argv[2]
            return UtilMgr.convPath(sys.argv[2], retStr=True, separator=',')



    @staticmethod
    def checkEnv():
        # check os #
        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

                # 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

            # android #
            if 'ANDROID_ROOT' in os.environ:
                SysMgr.isAndroid = True
                SysMgr.libcPath = 'libc'
                SysMgr.libcppPath = 'libstdc++'
                SysMgr.libdemanglePath = 'libgccdemangle'
                SysMgr.cacheDirPath = '/data/log/guider'
                SysMgr.colorEnable = False
        elif sys.platform.startswith('win') or \
            sys.platform.startswith('darwin'):
            SysMgr.isLinux = False
            if len(sys.argv) > 1 and \
                not SysMgr.checkMode('cli') and \
                not SysMgr.isDrawMode() and \
                not SysMgr.checkMode('convert') and \
                not SysMgr.checkMode('drawreq') and \
                not SysMgr.checkMode('readelf') and \
                not SysMgr.checkMode('addr2sym') and \
                not SysMgr.checkMode('mkcache') and \
                not SysMgr.checkMode('sym2addr') and \
                not SysMgr.checkMode('topdiff') and \
                not SysMgr.checkMode('topsum') and \
                not SysMgr.checkMode('printdir') and \
                not SysMgr.checkMode('report') and \
                not SysMgr.checkMode('exec') and \
                not SysMgr.checkMode('comp') and \
                not SysMgr.checkMode('decomp') and \
                not SysMgr.checkMode('req') and \
                not SysMgr.checkMode('ping') and \
                not SysMgr.isHelpMode():
                if len(sys.argv) == 1:
                    arg = sys.argv[0]
                else:
                    arg = sys.argv[1]

                SysMgr.printErr(
                    '%s command is not supported on %s platform now' % \
                        (arg, sys.platform))
                sys.exit(0)
        else:
            SysMgr.printErr(
                '%s platform is not supported now' % sys.platform)
            sys.exit(0)

        # check locale #
        try:
            if SysMgr.encodeEnable:
                if 'NOENCODE' in os.environ:
                    SysMgr.encodeEnable = False
                else:
                    lang = os.getenv('LANG')
                    if not lang or not 'UTF' in lang:
                        SysMgr.encodeEnable = False
        except:
            pass

        # check python #
        if sys.version_info < (2, 6):
            SysMgr.printWarn(
                'python version is %d.%d so that some features may not work'
                % (sys.version_info[0], sys.version_info[1]))



    @staticmethod
    def onAlarmExit(signum, frame):
        SysMgr.updateTimer()

        sys.exit(0)



    @staticmethod
    def onAlarm(signum, frame):
        SysMgr.progressCnt += 1
        if SysMgr.repeatCount <= SysMgr.progressCnt:
            sys.exit(0)

        SysMgr.updateTimer()



    @staticmethod
    def checkProgress():
        if not SysMgr.countEnable:
            return

        if SysMgr.progressCnt >= SysMgr.repeatCount:
            # remove progress #
            UtilMgr.deleteProgress()

            try:
                os.kill(SysMgr.pid, signal.SIGINT)
            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 len(prefix) > 0:
                    types = '[%s]' % prefix.upper()
                else:
                    types = ' '

                cmdbuf = '%s%4s%-12s%4s%-12s%4s<%-s>\n' % \
                    (cmdbuf, ' ', types, ' ', cmd, ' ', cvalue)
                prefix = ''
            cmdbuf = '%s\n' % cmdbuf

        return cmdbuf[:-1]



    @staticmethod
    def getCmdList():
        return {
            'monitor': {
                'atop': 'System',
                'bgtop': 'Background',
                'btop': 'Function',
                'ctop': 'Threshold',
                'cgtop': 'Cgroup',
                'dbustop': 'D-Bus',
                'disktop': 'Storage',
                'dlttop': 'DLT',
                'ftop': 'File',
                'mtop': 'Memory',
                'ntop': 'Network',
                'ptop': 'PMU',
                'rtop': 'JSON',
                'stacktop': 'Stack',
                'systop': 'Syscall',
                'top': 'Process',
                'ttop': 'Thread',
                'utop': 'Function',
                'pytop': 'Python',
                'wtop': 'WSS',
                },
            'trace': {
                'btrace': 'Breakpoint',
                'sigtrace': 'Signal',
                'strace': 'Syscall',
                'utrace': 'Function',
                },
            'profile': {
                'filerec': 'File',
                'funcrec': 'Function',
                'genrec': 'System',
                'mem': 'Page',
                'rec': 'Thread',
                'report': 'Report',
                'sysrec': 'Syscall',
                },
            'visual': {
                'convert': 'Text',
                'draw': 'System',
                'drawavg': 'Average',
                'drawcpu': 'CPU',
                'drawcpuavg': 'CPU',
                'drawdelay': 'Delay',
                'drawflame': 'Function',
                'drawio': 'I/O',
                'drawleak': 'Leak',
                'drawmem': 'Memory',
                'drawmemavg': 'Memory',
                'drawreq': 'URL',
                'drawrss': 'RSS',
                'drawrssavg': 'RSS',
                'drawtime': 'Timeline',
                'drawvss': 'VSS',
                'drawvssavg': 'VSS',
                },
            'util': {
                'addr2sym': 'Symbol',
                'dump': 'Memory',
                'exec': 'Command',
                'getafnt': 'Affinity',
                'comp': "Compress",
                'hook': 'Function',
                'kill/tkill': 'Signal',
                'leaktrace': 'Leak',
                'limitcpu': 'CPU',
                'mkcache': 'Cache',
                'pause': 'Thread',
                'ping': 'PING',
                'printbind': 'Funcion',
                'printcg': 'Cgroup',
                'printdbus': 'D-Bus',
                'printdbusinfo': 'D-Bus',
                'printdir': 'Dir',
                'printenv': 'Env',
                'printinfo': 'System',
                'printns': 'Namespace',
                'printsig': 'Signal',
                'printsub': 'D-Bus',
                'printsvc': 'systemd',
                'pstree': 'Process',
                'readelf': 'File',
                'remote': 'Command',
                'req': 'URL',
                'setafnt': 'Affinity',
                'setcpu': 'Clock',
                'setsched': 'Priority',
                'strings': 'Text',
                'sym2addr': 'Address',
                'systat': 'Status',
                'topdiff': 'Diff',
                'topsum': 'Summary',
                'decomp': 'Decompress',
                'watch': "File",
                },
            'log': {
                'logdlt': 'DLT',
                'logjrl': 'Journal',
                'logkmsg': 'Kernel',
                'logsys': 'Syslog',
                'printdlt': 'DLT',
                'printkmsg': 'Kernel',
                'printsys': 'Syslog',
                'printjrl': 'Journal',
                },
            'control': {
                'cli': 'Client',
                'event': 'Event',
                'list': 'List',
                'send': 'Signal',
                'server': 'Server',
                'start': 'Signal',
                },
            'test': {
                'cputest': 'CPU',
                'iotest ': 'Storage',
                'memtest': 'Memory',
                'nettest ': 'Network',
                },
            }



    @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 extention #
            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                          wait for input
    -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:TIME / e:exectime:TIME
            P:prio / C:contextswitch / o:oomscore ]
    -P                          group threads in a same process
    -I  <DIR|FILE>              set input 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
          [ dlt / kmsg / journal / 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}>
    -v                          verbose
                '''

                topSubStr = '''
Options:
    -e  <CHARACTER>             enable options
          [ a:affinity | b:block | 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:cmdline
            m:mem | n:net | N:namespace | o:oomScore
            O:color | p:pipe | P:perf | q:quit | r:report
            R:fileReport | 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
            c:cpu | C:clone | D:DWARF | e:encode
            E:exec | g:generalInfo | G:gpu | L:log
            p:print | t:truncate | T:task ]
                '''

                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
                    '''

                if SysMgr.checkMode('ttop'):
                    target = 'threads'
                else:
                    target = 'processes'

                topExamStr = '''
Examples:
    - Monitor status of {2:2} used CPU resource more than 1%% every interval
        # {0:1} {1:1}

    - Monitor status of {2:2} used CPU resource totally
        # {0:1} {1:1} -e T

    - Monitor status of all {2:2} with bar graphs for cores
        # {0:1} {1:1} -a -e B

    - Monitor status of all {2:2} sorted by memory(RSS)
        # {0:1} {1:1} -S m
        # {0:1} {1:1} -S m:500

    - Monitor status of all {2:2} sorted by execution time
        # {0:1} {1:1} -S e
        # {0:1} {1:1} -S e:2h

    - Monitor status of threads context-switched more than 5000 after sorting by Context Switch
        # {0:1} {1:1} -S C:5000

    - Report analysis results of {2:2} to ./guider.out when SIGINT signal arrives
        # {0:1} {1:1} -o .

    - Report analysis results of {2:2} with the fixed task list to save CPU resource for monitoring
        # {0:1} {1:1} -g a.out -e x

    - Monitor status and change priority for all {2:2} every second
        # {0:1} {1:1} -Y "c:-20::CONT" -a

    - Monitor status and change priority for specific {2:2} having name including a.out every second
        # {0:1} {1:1} -g a.out -Y "c:-20:a.out:CONT"

    - Report analysis results of {2:2} to ./guider.out with unlimited memory buffer
        # {0:1} {1:1} -o . -b 0

    - Report analysis results of {2:2} to ./guider.out with limited memory buffer 50MB
        # {0:1} {1:1} -o . -b 50m

    - Report analysis results of {2:2} to ./guider.out with limited memory buffer 50MB loss possible
        # {0:1} {1:1} -o . -d b

    - Report analysis results of {2:2} to ./guider.out in real-time until SIGINT signal arrives
        # {0:1} {1:1} -o . -e p

    - Report analysis results of {2:2} collected every 3 seconds for total 5 minutes to ./guider.out
        # {0:1} {1:1} -R 3s:5m -o .

    - Report analysis results of {2:2} collected every 3 seconds for 5 times to ./guider.out
        # {0:1} {1:1} -R 3s:5 -o .

    - Report analysis results of {2:2} collected every 10 seconds for 60 minutes to ./guider.out
        # {0:1} {1:1} -i 10 -R 60m -o .

    - Report analysis results of {2:2} collected every 3 seconds for 5 minutes to ./guider.out continuously
        # {0:1} {1:1} -R 3s:5m: -o .

    - Monitor status of {2:2} with memory(USS)
        # {0:1} {1:1} -e u

    - Monitor status of {2:2} with memory(PSS)
        # {0:1} {1:1} -e S

    - Monitor status of all {2:2} including block usage every 2 seconds
        # {0:1} {1:1} -e b -i 2 -a

    - Monitor status of {2:2} involved in a same process group with specific {2:2} having name including system
        # {0:1} {1:1} -g system -P

    - Monitor status of {2:2} on the minimum terminal
        # {0:1} {1:1} -m

    - Monitor status of {2:2} on the optimized terminal
        # {0:1} {1:1} -m :

    - Monitor status of {2:2} after optimizing system terminal
        # {0:1} {1:1} -m ::system

    - Monitor status of {2:2} and report to elastic search
        # {0:1} {1:1} -e I

    - Report analysis results of {2:2} to ./guider.out and console
        # {0:1} {1:1} -o . -Q

    - Monitor status of {2:2} and execute special commands
        # {0:1} {1:1} -w AFTER:/tmp/touched:1, AFTER:ls

    - Monitor status of {2:2} and report to 192.168.0.5:5555 in real-time
        # {0:1} {1:1} -e r -N REPORT_ALWAYS@192.168.0.5:5555

    - Monitor status of {2:2} after setting hot commands in advance
        # {0:1} {1:1} -c "{0:1} utop -g PID"
        # {0:1} {1:1} -c "{0:1} btrace -g PID *write*|getret\, __write_nocancel|getret"

    - Monitor status of {2:2} and execute specific commands for all tasks shown automatically
        # {0:1} {1:1} -c "{0:1} utop -g PID" -e E
        # {0:1} {1:1} -c "{0:1} btrace -g PID *write*|getret\, __write_nocancel|getret" -e E

    - Monitor status of {2:2} after setting config from guider.conf
        # {0:1} {1:1} -C guider.conf

    - Monitor status of {2:2} with no encoding lines
        # {0:1} {1:1} -d e
        # NOENCODE=1 {0:1} {1:1} -d e
                '''.format(cmd, mode, target)

                drawExamStr = '''
Examples:
    - Draw resource graph and memory chart
        # {0:1} {1:1} guider.out

    - Draw resource graph and timeline chart
        # {0:1} {1:1} guider.dat

    - Draw resource graph and timeline chart in ns timeunit
        # {0:1} {1:1} guider.dat -q TIMEUNIT:ns

    - Draw resource graph and event markers on specific points
        # {0:1} {1:1} guider.dat -q EVENT:14:90:EVENT_1:cpu, EVENT:30:100:EVENT_2:cpu

    - Draw resource graph and timeline chart for all events and tasks
        # {0:1} {1:1} guider.dat -a

    - Draw resource graph and timeline chart for specific cores
        # {0:1} {1:1} guider.dat -O 1, 4, 10

    - Draw resource graph and memory chart 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 resource graph and timeline chart with config file
        # {0:1} {1:1} guider.dat -C config.json

    - Draw resource graph excluding chrome process and memory chart
        # {0:1} {1:1} guider.out -g ^chrome

    - Draw resource graph with some boundary lines
        # {0:1} {1:1} guider.out worstcase.out -l 80, 100, 120

    - Draw resource graph 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

    - Draw resource graph with y range 1-100
        # {0:1} {1:1} guider.out worstcase.out -q YRANGE:1:100

    - Draw resource graph with specific font size
        # {0:1} {1:1} guider.out worstcase.out -q FONTSIZE:15

    - Draw resource graph of top 5 processes
        # {0:1} {1:1} guider.out worstcase.out -T 5

    - Draw graphs of total CPU usage by applying the multiplication of the number of CPUs
        # {0:1} {1:1} guider.out worstcase.out -d A

    - Draw resource graph 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 resource graph on devices for block and network
        # {0:1} {1:1} guider.out -e d n

    - Draw resource graph with multiple files for comparison
        # {0:1} {1:1} "guider*.out" worstcase.out

    - Draw graphs of total resource usage with multiple files for comparison
        # {0:1} {1:1} "guider*.out" worstcase.out -a -g TOTAL
                '''.format(cmd, mode)

                brkExamStr = '''
Commands:
    acc      print accumulation stat [NAME:VAR|REG|VAL]
    check    check values [VAR|ADDR|REG:OP(EQ/DF/INC/BT/LT):VAR|VAL:SIZE:EVENT]
    condexit exit if tracing was started
    dist     print distribution stat [NAME:VAR|REG|VAL]
    dump     dump specific memory range to a file [NAME|ADDR:FILE]
    exec     execute command [CMD]
    exit     exit
    filter   print only filtered context [VAR|ADDR|REG: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]
    jump     jump to specific function with specific arguments [FUNC#ARGS]
    kill     terminate target
    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]
    pystr    execute python code [CODE:SYNC]
    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]
    sleep    sleep for seconds [SEC]
    start    start printing all functions
    stop     pause tracing
    syscall  call a syscall [FUNC#ARGS]
    thread   create a new thread
    usercall call a specific function [FUNC#ARGS]
    wrmem    change specific memory or register [VAR|ADDR|REG:VAL:SIZE]

Examples:
    - Print all call contexts for a specific thread
        # {0:1} {1:1} -g 1234

    - Print all call contexts from a specific binary
        # {0:1} {1:1} "ls"
        # {0:1} {1:1} -I "ls"

    - Print all call contexts and standard output from a specific binary
        # {0:1} {1:1} "ls" -q NOMUTE

    - Print all call contexts except for wait status for a specific thread
        # {0:1} {1:1} a.out -g a.out -q EXCEPTWAIT

    - Print all call contexts except for register info for a specific thread
        # {0:1} {1:1} a.out -g a.out -q NOCONTEXT

    - Print all call contexts for a specific thread after loading all symbols in stop status
        # {0:1} {1:1} a.out -g a.out -q STOPTARGET

    - Print all call contexts except for no symbol functions for a specific thread
        # {0:1} {1:1} a.out -g a.out -q EXCEPTNOSYM

    - Print all call contexts except for ld for a specific thread
        # {0:1} {1:1} a.out -g a.out -q EXCEPTLD

    - Print all call contexts and injection info for a specific thread
        # {0:1} {1:1} a.out -g a.out -q TRACEINJECTION

    - Print all call contexts for 4th new threads in each new processes from a specific binary
        # {0:1} {1:1} a.out -g a.out -q TARGETNUM:4
        # {0:1} {1:1} -I a.out -g a.out -q TARGETNUM:4

    - Print all call contexts from a specific binary with DWARF info
        # {0:1} {1:1} -I "ls" -eD

    - Print all call contexts from a specific binary with 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

    - Print all call contexts with backtrace for a specific thread
        # {0:1} {1:1} -g a.out -H

    - Print printPeace call contexts for a specific thread
        # {0:1} {1:1} -g 1234 -c printPeace

    - Print all call contexts except for printPeace for a specific thread
        # {0:1} {1:1} -g 1234 -c ^printPeace

    - Print a specific call contexts from a specific binary
        # {0:1} {1:1} ~/test/mutex -c "std::_Vector_base<unsigned long\, std::allocator<unsigned long> >::~_Vector_base()"

    - Print printPeace call contexts only for 2 seconds
        # {0:1} {1:1} -g a.out -c printPeace -R 2s

    - Print printPeace call contexts and save them to ./guider.out
        # {0:1} {1:1} -g a.out -c printPeace -o . -a

    - Print specific call contexts including specific word
        # {0:1} {1:1} -g 1234 -c "*printPeace"
        # {0:1} {1:1} -g 1234 -c "printPeace*"
        # {0:1} {1:1} -g 1234 -c "*printPeace*"

    - Print all call contexts related to specific files
        # {0:1} {1:1} -g a.out -c -T /usr/bin/yes

    - Print all call contexts except for specific files
        # {0:1} {1:1} -g a.out -c -T ^/usr/bin/yes

    - Print specific call contexts including specific word and stop tracing
        # {0:1} {1:1} -g a.out -c "*printPeace|stop"
        # {0:1} {1:1} -g a.out -c "printPeace*|stop"
        # {0:1} {1:1} -g a.out -c "*printPeace*|stop"

    - Print all call contexts with 0.1 second sleep
        # {0:1} {1:1} -g a.out -c "*|sleep:0.1"

    - Print write call contexts with 0.1 second sleep only one time
        # {0:1} {1:1} -g a.out -c "write|oneshot:sleep:0.1"

    - Print write call contexts and kill the target thread
        # {0:1} {1:1} -g a.out -c "write|kill"

    - Print write call contexts and modify memory
        # {0:1} {1:1} -g a.out -c "write|wrmem:0x1234:aaaa:4"

    - Print write call contexts and modify memory pointed by 1st argument
        # {0:1} {1:1} -g a.out -c "write|wrmem:0:aaaa:4"

    - Print printf call contexts with 10-length string that 1st argument point to
        # {0:1} {1:1} -g a.out -c "printf|rdmem:0:10"

    - Print printf call contexts with 10-length string from the specific address
        # {0:1} {1:1} -g a.out -c "printf|rdmem:0x1234:10"

    - Print write call contexts and return a specific value immediately
        # {0:1} {1:1} -g a.out -c "write|ret:3"

    - Print write call contexts and dump stack to a file
        # {0:1} {1:1} -g a.out -c "write|dump:stack:stack.out"

    - Print write call contexts and dump specific memory range to a file
        # {0:1} {1:1} -g a.out -c "write|dump:0x1234-0x4567:dump.out"

    - Print write call contexts and return value
        # {0:1} {1:1} -g a.out -c "write|getret"

    - Print write call contexts and stop tracing and save return value to specific variable
        # {0:1} {1:1} -g a.out -c "write|getret:stop$print"

    - Print write call contexts and start tracing all calls
        # {0:1} {1:1} -g a.out -c "write|getret:start, *"

    - Print write call contexts with colorful elapsed time when the elapsed time exceed 0.1 second
        # {0:1} {1:1} -g a.out -c "write|getret" -q ELAPSED:0.1

    - Print write call contexts and call again repeatedly
        # {0:1} {1:1} -g a.out -c "write|repeat"
        # {0:1} {1:1} -g a.out -c "write|repeat:5"

    - Print write call contexts and change return value
        # {0:1} {1:1} -g a.out -c "write|setret:3"
        # {0:1} {1:1} -g a.out -c "write|setret:3:print"

    - Print write call contexts and modify 1st and 2nd arguments
        # {0:1} {1:1} -g a.out -c "write|setarg:0#2:1#5"

    - Print write call contexts and details
        # {0:1} {1:1} -g a.out -c "write|print"

    - Print write call contexts and save specific values to specific variables
        # {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"

    - Print write call contexts if call meets specific conditions
        # {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"

    - Print contexts for write call and return if only the elapsed time exceed 0.0005 second
        # {0:1} {1:1} -g a.out -c "write|filter:RET:BT:0.0005"
        # {0:1} {1:1} -g a.out -c "write|filter:RET:BT:0.0005" -H -a

    - Print write call contexts with specific check results
        # {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:@RET1:EQ:@RET2:EVENT_CONT"

    - Print write call contexts and 1st and 2nd arguments
        # {0:1} {1:1} -g a.out -c "write|getarg:0:1"

    - Print write call contexts and 1st and 2nd arguments and save its return value to specific variable
        # {0:1} {1:1} -g a.out -c "write|getarg:0:1|save:writeRet"

    - Print a write call contexsts and start tracing all functions
        # {0:1} {1:1} -g a.out -c "write|start, *"

    - Print write call context and terminate target thread
        # {0:1} {1:1} -g a.out -c "write|exit"

    - Print specific call contexts and all call contexts within a specific range
        # {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"

    - Print write call contexts and call specific functions
        # {0:1} {1:1} -g a.out -c "write|usercall:sleep#3"
        # {0:1} {1:1} -g a.out -c "write|usercall:printf#PEACE"
        # {0:1} {1:1} -g a.out -c "write|usercall:printf#12345"
        # {0:1} {1:1} -g a.out -c "write|usercall:getenv#PATH, usercall:write#1#@getenv#1024"

    - Print write call contexts and call specific syscalls
        # {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"

    - Print write call contexts and load specific library
        # {0:1} {1:1} -g a.out -c "write|load:/usr/lib/preload.so"

    - Print write call contexts and create a thread
        # {0:1} {1:1} -g a.out -c "write|thread"

    - Print write call contexts and execute python code
        # {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

    - Print malloc call contexts and accumulated stats for specific argument
        # {0:1} {1:1} -g a.out -c "malloc|acc:CHUNK:0:arg"

    - Print malloc call contexts and distribution stats for specific argument
        # {0:1} {1:1} -g a.out -c "malloc|dist:CHUNK:0:arg"

    - Print write call contexts and jump to specific function with specific arguments
        # {0:1} {1:1} -g a.out -c "write|jump:sleep#5"

    - Print all call contexts and 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)

                reportStr = '''
    - report all analysis results for a specific thread having TID 1234 to ./guider.out
        # {0:1} guider.dat -o . -g 1234 -a

    - report all analysis results including interval information for all threads to ./guider.out
        # {0:1} guider.dat -o . -a -i

    - report analysis results including preemption info for specific threads to ./guider.out
        # {0:1} guider.dat -o . -p 1234, 4567

    - report all analysis results for specific threads including other threads involved in the same process to ./guider.out
        # {0:1} guider.dat -o . -P -g 1234, 4567 -a

    - report all function analysis result with maximum 3-depth for a specific thread having TID 1234 to ./guider.out
        # {0:1} guider.dat -o . -g 1234 -H 3
                '''.format(cmd)

                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!"
                    '''.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
    -o  <DIR|FILE>              set output path
    -X  <REQ@IP:PORT>           set request address

Examples:
    - Print logs in real-time
        # {0:1} {1:1}

    - Print logs to the sepcific file
        # {0:1} {1:1} -o log.out
                    '''.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 ]
    -d  <CHARACTER>             disable options
          [ a:all | c:cpu | C:compress | e:encode
            g:generalInfo | l:latency | L:log | u:user ]
    -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                          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}>
    -v                          verbose
                    '''

                    helpStr += '''
Examples:
    - record default function events for all threads to ./guider.dat
        # {0:1} {1:1} -s .

    - record default function events for all threads to ./guider.dat for only 3 minutes
        # {0:1} {1:1} -s . -R 3m

    - record default function events for all threads to ./guider.dat every 3 minutes continuously
        # {0:1} {1:1} -s . -R 3m:1:

    - record default function events for specific threads having TID bigger than 1024 to ./guider.dat in the background
        # {0:1} {1:1} -s . -g 1024\< -u

    - record specific function events including memory, block, heap for all threads to ./guider.dat
        # {0:1} {1:1} -s . -e m, b, h

    - record specific function events including all syscalls for all threads to ./guider.dat
        # {0:1} {1:1} -s . -t

    - record specific function events including softirq_entry event for all threads to ./guider.dat
        # {0:1} {1:1} -s . -c softirq_entry:vec==1

    - record specific function events 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

    - record specific function events including blocking for all threads to ./guider.dat
        # {0:1} {1:1} -s . -d c -K block:schedule

    - record default function events for all threads to ./guider.dat and execute user commands
        # {0:1} {1:1} -s . -w BEFORE:/tmp/started:1, BEFORE:ls

    - record all kernel function calls for all threads to ./guider.dat
        # {0:1} {1:1} -s . -e g
                    '''.format(cmd, mode)

                    helpStr += reportStr

                # file record #
                elif SysMgr.checkMode('filerec'):
                    helpStr = '''
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Record on-memory file status
                        '''.format(cmd, mode)

                    helpStr += '''
Options:
    -e  <CHARACTER>             enable options
          [ p:pipe | e:encode ]
    -d  <CHARACTER>             disable options
          [ e:encode | g:genearlInfo ]
    -s  <DIR|FILE>              save trace data
    -u                          run in the background
    -W                          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
    -g  <COMM|TID{:FILE}>       set task filter
    -Q                          print all rows in a stream
    -q  <NAME{:VALUE}>          set environment variables
    -E  <DIR>                   set cache dir path
    -v                          verbose
                    '''

                    helpStr += '''
Examples:
    - report all analysis results of files mapped to all processes to ./guider.out
        # {0:1} {1:1} -o . -a

    - report all analysis results of files mapped to specific processes
        # {0:1} {1:1} -g a.out

    - report analysis result on each intervals of files mapped to all processes to ./guider.out
        # {0:1} {1:1} -o . -i
                    '''.format(cmd, mode)

                # syscall record #
                elif SysMgr.checkMode('sysrec'):
                    helpStr = '''
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Record syscall events
                        '''.format(cmd, mode)

                    helpStr += '''
Options:
    -e  <CHARACTER>             enable options
          [ p:pipe | e:encode ]
    -d  <CHARACTER>             disable options
          [ e:encode | g:genearlInfo ]
    -s  <DIR|FILE>              save trace data
    -u                          run in the background
    -b  <SIZE:KB>               set buffer size
    -t  <SYSCALL>               trace syscall
    -W                          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
    -g  <COMM|TID{:FILE}>       set task filter
    -E  <DIR>                   set cache dir path
    -v                          verbose
                    '''

                    helpStr += '''
Examples:
    - record all syscall events of all threads to ./guider.dat
        # {0:1} {1:1} -s .

    - report analysis result of specific syscalls to ./guider.out
        # {0:1} guider.dat -o . -t read, write
                    '''.format(cmd, mode)

                # report #
                elif SysMgr.checkMode('report'):
                    helpStr = '''
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Report analysis result based on guider.dat
                        '''.format(cmd, mode)

                    helpStr += '''
Options:
    -e  <CHARACTER>             enable options
          [ p:pipe | e:encode ]
    -d  <CHARACTER>             disable options
          [ e:encode | g:genearlInfo ]
    -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:
    - report analysis result based on guider.dat to ./guider.out
        # {0:1} {1:1}

    - report all analysis result based on guider.dat for a specific thread to ./guider.out
        # {0:1} {1:1} -g 1234 -a

    - report analysis result based on guider.dat to ./guider.out with high time resolution
        # {0:1} {1:1} -q PRECISE
                    '''.format(cmd, mode)

                    helpStr += reportStr

                # 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:genearlInfo ]
    -s  <DIR|FILE>              save trace data
    -u                          run in the background
    -W                          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
    -E  <DIR>                   set cache dir path
    -v                          verbose
                    '''

                    helpStr += '''
Examples:
    - report analysis results of system to ./guider.out
        # {0:1} {1:1} -o .
                    '''.format(cmd, mode)

                # thread record #
                elif SysMgr.checkMode('rec'):
                    helpStr = '''
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Record thread events
                        '''.format(cmd, mode)

                    helpStr += '''
Options:
  [collect]
    -e  <CHARACTER>             enable options
          [ b:block | B:binder | c:cgroup | d:disk
            e:encode | g:graph | i:irq | I:i2c
            L:lock | m:mem | n:net | p:pipe
            r:reset | P:power | w:workqueue ]
    -d  <CHARACTER>             disable options
          [ a:all | c:cpu | C:compress | e:encode
            g:generalInfo ]
    -s  <DIR|FILE>              save trace data
    -f                          force execution
    -u                          run in the background
    -W                          wait for input
    -b  <SIZE:KB>               set buffer size
    -D                          trace thread 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

  [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}>
    -v                          verbose
                    '''

                    helpStr += '''
Examples:
    - record default events of all threads to ./guider.dat
        # {0:1} {1:1} -s .

    - record default events of specific threads that having TID bigger than 1234 to ./guider.dat
        # {0:1} {1:1} -s . -g ">1234"

    - record default events of all threads and their commands
        # {0:1} {1:1} -s . -B

    - record default events of all threads to ./guider.dat for only 3 seconds
        # {0:1} {1:1} -s . -R 3

    - record default events of all threads to ./guider.dat every 3 seconds continuously
        # {0:1} {1:1} -s . -R 3:1:

    - 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

    - record default events including specific syscalls of all threads to ./guider.dat
        # {0:1} {1:1} -s . -t sys_read, write

    - record default events including lock of all threads to ./guider.dat
        # {0:1} {1:1} -s . -e L

    - record default events 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

    - record default events 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

    - record default events 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

    - record default events 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

    - record default events 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

    - record default events of all threads to ./guider.dat and execute user commands
        # {0:1} {1:1} -s . -w BEFORE:/tmp/started:1, BEFORE:ls

    - report analysis result for all threads to ./guider.out
        # {0:1} guider.dat -o .

    - convert event data compressed to original one
        # {0:1} guider.dat -s .
                    '''.format(cmd, mode)

                    helpStr += reportStr

                # 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 open files including null of all processes
        # {0:1} {1:1} -g :null

    - Monitor open files of specific processes including system
        # {0:1} {1:1} -g system

    - Monitor all processes sorted by the number of file descriptors
        # {0:1} {1:1} -S f

    - Report analysis result of open files to ./guider.out
        # {0:1} {1:1} -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

                # 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:
    - Monitor syscalls
        # {0:1} {1:1} -g a.out

    - Monitor syscalls with backtrace for a specific thread
        # {0:1} {1:1} -g a.out -H

    - Monitor syscalls for child tasks created by a specific thread
        # {0:1} {1:1} -g a.out -W

    - Monitor syscalls for a specific thread 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

    - Monitor syscalls with breakpoint for read including register info for a specific thread
        # {0:1} {1:1} -g 1234 -c read -a

    See the top COMMAND help for more examples.
                    '''.format(cmd, mode)

                    helpStr += topSubStr + topCommonStr + examStr

                # python top #
                elif SysMgr.checkMode('pytop'):
                    helpStr = '''
Usage:
    # {0:1} {1:1} -g <TARGET> [OPTIONS] [--help]

Description:
    Monitor python methods consuming CPU
                        '''.format(cmd, mode)

                    examStr = '''
Examples:
    - Monitor python methods for a specific thread
        # {0:1} {1:1} -g a.out

    - Monitor python methods for child tasks created by a specific thread
        # {0:1} {1:1} -g a.out -W

    - Monitor python methods with backtrace for a specific thread
        # {0:1} {1:1} -g a.out -H

    - Monitor python methods for a specific thread 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 python methods for a specific thread
        # {0:1} {1:1} -g a.out -e c

    - Monitor python methods with breakpoint for peace including register info for a specific thread
        # {0:1} {1:1} -g 1234 -c peace -a

    See the top COMMAND help for more examples.
                    '''.format(cmd, mode)

                    helpStr += topSubStr + topCommonStr + examStr

                # usercall top #
                elif SysMgr.checkMode('utop'):
                    helpStr = '''
Usage:
    # {0:1} {1:1} -g <TARGET> [OPTIONS] [--help]

Description:
    Monitor function calls consuming CPU
                        '''.format(cmd, mode)

                    examStr = '''
Examples:
    - Monitor function calls for a specific thread
        # {0:1} {1:1} -g a.out

    - Monitor function calls from a specific binary
        # {0:1} {1:1} a.out
        # {0:1} {1:1} -I a.out

    - Monitor function calls and standard output from a specific binary
        # {0:1} {1:1} a.out -q NOMUTE

    - Monitor function calls for specific threads from a specific binary
        # {0:1} {1:1} a.out -g a.out
        # {0:1} {1:1} -I a.out -g a.out

    - Monitor function calls except for wait status for a specific thread
        # {0:1} {1:1} a.out -g a.out -q EXCEPTWAIT

    - Monitor function calls except for register info for a specific thread
        # {0:1} {1:1} a.out -g a.out -q NOCONTEXT

    - Monitor function calls except for no symbol functions for a specific thread
        # {0:1} {1:1} a.out -g a.out -q EXCEPTNOSYM

    - Monitor function calls for a specific thread after loading all symbols in stop status
        # {0:1} {1:1} a.out -g a.out -q STOPTARGET

    - Monitor function calls for 4th new threads in each new processes from a specific binary
        # {0:1} {1:1} a.out -g a.out -q TARGETNUM:4
        # {0:1} {1:1} -I a.out -g a.out -q TARGETNUM:4

    - Monitor function calls for a specific binary execution with enviornment 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

    - Monitor function calls for a specific thread with DWARF info
        # {0:1} {1:1} -g a.out -eD

    - Monitor function calls for child tasks created by a specific thread
        # {0:1} {1:1} -g a.out -W

    - Monitor function calls with backtrace for a specific thread
        # {0:1} {1:1} -g a.out -H

    - Monitor function calls for a specific thread 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 function calls for a specific thread
        # {0:1} {1:1} -g a.out -e c

    - Monitor function calls with breakpoint for peace including register info for a specific thread
        # {0:1} {1:1} -g 1234 -c peace -a

    See the top COMMAND help for more examples.
                    '''.format(cmd, mode)

                    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 by threshold
                        '''.format(cmd, mode)

                    examStr = '''
Examples:
    - Monitor resources by condition
        # {0:1} {1:1}
        # {0:1} {1:1} -C /tmp/guider.conf

    See the top COMMAND help for more examples.
                    '''.format(cmd, mode)

                    helpStr += 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 by 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 of specific processes
        # {0:1} {1:1} -g chrome

    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 processes after clearing page reference bits
                        '''.format(cmd, mode)

                    examStr = '''
Examples:
    - Monitor WSS(Working Set Size) change of specific processes
        # {0:1} {1:1} -g chrome

    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:
    - Report system status in JSON format to /tmp/guider.report
        # {0:1} {1:1}

    - Report system status in JSON format to console standard output
        # {0:1} {1:1} -Q

    - Report system status in JSON format to ./guider.report in the background every second
        # {0:1} {1:1} -j . -u

    - Stop reporting processes in the background
        # {0:1} stop

    See the top COMMAND help for more examples.
                    '''.format(cmd, mode)

                    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 storage status
                        '''.format(cmd, mode)

                    examStr = '''
Examples:
    - Monitor status of all storages
        # {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:
    - Monitor DLT logs
        # {0:1} {1:1}

    - Monitor DLT logs 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

    - Monitor DLT logs including specific string
        # {0:1} {1:1} -g test

    - Monitor DLT logs from specific address for dlt-daemon
        # {0:1} {1:1} -X 127.0.0.1:12345

    See the top COMMAND help for more examples.
                    '''.format(cmd, mode)

                    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:
    - Monitor D-Bus messages
        # {0:1} {1:1}

    - Monitor D-Bus messages including DBus interfaces
        # {0:1} {1:1} -g dbus-daemon

    - Monitor D-Bus messages for dbus-client process
        # {0:1} {1:1} -g dbus-client

    - Monitor D-Bus messages including specific word
        # {0:1} {1:1} -c test

    - Monitor D-Bus messages except for specific messages
        # {0:1} {1:1} -G sendData

    - Monitor D-Bus messages 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)

                    helpStr += topSubStr + topCommonStr + examStr

                # network top #
                elif SysMgr.checkMode('ntop'):
                    helpStr = '''
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Monitor network status
                        '''.format(cmd, mode)

                    examStr = '''
Examples:
    - Monitor 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 process status
                        '''.format(cmd, mode)

                    helpStr += topSubStr + topCommonStr + topExamStr

                # 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
    -o  <DIR|FILE>              set output path
    -m  <ROWS:COLS:SYSTEM>      set terminal size
    -v                          verbose
                    '''

                    helpStr += '''
Examples:
    - Print the sequences of printable characters in files
        # {0:1} {1:1} -I a.out
                    '''.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 including 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:
    - Dump target memory to the sepcific file
        # {0:1} {1:1} -g a.out -I 0x1234-0x4567 -o dump.out

    - Dump target memory mapped to a specific file to the sepcific file
        # {0:1} {1:1} -g a.out -I a.out -o dump.out

    - Dump target stack to the sepcific file
        # {0:1} {1:1} -g a.out -I stack -o dump.out

    - Dump target heap to the sepcific file
        # {0:1} {1:1} -g a.out -I heap -o dump.out
                    '''.format(cmd, mode)

                # 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:generalInfo | O:color ]
    -u                          run in the background
    -a                          show all stats including registers
    -g  <COMM|TID{:FILE}>       set task filter
    -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
    -v                          verbose
                    '''

                    helpStr += '''
Examples:
    - Trace all read syscalls for a specific thread
        # {0:1} {1:1} -g a.out -t read

    - Trace all read syscalls for child tasks created by a specific thread
        # {0:1} {1:1} -g 1234 -t read -W

    - Trace all write syscalls with specific command
        # {0:1} {1:1} -I "ls -al" -t write

    - Trace all write syscalls with specific command and print standard output
        # {0:1} {1:1} -I "ls -al" -t write -q NOMUTE

    - Trace all write syscalls with colorful elapsed time when the elapsed time exceed 0.1 second
        # {0:1} {1:1} -g a.out -c write -q ELAPSED:0.1

    - Trace all read syscalls for a specific thread and save summary tables, call history to ./guider.out
        # {0:1} {1:1} -g a.out -t read -o . -a

    - Trace all syscalls with breakpoint for read including register info for a specific thread
        # {0:1} {1:1} -g a.out -c read -a

    - Trace all syscalls for a specific thread only for 1 minute
        # {0:1} {1:1} -g a.out -R 1m

    - Trace all syscalls and pause when catching open syscall
        # {0:1} {1:1} -I "ls -al" -c open

    - Trace all syscalls and sleep for 1.5 second when catching open syscall
        # {0:1} {1:1} -I "ls -al" -c "open|sleep:1.5"

    - Trace all syscalls and sleep for 1.5 second whenever catching syscall
        # {0:1} {1:1} -I "ls -al" -c "*|sleep:1.5"

    - Trace all syscalls and print memory that 2nd argument point to
        # {0:1} {1:1} -I "ls -al" -c "write|rdmem:1"
                    '''.format(cmd, mode)

                # 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:generalInfo ]
    -u                          run in the background
    -a                          show all stats including 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:
    - Trace usercalls for a specific thread in 100us cycles
        # {0:1} {1:1} -g a.out

    - Trace usercalls for child tasks created by a specific thread
        # {0:1} {1:1} -g a.out -W

    - Trace usercalls from a specific binary
        # {0:1} {1:1} "ls -al"
        # {0:1} {1:1} -I "ls -al"

    - Trace usercalls for specific threads from a specific binary
        # {0:1} {1:1} "ls -al" -g a.out
        # {0:1} {1:1} -I "ls -al" -g a.out

    - Trace usercalls for a specific thread in 10ms cycles
        # {0:1} {1:1} -g a.out -i 10000

    - Trace usercalls for a specific thread and print standard output
        # {0:1} {1:1} -g a.out -i 10000 -q NOMUTE

    - Trace usercalls with 1/10 instructions for a specific thread
        # {0:1} {1:1} -g a.out -H 10

    - Trace usercalls for a specific thread and save summary tables, call history to ./guider.out
        # {0:1} {1:1} -g a.out -o . -a

    - Trace usercalls with breakpoint for peace including register info for a specific thread
        # {0:1} {1:1} -g a.out -c peace -a

    - Trace usercalls for a specific thread only for 2 seconds
        # {0:1} {1:1} -g a.out -R 2s

    - Trace usercalls 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)

                # btrace #
                elif SysMgr.checkMode('btrace'):
                    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 | D:DWARF | e:encode | E:exec | g:generalInfo ]
    -u                          run in the background
    -a                          show all stats including 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
    -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 including 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 context repeatedly 5 times
        # {0:1} {1:1} -g a.out -c print -i 5
                    '''

                    helpStr += brkExamStr + remoteExamStr

                # hook #
                elif SysMgr.checkMode('hook'):
                    helpStr = '''
Usage:
    # {0:1} {1:1} -g <TARGET> -c <COMMAND> [OPTIONS] [--help]

Description:
    Replace specific functions with a custom function

Options:
    -u                          run in the background
    -g  <COMM|TID>              set task filter
    -c  <TARGET#BIN#HOOK>       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 standard malloc function calls with customized malloc function calls in libhook.so for a.out process
        # {0:1} {1:1} -g a.out -c malloc#./libhook.so#malloc
                    '''.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

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

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:generalInfo ]
    -u                          run in the background
    -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:
    - Trace all signals for a specific thread
        # {0:1} {1:1} -g a.out

    - Trace all signals for a specific command
        # {0:1} {1:1} -I "ls"

    - Trace the SIGINT signal for a specific thread
        # {0:1} {1:1} -g 1234 -c SIGINT

    - Trace the SIGINT signal for a specific thread and print standard output
        # {0:1} {1:1} -g 1234 -c SIGINT -q NOMUTE
                    '''.format(cmd, mode)

                # 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 for specific processes
        # {0:1} {1:1} a.out

    - Print memory map details for specific processes
        # {0:1} {1:1} a.out -a

    - Print page attributes in specific area for specific processes
        # {0:1} {1:1} a.out -I 0x0-0x4000
                    '''.format(cmd, mode)

                # 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

                # 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 chart 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]
      "segments": [
        {{
          "group": 0,
          "text": "task0",
          "time_start": 10,
          "time_end": 40
          "id": 12,         // optional for class
          "color": "red",   // optional for color
          "state": 'OFF',   // optional for event
        }},
        {{
          "group": 1,
          "text": "task1",
          "time_start": 10,
          "time_end": 40
          "id": 13,
          "color": "rgb(128,0,128)",
          "state": 'OFF',
        }}
      ]
    }}

    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:
    - Diff top report files
        # {0:1} {1:1} "tc1.out, tc2.out"

    - Diff top report files
        # {0:1} {1:1} "tc*.out"

    - Diff top report files by total usage
        # {0:1} {1:1} "tc*.out" -dA

    - Diff top report files within specific interval range in second unit
        # {0:1} {1:1} "tc*.out" -q TRIM:9:15
                    '''

                # topsum #
                elif SysMgr.checkMode('topsum'):
                    helpStr = '''
Usage:
    # {0:1} {1:1} <FILE> [OPTIONS] [--help]

Description:
    Summary a top output file
                        '''.format(cmd, mode)

                    helpStr += '''
Examples:
    - Summary a top output file
        # {0:1} {1:1} output

    - Summary a top output file into summary.out
        # {0:1} {1:1} output -o guider.out
                    '''.format(cmd, mode)

                # 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:
    -g  <TID|COMM>              set task filter
    -i  <SEC>                   set interval
    -l                          print signal list
    -W                          wait for task
    -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} -stop 1234
        # {0:1} {1:1} -stop a.out
        # {0:1} {1:1} -stop a.out*

    - Send SIGSTOP signal to specific tasks until one gets the signal
        # {0:1} {1:1} -stop 1234 -W

    - Send 9th signal SIGKILL to specific tasks
        # {0:1} {1:1} -9 1234
        # {0:1} {1:1} -kill 1234

    - Send 9th signal SIGKILL to specific tasks every 2 seconds
        # {0:1} {1:1} -9 1234 -i 2
        # {0:1} {1:1} -kill 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 1234 -R 3

    - Pause specific running threads including a same process group
        # {0:1} {1:1} -g 1234 -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
        -v                          verbose
                        '''.format(cmd, mode)

                    helpStr += '''
Examples:
    - Print ELF infomation of specific file
        # {0:1} {1:1} -I /usr/bin/yes

    - Print vDSO infomation
        # {0:1} {1:1} -I vdso
                    '''.format(cmd, mode)

                # 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 += '''
    - Print D-Bus messages with detailed information in real-time
        # {0:1} {1:1} -a

    - Print D-Bus messages including specific word in real-time
        # {0:1} {1:1} -c test

    - Print D-Bus messages with backtrace for a.out process in real-time
        # {0:1} {1:1} -g a.out -H

    - Print D-Bus messages for a specific session bus
        # DBUS_SESSION_BUS_ADDRESS=$(cat addr) {0:1} {1:1}

    - Print D-Bus messages except for specific messages
        # {0:1} {1:1} -G sendData

                    '''.format(cmd, mode)

                    # 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 += '''
    - Print all journals
        # {0:1} {1:1} -a

    - Print journals including specific words in real-time
        # {0:1} {1:1} -g test

    - Print journals with all fields in real-time
        # {0:1} {1:1} -I

    - Print journals with specific fields in real-time
        # {0:1} {1:1} -I _TIME, _COMM, _PID
                    '''.format(cmd, mode)

                    # printdlt #
                    if SysMgr.checkMode('printdlt'):
                        helpStr += '''
    - Print DLT messages from specific files
        # {0:1} {1:1} "./*.dlt"
        # {0:1} {1:1} -I "./*.dlt"

    - Print DLT messages including specific words
        # {0:1} {1:1} -g test

    - Change default log level to be printed
        # {0:1} {1:1} -c INFO

    - Print DLT messages using libdlt.so from specific path
        # {0:1} {1:1} -q LIBDLT:/home/iipeace/test/libdlt.so

    - Print DLT messages sorted by line from specific files
        # {0:1} {1:1} "./*.dlt" -S
        # {0:1} {1:1} -I "./*.dlt" -S

    - Print DLT messages from specific address for dlt-daemon
        # {0:1} {1:1} -X 127.0.0.1:12345
                    '''.format(cmd, mode)

                # 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
    -v                          verbose
                        '''.format(cmd, mode)

                    helpStr += '''
Examples:
    - Print signal status info for a specific process
        # {0:1} {1:1} -g a.out
                    '''.format(cmd, mode)

                # printsub #
                elif SysMgr.checkMode('printsub'):
                    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 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
    -v                          verbose
                        '''.format(cmd, mode)

                    helpStr += '''
Examples:
    - Print symbol infomation of specific addresses in a file
        # {0:1} {1:1} -I /usr/bin/yes -g ab1cf

    - Print symbol infomation of specific addresses in a process memory map
        # {0:1} {1:1} -I yes -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

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
        # {0:1} {1:1} a.out, yes

    - Make ELF caches for /usr/bin/yes
        # {0:1} {1:1} /usr/bin/yes
                    '''.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
    -v                          verbose
                        '''.format(cmd, mode)

                    helpStr += '''
Examples:
    - Print infomation of specific symbols in a file
        # {0:1} {1:1} -I /usr/bin/yes -g testFunc

    - Print infomation of all symbols in a file
        # {0:1} {1:1} -I /usr/bin/yes -g

    - Print infomation of specific symbols including specific word in 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*"

    - Print infomation of specific symbols including specific word in a file
        # {0:1} {1:1} -I ~/test/mutex -g "std::_Vector_base<unsigned long\, std::allocator<unsigned long> >::~_Vector_base()"

    - Print infomation of specific symbols in a process memory map
        # {0:1} {1:1} -I yes -g testFunc
                    '''.format(cmd, mode)

                # printdbusinfo #
                elif SysMgr.checkMode('printdbusinfo'):
                    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}
                    '''.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:
    - Print system cgroup tree
        # {0:1} {1:1}

    - Print system cgroup tree for specific subsystem
        # {0:1} {1:1} cpu
        # {0:1} {1:1} blkio

    - Print system cgroup tree with processes
        # {0:1} {1:1} -a

    - Print system cgroup tree with processes having specific name
        # {0:1} {1:1} -a -g kworker

    - Print system cgroup tree with depth 3
        # {0:1} {1:1} -H 3
                    '''.format(cmd, mode)

                # 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
    -q  <NAME{{:VALUE}}>          set environment variables
    -u                          run in the background
                        '''.format(cmd, mode)

                    helpStr += '''
Examples:
    - Execute a command
        # {0:1} {1:1} -I "ls -lha"

    - Execute a command 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 for a directory
        # {0:1} {1:1} -I "ls -lha FILE" -c FILE:/data

    - Execute commands with enviornment 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
                    '''.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
    -H  <LEVEL>                 set function depth level
                        '''.format(cmd, mode)

                    helpStr += '''
Examples:
    - Print directory structure from current working directory
        # {0:1} {1:1}

    - Print directory structure from / dir
        # {0:1} {1:1} /
        # {0:1} {1:1} -I /

    - Print directory structure in 2-depth from / dir
        # {0:1} {1:1} -I / -H 2

    - Print directory structure with files from / dir
        # {0:1} {1:1} -I / -a

    - Print specific directories and files from / dir
        # {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"

    - 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)

                # leaktracer #
                elif SysMgr.checkMode('leaktrace'):
                    helpStr = '''
Usage:
    # {0:1} {1:1} -g <TARGET> [OPTIONS] [--help]

Description:
    Show functions caused memory leakage with leaktracer output

    Get libleaktracer.so for various CPU architectures from https://github.com/iipeace/portable/tree/master/leaktracer

    Run the target process with below specific environment variables if you can't inject the hook binary
    $ LD_PRELOAD=./libleaktracer.so \\
        LEAKTRACER_AUTO_REPORTFILENAME=leaks.out \\
        LEAKTRACER_ONSIG_REPORT=36 EXEC
    $ LD_PRELOAD=./libleaktracer.so \\
        LEAKTRACER_ONSIG_REPORTFILENAME=leaks.out \\
        LEAKTRACER_ONSIG_STARTALLTHREAD=35 \\
        LEAKTRACER_ONSIG_REPORT=36 EXEC

    If the target process is on secure-execution mode,
    libleaktracer.so should be in standard search directoriesspecified in /etc/ld.so.conf,
    And all slashes in it's preload path will be ignored
    Otherwise add the library path to /etc/ld.so.preload

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
    -C  <PATH>                  set config path
    -v                          verbose
                        '''.format(cmd, mode)

                    helpStr += '''
Examples:
    - Create an output file for memory leakage hints of a specific process when user input Ctrl + c key after setting environment variables
        # {0:1} {1:1} -g a.out

    - Create an output file for memory leakage hints of a specific process when user input Ctrl + c key with binary injection
        # {0:1} {1:1} -g a.out -T /home/root/libleaktracer.so

    - Create an output file for memory leakage hints of a specific process when user input Ctrl + c key with binary injection and a temporary writable path
        # {0:1} {1:1} -g a.out -I /var/log/guider -T /home/root/libleaktracer.so

    - Create an output file for memory leakage hints of a specific process after sending signal 36 to stop profiling
        # {0:1} {1:1} -g a.out -k 36

    - Create an output file for memory leakage hints of a specific process when it's RSS reached the specific size
        # {0:1} {1:1} -g a.out -c 20m
        # {0:1} {1:1} -g a.out -c 15m,20m

    - Print funtions caused memory leakage of a specific process
        # {0:1} {1:1} -I ./leaks.out -g a.out
                    '''.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:
    - Print systemd services
        # {0:1} {1:1}

    - Print systemd services about only specific files
        # {0:1} {1:1} -g test

    - Print systemd services including specific attributes
        # {0:1} {1:1} -c Restart

    - Print systemd services including specific value of attributes
        # {0:1} {1:1} -c :pid

    - Print systemd services in specific directories
        # {0:1} {1:1} -I /home/iipeace/services
                    '''.format(cmd, mode)

                # 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 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
                    '''.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
                    '''.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}

    - Request GET / URL to specific server
        # {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"

    - Request GET / URL to specific server and print contents for the request
        # {0:1} {1:1} http://127.0.0.1:5000 -q PRINTREQ

    - Request GET / URL to specific server and print only summary for requests
        # {0:1} {1:1} http://127.0.0.1:5000 -q MUTE

    - Request POST / URL to specific server
        # {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

    - Request POST / URL to specific server after base64 encoding specific file data from specific path 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

    - Request POST / URL to specific server 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

    - Request POST / URL to specific server with data from data.json file
        # {0:1} {1:1} POST#JSONFILE:data.json#http://127.0.0.1:5000

    - Request POST / URL to specific server with data from data file
        # {0:1} {1:1} POST#DATAFILE:data#http://127.0.0.1:5000

    - Request GET / URL to specific server infinitely
        # {0:1} {1:1} GET#http://127.0.0.1:5000 -R

    - Request GET / URL to specific server 10 times with 500ms delay
        # {0:1} {1:1} GET#http://127.0.0.1:5000 -R 500:10

    - Request GET / URL to specific server 10 times by 10 processes
        # {0:1} {1:1} GET#http://127.0.0.1:5000 -R 10 -T 10

    - Request GET / URL to specific server with 5 second timeout
        # {0:1} {1:1} GET#TIMEOUT:5#http://127.0.0.1:5000

    - Request GET / URL to specific server with no verification for SSL
        # {0:1} {1:1} GET#VERIFY:false#https://127.0.0.1:5000

    - Request GET / URL to specific server with auth
        # {0:1} {1:1} GET#AUTH:id,passwd#https://127.0.0.1:5000

    - Request GET / URL to specific server with cookies
        # {0:1} {1:1} GET#COOKIES:sessionKey:sessionValue#https://127.0.0.1:5000

    - Request GET / URL to specific server with headers
        # {0:1} {1:1} GET#HEADERS:Content-Type:application/json;charset=utf-8#https://127.0.0.1:5000
                    '''.format(cmd, mode)

                # 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
    -v                          verbose
                        '''.format(cmd, mode)

                    helpStr += '''
Examples:
    - Limit CPU usage of specific threads for 3 seconds
        # {0:1} {1:1} -g 1234:10, yes:20 -R 3
                    '''.format(cmd, mode)

                # 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:
    - Set the clock speed to 10000000HZ and the governor to userspace for CPU1
        # {0:1} {1:1} 1:10000000:userspace

    - Set the clock speed to 10000000HZ and the governor to userspace for All CPUs
        # {0:1} {1:1} :10000000:userspace

    - Set the clock speed to 10000000HZ for CPU0
        # {0:1} {1:1} 0:10000000

    - Set the governor to performance for CPU2
        # {0:1} {1:1} 2:0:performance

    - Set the governor to performance for CPU2
        # {0:1} {1:1} 2:0:performance
                    '''.format(cmd, mode)

                # 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)

                # setsched #
                elif SysMgr.checkMode('setsched'):
                    helpStr = '''
Usage:
    # {0:1} {1:1} -g <POLICY:PRIORITY|TIME:TID|COMM> [OPTIONS] [--help]

Description:
    Set CPU scheduler policy and priority for threads / processes

Policy:
    c: CFS [default]
    f: FIFO(RT)
    r: RR(RT)
    B: BATCH
    I: IDLE
    d: DEADLINE

Options:
    -g <POLICY:PRIORITY|TIME:TID|COMM> set value
    -P                                 group threads in a same process
    -i  <SEC>                          set interval
    -v                                 verbose
                        '''.format(cmd, mode)

                    helpStr += '''
Examples:
    - Set CPU scheduler policy(CFS), priority(-20) for a specific thread
        # {0:1} {1:1} "-20:a.out"
        # {0:1} {1:1} "c:-20:1234"

    - Set CPU scheduler policy(CFS), priority(-20) for a specific thread every 2 seconds
        # {0:1} {1:1} "-20:a.out" -i 2

    - Set CPU scheduler policy(CFS), priority(-20) for all threads in a specific process
        # {0:1} {1:1} "-20:a.out -P"

    - Set CPU scheduler policy(FIFO), priority(90) for a specific thread
        # {0:1} {1:1} "f:90:a.out"

    - Set CPU scheduler policy(DEADLINE), runtime(1ms), deadline(10ms), period(10ms) for a specific thread
        # {0:1} {1:1} "d:1000000/10000000/10000000:a.out"
                    '''.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
                    '''.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
    -v                          verbose
                        '''.format(cmd, mode)

                    helpStr += '''
Examples:
    - Set CPU affinity of a specific thread to use only CPU 1 and CPU 2
        # {0:1} {1:1} a.out:3
        # {0:1} {1:1} -g a.out:3

    - Set CPU affinity of a specific thread to use only CPU 1 every 2 seconds
        # {0:1} {1:1} a.out:1 -i 2
                    '''.format(cmd, mode)

                # 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:
    - Send ICMP ECHO_REQUEST to network hosts
        # {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"

    - Send ICMP ECHO_REQUEST to network hosts in a specific file
        # {0:1} {1:1} -I ip.txt

    - Send ICMP ECHO_REQUEST to network hosts infinitely
        # {0:1} {1:1} www.google.com -R

    - Send ICMP ECHO_REQUEST to network hosts with 3 second interval infinitely
        # {0:1} {1:1} www.google.com -R -i 3

    - Send ICMP ECHO_REQUEST to network hosts 3 times
        # {0:1} {1:1} www.google.com -R 3

    - Send ICMP ECHO_REQUEST to network hosts with 2.5 second timeout
        # {0:1} {1:1} www.google.com -T 2.5
                    '''.format(cmd, mode)

                # 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

    - Create processes using 250% CPU totally
        # {0:1} {1:1} 250

    - Create threads in a process using 250% CPU totally
        # {0:1} {1:1} 250 -et

    - Create processes using 250% CPU totally with RR 1 priority
        # {0:1} {1:1} 250 -Y r:1

    - Create processes using 250% CPU totally and run them only on CPU 1
        # {0:1} {1:1} 250 -z :1

    - Create processes using 250% CPU totally and terminate them after 3 seconds
        # {0:1} {1:1} 250 -R 3
                    '''.format(cmd, mode)

                # memtest #
                elif SysMgr.checkMode('memtest'):
                    helpStr = '''
Usage:
    # {0:1} {1:1} <SIZE:INTERVAL:COUNT> [OPTIONS] [--help]

Description:
    Allocate physical memory

Options:
    -R  <TIME>                  set timer
    -v                          verbose
                        '''.format(cmd, mode)

                    helpStr += '''
Examples:
    - Allocate physical memory 1G
        # {0:1} {1:1} 1G

    - Allocate physical memory 200MB using a new process every 3 seconds
        # {0:1} {1:1} 200M:3

    - Allocate physical memory 100MB twice using 2 processes
        # {0:1} {1:1} 100M:0:2

    - Allocate physical memory 100MB twice using 2 processes and terminate them after 3 seconds
        # {0:1} {1:1} 100M:0:2 -R 3
                    '''.format(cmd, mode)

                # 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
    -R  <TIME>                  set timer
    -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 device nodes mounted
        # {0:1} {1:1} -a

    - Write dummy data to a specific file infinitely
        # {0:1} {1:1} -g write:TEST
                    '''.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)

                # list #
                elif SysMgr.checkMode('list'):
                    helpStr = '''
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Show running {2:1} processes

Options:
    -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:
    Send the event signal to all running Guider processes

Options:
    -I  <EVENT>                 set event name
    -g  <PID>                   set target
    -v                          verbose
                        '''.format(cmd, mode)

                    helpStr += '''
Examples:
    - Send scene1 event to running Guider processes
        # {0:1} {1:1} scene1
        # {0:1} {1:1} -I scene1

    - Send scene1 event to specific Guider processes
        # {0:1} {1:1} scene1 -g 1234, 1237
                    '''.format(cmd, mode)

                # 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

    - Run server with specific local address
        # {0:1} {1:1} -x 127.0.0.1:5556

    - Run server and register to agent node as a service node
        # {0:1} {1:1} -X 127.0.0.1:3456

    - Run server with no timeout
        # {0:1} {1:1} -q NOTIMEOUT

    - Run server with specific timeout
        # {0:1} {1:1} -q TIMEOUT:1.5

    - Run server with specific read chunk size for command process
        # {0:1} {1:1} -q READCHUNK:4096

    - Run server with no output for remote reqeust
        # {0:1} {1:1} -q QUIET
                    '''.format(cmd, mode)

                # client #
                elif SysMgr.checkMode('cli'):
                    helpStr = '''
Usage:
    # {0:1} {1:1} [OPTIONS] [--help]

Description:
    Execute remote command

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)

                    helpStr += '''
Examples:
    - Run client with interaction menu
        # {0:1} {1:1}

    - Download a.out from server to ./a.out
        # {0:1} {1:1} -c d:a.out@./a.out
        # {0:1} {1:1} -c download:a.out@./a.out
        # {0:1} {1:1} -c download:a.out

    - Upload ./a.out to a.out in server
        # {0:1} {1:1} -c u:./a.out@a.out
        # {0:1} {1:1} -c upload:./a.out@a.out
        # {0:1} {1:1} -c upload:./a.out

    - Ping to the server
        # {0:1} {1:1} -c "p"
        # {0:1} {1:1} -c "ping"

    - Print node list registered in server
        # {0:1} {1:1} -c "l"
        # {0:1} {1:1} -c "list"

    - Execute remote commands in parallel
        # {0:1} {1:1} -c "ls -lha", "date"
        # {0:1} {1:1} -c 192.168.0.100:5050\|"vmstat 1", 192.168.0.101:1234\|"find /"

    - Execute remote command by service nodes
        # {0:1} {1:1} -c "b:ls -lha"
        # {0:1} {1:1} -c "broadcast:ls -lha"

    - Execute a remote command with no timeout
        # {0:1} {1:1} -c "ls -lha" -q NOTIMEOUT

    - Execute a remote command with specific timeout
        # {0:1} {1:1} -c "ls -lha" -q TIMEOUT:1.5

    - Execute a remote command with no output
        # {0:1} {1:1} -q QUIET

    - Execute remote Guider commands in fixed-line-output
        # {0:1} {1:1} -c 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(0)

                # 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)

                # reset terminal #
                SysMgr.resetTTY()

            sys.exit(0)



    @staticmethod
    def getKernelVersion():
        if SysMgr.kernelVersion:
            return SysMgr.kernelVersion

        try:
            kernel = os.uname()[2]
            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:
            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'):
                SysMgr.arch = 'x64'
            elif arch.startswith('i386') or arch.startswith('i686'):
                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(
                'fail to set architecture to %s, only %s supported' % \
                (arch, support))
            sys.exit(0)

        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=[], 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 path #
        for item in path:
            if not os.path.exists(item):
                SysMgr.printWarn(
                    "fail to access to %s" % item, verb)
                return False

        # check flags type #
        if type(flags) is not list:
            SysMgr.printErr(
                "fail 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("fail 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("fail to inotify_add_watch", verb)
                return False
            wlist[wd] = item

        # read events #
        length = SysMgr.libcObj.read(fd, byref(buf), BUF_LEN)
        if length < 0:
            SysMgr.printWarn("fail 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.keys()):
            SysMgr.libcObj.inotify_rm_watch(fd, wd)
        SysMgr.libcObj.close(fd)

        return revents



    @staticmethod
    def syscall(syscall, *args):
        if not SysMgr.isLinux:
            return None

        try:
            # load libc #
            if not SysMgr.loadLibcObj():
                raise Exception('no libc')

            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 = ConfigMgr.sysList.index(nmSyscall)
            else:
                raise Exception('wrong syscall')

            try:
                nrParams = \
                    len(ConfigMgr.SYSCALL_PROTOTYPES[nmSyscall[4:]][1])
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "fail to get the number of arguments for %s" % nmSyscall)
                raise Exception('wrong syscall')

            # check arguments #
            if len(args) != nrParams:
                SysMgr.printErr((
                    "fail 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])

            return ret
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn(
                'fail to call %s syscall' % syscall, True, reason=True)



    @staticmethod
    def checkRootPerm(exit=True, verb=True, attr='error', msg=''):
        if not SysMgr.isRoot():
            if verb:
                if msg:
                    msg = ' to %s' % msg

                if attr == 'error':
                    logger = SysMgr.printErr
                else:
                    logger = SysMgr.printWarn

                logger("fail to get root permission%s" % msg)

            if exit:
                sys.exit(0)
            return False
        else:
            return True



    @staticmethod
    def isRoot():
        if SysMgr.isLinux 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(
                'fail to recognize %s as perf event type' % econfig)
            return

        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.isRoot():
                    SysMgr.printWarn(
                        'fail to get root permission to open perf event')
                    return
                else:
                    return -1
            else:
                return fd

        # load libc #
        if not SysMgr.loadLibcObj():
            SysMgr.perfEnable = False
            SysMgr.perfGroupEnable = False
            return

        # 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 = long(0)
        _IOC_TYPESHIFT = _IOC_NRSHIFT + _IOC_NRBITS
        _IOC_SIZESHIFT = _IOC_TYPESHIFT + _IOC_TYPEBITS
        _IOC_DIRSHIFT = _IOC_SIZESHIFT + _IOC_SIZEBITS
        _IOC_NONE = long(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.syscall.argtypes = \
            [c_int, POINTER(struct_perf_event_attr),
                c_int, c_int, c_int, c_ulong]
        SysMgr.libcObj.syscall.restype = c_int
        SysMgr.libcObj.ioctl.restype = c_int
        SysMgr.libcObj.ioctl.argtypes = [c_int, c_ulong, c_int]

        # 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.libcObj.syscall(
            ConfigMgr.sysList.index('sys_perf_event_open'),
            pointer(perf_attr), pid, cpu, -1, 0)

        if fd < 0:
            # check root permission #
            if not SysMgr.isRoot():
                SysMgr.printWarn(
                    'fail to get root permission to open perf event')
                return
            else:
                return -1

        # control perf event #
        SysMgr.libcObj.ioctl(fd, PERF_EVENT_IOC_RESET, 0)
        SysMgr.libcObj.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 = long(0)
        _IOC_TYPESHIFT = _IOC_NRSHIFT + _IOC_NRBITS
        _IOC_SIZESHIFT = _IOC_TYPESHIFT + _IOC_TYPEBITS
        _IOC_DIRSHIFT = _IOC_SIZESHIFT + _IOC_SIZEBITS
        _IOC_NONE = long(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 = long(0)
        cpuPath = '/sys/devices/system/cpu'
        cpuList = \
            [ coreId.strip('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].keys())

        if successCnt == 0:
            SysMgr.printWarn('fail 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.keys()):
            # make event list #
            events = list(SysMgr.perfEventChannel[coreId].keys())

            # 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.keys())

        # 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, convSize(inst))
            ipc = inst / float(cpucycle)
            perfbuf = '%sIPC: %.2f / ' % (perfbuf, ipc)
        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 = cachemiss / float(cacheref) * 100
            perfbuf = '%sCacheMiss : %s(%s%%) / ' % \
                (perfbuf, convSize(cachemiss),
                    convColor(long(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 = branchmiss / float(branch) * 100
            perfbuf = '%sBrcMiss: %s(%s%%) / ' % \
                (perfbuf, convSize(branchmiss),
                    convColor(long(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 len(perfbuf) > 0:
                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(0)
        elif not os.path.isfile(
            SysMgr.mountPath + '../kprobe_events'):
            SysMgr.printErr(
                "enable CONFIG_KPROBES & CONFIG_KPROBE_EVENTS kernel option")
            sys.exit(0)

        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(0)

            for item in effectiveCmd:
                if cmdFormat[0] == item[0]:
                    SysMgr.printErr(
                        "redundant kernel event name '%s'" % item[0])
                    sys.exit(0)

            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(0)

            # 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(0)
                    tVal = rVal[1]

                    # count the number of prefix * #
                    wCnt = long(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.writeCmd(
                        '../kprobe_events', pCmd, append=True) < 0:
                    SysMgr.printErr("wrong command '%s'" % pCmd)
                    sys.exit(0)

            # 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(0)
                    tVal = rVal[0]

                    # count the number of prefix * #
                    wCnt = long(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.writeCmd(
                    '../kprobe_events', rCmd, append=True) < 0:
                    SysMgr.printErr("wrong command '%s'" % rCmd)
                    sys.exit(0)

        # apply filter #
        if SysMgr.filterGroup:
            cmd = SysMgr.getPidFilter()
            if cmd != '':
                SysMgr.writeCmd("kprobes/filter", cmd)
            else:
                SysMgr.printErr("fail to apply '%s' to kprobe filter" % cmd)
                sys.exit(0)

        # enable kprobe events #
        if SysMgr.writeCmd("kprobes/enable", '1') < 0:
            SysMgr.printErr("fail to apply '%s' to kprobe events" % cmd)
            sys.exit(0)



    @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(0)
        elif not os.path.isfile(
            SysMgr.mountPath + '../uprobe_events'):
            SysMgr.printErr(
                "enable CONFIG_UPROBES & CONFIG_UPROBE_EVENT kernel option")
            sys.exit(0)

        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(0)

            # 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(0)

            # check binary file #
            if not os.path.isfile(cmdFormat[2]):
                SysMgr.printErr(
                    "fail to find '%s' binary" % cmdFormat[2])
                sys.exit(0)

            # 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(
                        "use '%s' as objdump path" % objdumpPath)

                    if not os.path.isfile(objdumpPath):
                        SysMgr.printErr(
                            "fail to find %s to use objdump" % objdumpPath)
                        sys.exit(0)

                    # get address of symbol in binary #
                    addr = ElfAnalyzer.getSymOffset(
                        cmdFormat[1], cmdFormat[2], objdumpPath, loadAddr=True)

                if not addr:
                    SysMgr.printErr("fail to find '%s' in %s" % \
                        (cmdFormat[1], cmdFormat[2]))
                    sys.exit(0)
            # address input #
            else:
                addr = cmdFormat[1]
                try:
                    hex(long(addr, base=16))
                except:
                    SysMgr.printErr(
                        "fail to recognize address %s" % addr)
                    sys.exit(0)

            for item in effectiveCmd:
                if cmdFormat[0] == item[0]:
                    SysMgr.printErr(
                        "redundant user event name '%s'" % item[0])
                    sys.exit(0)

            # 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.writeCmd('../uprobe_events', pCmd, append=True) < 0:
                SysMgr.printErr(
                    "wrong command '%s'" % pCmd)
                sys.exit(0)

            # apply return events #
            rCmd = 'r:%s_exit %s:%s' % (cmd[0], cmd[2], cmd[1])
            if SysMgr.writeCmd('../uprobe_events', rCmd, append=True) < 0:
                SysMgr.printErr(
                    "wrong command '%s'" % rCmd)
                sys.exit(0)

        # apply filter #
        if SysMgr.filterGroup:
            cmd = SysMgr.getPidFilter()
            if cmd != '':
                SysMgr.writeCmd("uprobes/filter", cmd)
            else:
                SysMgr.printErr("fail to apply '%s' to uprobe filter" % cmd)
                sys.exit(0)

        # enable uprobe events #
        if SysMgr.writeCmd("uprobes/enable", '1') < 0:
            SysMgr.printErr("fail to apply '%s' to uprobe events" % cmd)
            sys.exit(0)



    @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 len(sfilter) > 0 and len(pfilter) > 0:
                scmd = "(%s && %s)" % (sfilter, pfilter)
            elif len(sfilter) > 0:
                scmd = sfilter
                for item in defaultList:
                    try:
                        scmd = "%s || ( id == %s )" % \
                            (scmd, ConfigMgr.sysList.index(item))
                    except:
                        continue
            elif len(pfilter) > 0:
                scmd = "(%s)" % pfilter
            else:
                pass
        # default syscalls #
        else:
            for item in defaultList:
                try:
                    scmd = "%s || ( id == %s )" % \
                        (scmd, ConfigMgr.sysList.index(item))
                except:
                    continue
            scmd = scmd[scmd.find("("):]

        SysMgr.writeCmd('raw_syscalls/filter', scmd)
        ret = SysMgr.writeCmd(cmd, '1')
        if ret < 0:
            SysMgr.printWarn("fail to enable syscall events", True)



    @staticmethod
    def printSigError(tid, signal, warn=True):
        if warn:
            printFunc = SysMgr.printWarn
        else:
            printFunc = SysMgr.printErr

        printFunc(
            "fail to send %s to thread %s" % (signal, tid), reason=True)



    @staticmethod
    def getLine(start=1):
        try:
            inspect = SysMgr.getPkg('inspect')
            lines = ''
            for stack in inspect.stack()[start:-1]:
                lines += '%s<' % inspect.getframeinfo(stack[0]).lineno
            return lines.rstrip('<')
        except:
            return None



    @staticmethod
    def getErrMsg(start=2):
        et, err, to = sys.exc_info()
        lineno = SysMgr.getLine(start=start)

        try:
            if not err.args or err.args[0] == 0:
                return '%s at %s line' % \
                    (sys.exc_info()[0].__name__, lineno)
        except:
            if to:
                return 'N/A at %s line' % lineno
            else:
                return 'N/A'

        try:
            code = '%s-' % errno.errorcode[err.args[0]]
        except:
            code = ''

        errstr = ' '.join(list(map(str, err.args)))
        return '%s%s at %s line' % (code, errstr, lineno)



    def disableAllEvents(self):
        for event in list(self.cmdList.keys()):
            self.cmdList[event] = False



    @staticmethod
    def writeCustomCmd():
        effectiveCmd = []

        if not SysMgr.customCmd:
            return

        if 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(0)

            # check filter #
            if len(cmdFormat) == 1:
                origFilter = ''
                cmdFormat.append(pidFilter)
            else:
                origFilter = cmdFormat[1]
                cmdFormat[1] = pidFilter + " && " + cmdFormat[1]

            # check effective event #
            if SysMgr.writeCmd(cmdFormat[0] + '/enable', '0') < 0:
                SysMgr.printErr("wrong event '%s'" % cmdFormat[0])
                sys.exit(0)

            # check and enable effective filter #
            if len(cmdFormat) > 1 and \
                SysMgr.writeCmd(cmdFormat[0] + '/filter', cmdFormat[1]) < 0:
                SysMgr.printErr("wrong filter '%s' for '%s' event" % \
                    (origFilter, cmdFormat[0]))
                sys.exit(0)

            # check and enable effective event #
            if SysMgr.writeCmd(cmdFormat[0] + '/enable', '1') < 0:
                SysMgr.printErr("wrong event '%s'" % cmdFormat[0])
                sys.exit(0)
            else:
                effectiveCmd.append(cmdFormat[0])

        if len(effectiveCmd) > 0:
            SysMgr.printInfo(
                "enabled custom events [ %s ]" % ', '.join(effectiveCmd))



    @staticmethod
    def printAnalOption():
        enableStat = ''
        disableStat = ''

        if SysMgr.outputFile:
            return

        if not SysMgr.isRecordMode() and \
            not SysMgr.isTopMode():
            # common options #
            enableStat += SysMgr.arch.upper() + ' '
            if SysMgr.warnEnable:
                enableStat += 'WARN '

        # function mode #
        if SysMgr.isFuncMode():
            if not SysMgr.heapEnable:
                disableStat += 'HEAP '
            else:
                enableStat += 'HEAP '

            if not SysMgr.userEnable:
                disableStat += 'USER '
            else:
                enableStat += 'USER '

            if SysMgr.customCmd:
                SysMgr.printInfo(
                    "selected custom events [ %s ]" % \
                    ', '.join(SysMgr.customCmd))
        # thread mode #
        else:
            if SysMgr.intervalEnable > 0:
                enableStat += 'INTERVAL '
            else:
                disableStat += 'INTERVAL '

            if SysMgr.latEnable:
                enableStat += 'LATENCY '
            else:
                disableStat += 'LATENCY '

            if SysMgr.depEnable:
                enableStat += 'DEP '
            else:
                disableStat += 'DEP '

            if SysMgr.ueventEnable:
                enableStat += 'UEVT '
            else:
                disableStat += 'UEVT '

            if SysMgr.keventEnable:
                enableStat += 'KEVT '
            else:
                disableStat += 'KEVT '

            if SysMgr.irqEnable:
                enableStat += 'IRQ '
            else:
                disableStat += 'IRQ '

            if SysMgr.networkEnable:
                enableStat += 'NET '
            else:
                disableStat += 'NET '

            if SysMgr.powerEnable:
                enableStat += 'POWER '
            else:
                disableStat += 'POWER '

            if SysMgr.wqEnable:
                enableStat += 'WQ '
            else:
                disableStat += 'WQ '

            if SysMgr.preemptGroup:
                enableStat += 'PREEMPT '
            else:
                disableStat += 'PREEMPT '

            if SysMgr.perCoreList:
                enableStat += 'PERCORE '
            else:
                disableStat += 'PERCORE '

            if SysMgr.customCmd:
                SysMgr.printInfo(
                    "selected custom events [ %s ]" % \
                    ', '.join(SysMgr.customCmd))

        # common options #
        if SysMgr.showAll:
            enableStat += 'ALL '
        else:
            disableStat += 'ALL '

        if SysMgr.groupProcEnable:
            enableStat += 'PGRP '
        else:
            disableStat += 'PGRP '

        if SysMgr.cpuEnable:
            enableStat += 'CPU '
        else:
            disableStat += 'CPU '

        if SysMgr.memEnable:
            enableStat += 'MEM '
        else:
            disableStat += 'MEM '

        if SysMgr.blockEnable:
            enableStat += 'BLOCK '
        else:
            disableStat += 'BLOCK '

        if SysMgr.printEnable:
            enableStat += 'PRINT '
        else:
            disableStat += 'PRINT '

        if SysMgr.sysEnable:
            enableStat += 'SYSCALL '
        else:
            disableStat += 'SYSCALL '

        if SysMgr.lockEnable:
            enableStat += 'LOCK '
        else:
            disableStat += 'LOCK '

        if SysMgr.compressEnable:
            enableStat += 'COMP '
        else:
            disableStat += 'COMP '

        if SysMgr.countEnable:
            enableStat += 'CUT '
        else:
            disableStat += 'CUT '

        # check current mode #
        if SysMgr.disableAll:
            enableStat += 'DISABLE '

        # print options #
        if enableStat != '':
            SysMgr.printInfo(
                "enabled analysis options [ %s]" % enableStat)

        if disableStat != '':
            SysMgr.printWarn(
                "disabled analysis options [ %s]" % disableStat)



    @staticmethod
    def getUdsList():
        udsBuf = []
        udsPath = '%s/net/unix' % SysMgr.procPath

        try:
            with open(udsPath, 'r') as fd:
                udsBuf = fd.readlines()
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenErr(udsPath)
            return udsBuf

        UDS_ATTR = []
        for line in udsBuf:
            UDS_ATTR.append(line.split())

        # remove title #
        UDS_ATTR.pop(0)

        return UDS_ATTR



    @staticmethod
    def getUdpList():
        if SysMgr.udpListCache:
            return SysMgr.udpListCache

        udpBuf = []
        udpPath = '%s/net/udp' % SysMgr.procPath

        try:
            with open(udpPath, 'r') as fd:
                udpBuf = fd.readlines()
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenErr(udpPath)
            return udpBuf

        udpList = []
        for line in udpBuf:
            udpList.append(line.split())

        # remove title #
        udpList.pop(0)

        SysMgr.udpListCache = udpList

        return udpList



    @staticmethod
    def getTcpList():
        if SysMgr.tcpListCache:
            return SysMgr.tcpListCache

        tcpBuf = []
        tcpPath = '%s/net/tcp' % SysMgr.procPath

        try:
            with open(tcpPath, 'r') as fd:
                tcpBuf = fd.readlines()
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenErr(tcpPath)
            return tcpBuf

        tcpList = []
        for line in tcpBuf:
            tcpList.append(line.split())

        # remove title #
        tcpList.pop(0)

        SysMgr.tcpListCache = tcpList

        return tcpList



    @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("fail 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(
                "fail 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("fail to find getauxval in libc")
            return None

        return SysMgr.libcObj.getauxval(c_ulong(nrType))



    @staticmethod
    def printProfileOption():
        enableStat = ''
        disableStat = ''

        # common options #
        enableStat += SysMgr.arch.upper() + ' '

        if SysMgr.warnEnable:
            enableStat += 'WARN '
        else:
            disableStat += 'WARN '

        if SysMgr.pipeEnable:
            enableStat += 'PIPE '
        else:
            disableStat += 'PIPE '

        if SysMgr.printEnable:
            enableStat += 'PRINT '
        else:
            disableStat += 'PRINT '

        if SysMgr.cgroupEnable:
            enableStat += 'CGROUP '
        else:
            disableStat += 'CGROUP '

        if SysMgr.encodeEnable:
            enableStat += 'ENCODE '
        else:
            disableStat += 'ENCODE '

        if SysMgr.compressEnable:
            enableStat += 'COMP '
        else:
            disableStat += 'COMP '

        # check current mode #
        if SysMgr.isTopMode():
            SysMgr.printInfo("<TOP MODE>")

            if SysMgr.fileTopEnable:
                enableStat += 'FILE '
            else:
                if SysMgr.processEnable:
                    enableStat += 'PROCESS '
                else:
                    enableStat += 'THREAD '

                if SysMgr.cpuEnable:
                    enableStat += 'CORE '
                else:
                    disableStat += 'CORE '

                if SysMgr.gpuEnable:
                    enableStat += 'GPU '
                else:
                    disableStat += 'GPU '

                if SysMgr.memEnable:
                    enableStat += 'MEM '
                else:
                    disableStat += 'MEM '

                if SysMgr.blockEnable:
                    enableStat += 'BLOCK '
                else:
                    disableStat += 'BLOCK '

                if SysMgr.irqEnable:
                    enableStat += 'IRQ '
                else:
                    disableStat += 'IRQ '

                if SysMgr.diskEnable:
                    enableStat += 'DISK '
                else:
                    disableStat += 'DISK '

                if SysMgr.perfEnable or \
                    SysMgr.perfGroupEnable:
                    enableStat += 'PERF '
                else:
                    disableStat += 'PERF '

                if SysMgr.nsEnable:
                    enableStat += 'NS '
                else:
                    disableStat += 'NS '

                if SysMgr.wchanEnable:
                    enableStat += 'WCHAN '
                else:
                    disableStat += 'WCHAN '

                if SysMgr.oomEnable:
                    enableStat += 'OOM '
                else:
                    disableStat += 'OOM '

                if SysMgr.floatEnable:
                    enableStat += 'FLOAT '
                else:
                    disableStat += 'FLOAT '

                if SysMgr.sigHandlerEnable:
                    enableStat += 'SIG '
                else:
                    disableStat += 'SIG '

                if SysMgr.wfcEnable:
                    enableStat += 'WFC '
                else:
                    disableStat += 'WFC '

                if SysMgr.cmdlineEnable:
                    enableStat += 'CMD '
                else:
                    disableStat += 'CMD '

                if SysMgr.stackEnable:
                    enableStat += 'STACK '

                if SysMgr.networkEnable:
                    enableStat += 'NET '

                if SysMgr.affinityEnable:
                    enableStat += 'AFNT '
                else:
                    disableStat += 'AFNT '

                if SysMgr.reportFileEnable:
                    enableStat += 'RFILE '
                else:
                    disableStat += 'RFILE '

                if SysMgr.pssEnable:
                    enableStat += 'PSS '
                else:
                    disableStat += 'PSS '

                if SysMgr.ussEnable:
                    enableStat += 'USS '
                else:
                    disableStat += 'USS '

                if SysMgr.wssEnable:
                    enableStat += 'WSS '
                else:
                    disableStat += 'WSS '

                if SysMgr.dltEnable:
                    enableStat += 'DLT '
                else:
                    disableStat += 'DLT '

                if SysMgr.syslogEnable:
                    enableStat += 'SYSLOG '
                else:
                    disableStat += 'SYSLOG '

                if SysMgr.dwarfEnable:
                    enableStat += 'DWARF '
                else:
                    disableStat += 'DWARF '

                if SysMgr.kmsgEnable:
                    enableStat += 'KMSG '
                else:
                    disableStat += 'KMSG '

                if SysMgr.journalEnable:
                    enableStat += 'JRL '
                else:
                    disableStat += 'JRL '

                if SysMgr.schedEnable:
                    enableStat += 'SCHED '
                else:
                    disableStat += 'SCHED '

                if SysMgr.delayEnable:
                    enableStat += 'DELAY '
                else:
                    disableStat += 'DELAY '

                if SysMgr.groupProcEnable:
                    enableStat += 'PGRP '
                else:
                    disableStat += 'PGRP '

                if SysMgr.reportEnable:
                    enableStat += 'REPORT '
                else:
                    disableStat += 'REPORT '

                if SysMgr.totalEnable:
                    enableStat += 'TOTAL '
                else:
                    disableStat += 'TOTAL '

                if SysMgr.barGraphEnable:
                    enableStat += 'BAR '
                else:
                    disableStat += 'BAR '

        elif SysMgr.isFuncMode():
            SysMgr.printInfo("<FUNCTION MODE>")

            if SysMgr.graphEnable:
                enableStat += 'GRAPH '
            else:
                disableStat += 'GRAPH '

                if not SysMgr.cpuEnable:
                    disableStat += 'CPU '
                else:
                    enableStat += 'CPU '

                if not SysMgr.memEnable:
                    disableStat += 'MEM '
                else:
                    enableStat += 'MEM '

                if not SysMgr.heapEnable:
                    disableStat += 'HEAP '
                else:
                    enableStat += 'HEAP '

                if not SysMgr.blockEnable:
                    disableStat += 'BLOCK '
                else:
                    enableStat += 'BLOCK '

                if not SysMgr.userEnable:
                    disableStat += 'USER '
                else:
                    enableStat += 'USER '

                if SysMgr.sysEnable:
                    enableStat += 'SYSCALL '
                else:
                    disableStat += 'SYSCALL '

                if SysMgr.lockEnable:
                    enableStat += 'LOCK '
                else:
                    disableStat += 'LOCK '

                if SysMgr.disableAll:
                    enableStat += 'DISABLE '
                else:
                    disableStat += 'DISABLE '

        elif SysMgr.isFileMode():
            SysMgr.printInfo("<FILE MODE>")

        elif SysMgr.isSystemMode():
            SysMgr.printInfo("<SYSTEM MODE>")

        else:
            SysMgr.printInfo("<THREAD MODE>")
            SysMgr.threadEnable = True

            if not SysMgr.cpuEnable:
                disableStat += 'CPU '
            else:
                enableStat += 'CPU '

            if SysMgr.memEnable:
                enableStat += 'MEM '
            else:
                disableStat += 'MEM '

            if SysMgr.blockEnable:
                enableStat += 'BLOCK '
            else:
                disableStat += 'BLOCK '

            if SysMgr.irqEnable:
                enableStat += 'IRQ '
            else:
                disableStat += 'IRQ '

            if SysMgr.ueventEnable:
                enableStat += 'UEVT '
            else:
                disableStat += 'UEVT '

            if SysMgr.keventEnable:
                enableStat += 'KEVT '
            else:
                disableStat += 'KEVT '

            if SysMgr.bufferLossEnable:
                enableStat += 'BLOSS '
            else:
                disableStat += 'BLOSS '

            if SysMgr.networkEnable:
                enableStat += 'NET '
            else:
                disableStat += 'NET '

            if SysMgr.depEnable:
                enableStat += 'DEP '
            else:
                disableStat += 'DEP '

            if SysMgr.latEnable:
                enableStat += 'LATENCY '
            else:
                disableStat += 'LATENCY '

            if SysMgr.sysEnable:
                enableStat += 'SYSCALL '
            else:
                disableStat += 'SYSCALL '

            if SysMgr.lockEnable:
                enableStat += 'LOCK '
            else:
                disableStat += 'LOCK '

            if SysMgr.powerEnable:
                enableStat += 'POWER '
            else:
                disableStat += 'POWER '

            if SysMgr.wqEnable:
                enableStat += 'WQ '
            else:
                disableStat += 'WQ '

            if SysMgr.resetEnable:
                enableStat += 'RESET '

            if SysMgr.disableAll:
                enableStat += '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)

        # masking signal #
        if signum:
            signal.signal(signum, signal.SIG_IGN)

        # write user command #
        SysMgr.writeTraceCmd('STOP')

        if SysMgr.isFileMode() or \
            SysMgr.isSystemMode():
            SysMgr.condExit = True

        elif SysMgr.isTopMode() or SysMgr.isTraceMode():
            if SysMgr.outPath:
                # reload data written to file #
                if SysMgr.pipeEnable:
                    SysMgr.reloadFileBuffer()

                SysMgr.printLogo(absolute=True, big=True)

                # save system info #
                SysMgr.sysInstance.saveSysStat()
                SysMgr.printInfoBuffer()

                # submit summarized report and details #
                TaskAnalyzer.printIntervalUsage()

                if os.path.exists(SysMgr.inputFile):
                    # get output size #
                    fsize = UtilMgr.getFileSize(SysMgr.inputFile)
                    if fsize and fsize != '0':
                        fsize = ' [%s]' % fsize
                    else:
                        fsize = ''

                    SysMgr.printInfo(
                        "saved results based monitoring into "
                        "'%s'%s successfully" % \
                        (SysMgr.inputFile, fsize))

            SysMgr.releaseResource()

            # re-enable signal again #
            if signum:
                signal.signal(signum, SysMgr.stopHandler)

            # quit to avoid termination #
            if not SysMgr.termFlag:
                SysMgr.progressCnt = long(0)
                return

            '''
            # enable for cProfile #
            sys.settrace
            sys.exit(0)
            '''

            # do terminate #
            os._exit(0)

        else:
            SysMgr.writeEvent("EVENT_STOP", False)
            if signum:
                signal.signal(signal.SIGINT, signal.SIG_DFL)
            SysMgr.stopRecording()

        # update record status #
        SysMgr.recordStatus = False

        SysMgr.repeatCount = long(0)

        SysMgr.printStat(
            'ready to save and analyze... [ STOP(Ctrl+c) ]')

        # enable signal again #
        if signum:
            signal.signal(signum, SysMgr.stopHandler)

        if not "ISMAIN" in os.environ:
            sys.exit(0)

        raise Exception('stop signal')



    @staticmethod
    def newHandler(signum=None, frame=None):
        SysMgr.condExit = False

        if SysMgr.isFileMode():
            SysMgr.printStat("saved file usage successfully")
        elif SysMgr.isSystemMode():
            pass
        elif SysMgr.isTopMode():
            # 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()

            SysMgr.printLogo(absolute=True, big=True)

            # save system info #
            SysMgr.sysInstance.saveSysStat()
            SysMgr.printInfoBuffer()

            # submit summarized report and details #
            TaskAnalyzer.printIntervalUsage()

            # close an output file to sync #
            try:
                SysMgr.printFd.close()
            except:
                pass
            finally:
                SysMgr.printFd = None

            # print output info #
            fsize = UtilMgr.getFileSize(SysMgr.inputFile)
            if fsize and fsize != '0':
                fsize = ' [%s]' % fsize
            else:
                fsize = ''

            SysMgr.printInfo(
                "saved results based monitoring into "
                "'%s'%s successfully" % \
                    (SysMgr.inputFile, fsize))

            # enable signal again #
            if signum:
                signal.signal(signum, SysMgr.newHandler)
        elif SysMgr.resetEnable:
            SysMgr.writeEvent("EVENT_START")
        else:
            SysMgr.writeEvent("EVENT_MARK")



    @staticmethod
    def exitHandler(signum, frame):
        if SysMgr.exitFlag:
            os._exit(0)

        # block signals and disable alarm for stable termination #
        SysMgr.setIgnoreSignal()
        signal.alarm(0)
        SysMgr.condExit = True

        # reset terminal #
        SysMgr.resetTTY()

        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):
        if SysMgr.repeatCount <= SysMgr.progressCnt and \
            SysMgr.termFlag:
            UtilMgr.deleteProgress()
            sys.exit(0)

        if 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:
                SysMgr.stopRecording()
                SysMgr.recordStatus = False
            signal.alarm(repeatInterval)
        elif SysMgr.outputFile:
            if repeatCount == 1 and SysMgr.termFlag:
                output = SysMgr.outputFile
            else:
                output = '%s_%s' % \
                    (SysMgr.outputFile, SysMgr.getRuntime())

            # save system info #
            SysMgr.sysInstance.saveSysStat()

            # read trace data #
            try:
                rpath = os.path.join(SysMgr.mountPath, '../trace')
                with open(rpath, 'r') as fr:
                    lines = fr.readlines()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenErr(rpath)
                sys.exit(0)

            # write trace data #
            try:
                SysMgr.saveTraceData(lines, output)
                SysMgr.clearInfoBuffer()
            except SystemExit:
                sys.exit(0)
            except:
                sys.exit(0)
        else:
            SysMgr.printErr(
                'fail to save data because file path is not set')
            sys.exit(0)

        # set alarm again #
        signal.signal(signal.SIGALRM, SysMgr.alarmHandler)



    @staticmethod
    def isTermSignal(sig):
        if sig == signal.SIGKILL or \
            sig == signal.SIGSEGV or \
            sig == signal.SIGABRT:
            return True
        else:
            return False



    @staticmethod
    def saveTraceData(lines, outputFile=None):
        if not outputFile:
            outputFile = SysMgr.outputFile

        # backup file already exists #
        SysMgr.backupFile(outputFile)

        disabledOptions = SysMgr.getOption('d')

        # compress data by default #
        if disabledOptions and 'C' in disabledOptions:
            compressEnable = False
        else:
            compressEnable = True

        # compress by gzip #
        if SysMgr.isRecordMode() and compressEnable:
            compressor = SysMgr.getPkg('gzip', False)
        else:
            compressor = None

        size = long(0)
        for line in lines:
            size += len(line)

        SysMgr.printInfo(
            "wait for writing data to '%s' [%s]" % \
                (outputFile, UtilMgr.convSize2Unit(size)))

        try:
            if compressor:
                fd = open(outputFile, 'wb')
                f = compressor.GzipFile(fileobj=fd)
            else:
                f = open(outputFile, 'w')

            # write system info #
            if SysMgr.systemInfoBuffer:
                magicStr = '%s\n' % SysMgr.magicStr

                if compressor:
                    magicStr = magicStr.encode('utf-8')

                f.write(magicStr)

                if compressor:
                    f.write(SysMgr.systemInfoBuffer.encode('utf-8'))
                else:
                    f.write(SysMgr.systemInfoBuffer)

                f.write(magicStr)

            # write trace info #
            if compressor:
                f.write('\n'.join(lines).encode('utf-8'))
            else:
                f.writelines(lines)

            f.close()

            # get output size #
            fsize = UtilMgr.getFileSize(outputFile)
            if fsize and fsize != '0':
                fsize = ' [%s]' % fsize
            else:
                fsize = ''

            SysMgr.printInfo(
                "finish saving trace data into '%s'%s successfully" % \
                (outputFile, fsize))
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "fail to write trace data to '%s'" % outputFile, True)



    @staticmethod
    def writeTraceCmd(time):
        if SysMgr.rcmdList == {}:
            return

        for cmd in SysMgr.rcmdList[time]:
            if len(cmd) == 2:
                path = cmd[0]
                val = cmd[1]

                try:
                    with open(path, 'w') as fd:
                        fd.write(val)
                        SysMgr.printInfo(
                            "applied command '%s' to %s successfully" % \
                            (val, path))
                except:
                    SysMgr.printWarn(
                        "fail to apply command '%s' to %s" % (val, path))
            elif len(cmd) == 1:
                os.system(cmd[0])



    @staticmethod
    def readCmdVal(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(
                "fail 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 writeCmd(path, val, append=False):
        # set file 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 "\nstart 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)
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr("fail to write command")
                    return -1

        # open for applying command #
        try:
            fd = None
            target = '%s%s' % (SysMgr.mountPath, path)

            if append:
                if target in SysMgr.cmdAttachCache:
                    fd = SysMgr.cmdAttachCache[target]
                    os.lseek(fd, 0, 0)
                else:
                    fd = os.open(target, os.O_RDWR|os.O_CREAT|os.O_APPEND)
                    SysMgr.cmdAttachCache[target] = fd
            else:
                try:
                    fd = SysMgr.cmdFileCache[target]
                    fd.seek(0)
                except:
                    pass

                if not fd:
                    fd = open(target, perm)
                    SysMgr.cmdFileCache[target] = fd
        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(
                "fail to use %s event" % epath, reason=True)
            return -1

        # apply command #
        try:
            if append:
                os.write(fd, bytes(UtilMgr.encodeStr(val)))
                os.fsync(fd)
            else:
                fd.write(val)
                fd.flush()

            # modify flags in 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.cmdFileCache.pop(target, None)
            SysMgr.printWarn(
                "fail to apply command '%s' to %s" % \
                    (val, path), reason=True)
            return -2

        return 0



    @staticmethod
    def doPrint(newline=True, clear=False, flush=True, addLine=False):
        if not SysMgr.bufferString:
            return

        if addLine:
            output = '%s\n' % SysMgr.bufferString
        else:
            output = SysMgr.bufferString

        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 #
        print(string.rstrip())



    @staticmethod
    def addPrint(string, newline=1, force=False, listBuf=False):
        if not force and SysMgr.checkCutCond(newline):
            return False

        # add string to buffer #
        if listBuf:
            SysMgr.bufferList.append(string)
        else:
            SysMgr.bufferString = \
                "%s%s" % (SysMgr.bufferString, string)

        SysMgr.bufferRows += newline

        if SysMgr.terminalOver or \
            not SysMgr.outPath or \
            not SysMgr.printStreamEnable:
            return True

        SysMgr.printConsole(string)

        return True



    @staticmethod
    def getPrintList(retStr=False, sort=False):
        if sort:
            SysMgr.bufferList.sort()

        if retStr:
            return '\n'.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.bufferString = ''
        SysMgr.bufferRows = long(0)
        SysMgr.terminalOver = False



    @staticmethod
    def clearScreen():
        # check stdout status #
        if not SysMgr.printEnable or \
            SysMgr.pipeForPager:
            return

        if SysMgr.isLinux and \
            not 'REMOTERUN' in os.environ:
            sys.stdout.write("\x1b[2J\x1b[H")
        elif sys.platform.startswith('win'):
            os.system('cls')
        else:
            pass



    @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.convertExtAscii(ConfigMgr.logo)

        if not SysMgr.outPath:
            if SysMgr.printStreamEnable:
                if not absolute:
                    return
            elif onlyFile:
                return

        # print logo #
        if big:
            if pager:
                SysMgr.printPipe(ConfigMgr.logo)
            else:
                print(ConfigMgr.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))



    @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]

            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(0)
            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

        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

        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': ' '}

        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:-1]
                    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

        # apply arch type #
        if not SysMgr.archOption:
            try:
                archPosStart = infoBuf.find('Arch')
                archPosEnd = infoBuf.find('\n', archPosStart)
                arch = infoBuf[archPosStart:archPosEnd].split()[1]
                SysMgr.setArch(arch)
            except:
                pass

        # add anlaysis option #
        archPosStart = infoBuf.find('Arch')
        archPosEnd = infoBuf.find('\n', archPosStart)
        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 'u' in filterList:
                SysMgr.userEnable = False
                SysMgr.userRecordEnable = False
            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 '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 '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 len(filterList) > 0:
                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(0)



    @staticmethod
    def writeEvent(message, show=True):
        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(
                    "fail to open %s" % SysMgr.eventLogPath)
                return

        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(
                    "fail to write %s event" % (message), reason=True)
                return
        else:
            SysMgr.printErr(
                "fail 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((
            "fail to import python package: %s, "
            "try to enter '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):

        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((
                            'fail to recognize %s in '
                            'X:Y:NAME:[CPU|MEM|IO]:[BOX|CIRCLE|LARROW|RARROW]'
                            'format') % item)
                        sys.exit(0)

                    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(
                        'fail to recognize event for timeline', reason=True)
                    sys.exit(0)



        # get svgwrite object #
        svgwrite = SysMgr.getPkg('svgwrite')

        if inputPath:
            inputStr = ' from "%s"' % inputPath
        else:
            inputStr = ''

        SysMgr.printInfo(
            "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 = 'ms'

            # apply user event #
            _addUserEvent(inputData)

            # load data #
            timeline = Timeline.load(inputPath, inputData, config, taskList)

            # draw timeslices #
            timeline.draw(dwg)

            dwg.save()
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                'fail to draw timeline', reason=True)
            return

        # get output size #
        fsize = UtilMgr.getFileSize(outputPath)
        if fsize and fsize != '0':
            fsize = ' [%s]' % fsize
        else:
            fsize = ''

        SysMgr.printStat(
            "wrote timeline chart into '%s'%s" %
                (outputPath, fsize))



    @staticmethod
    def drawText(lines):
        imageType = None

        # get textwrap object #
        textwrap = SysMgr.getPkg('textwrap', False)
        if not textwrap:
            SysMgr.printPipWarn('textwrap', 'textwrap3')
            sys.exit(0)

        # get PIL object #
        PIL = SysMgr.getPkg('PIL', False)
        if not PIL:
            SysMgr.printPipWarn('PIL', 'pillow')
            sys.exit(0)

        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(
                "fail to import python package: %s" % err.args[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(
                "fail to import python package: %s" % err.args[0])
            return

        if not SysMgr.imagePath:
            SysMgr.printErr("fail 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(
                    "fail to load font from %s" % SysMgr.fontPath)
                return
        else:
            try:
                # load default font #
                imageFont = ImageFont.load_default().font
            except:
                SysMgr.printErr((
                    "fail 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:
            SysMgr.printErr(
                "fail to save image as %s\n" % SysMgr.imagePath)
            return

        # get output size #
        fsize = UtilMgr.getFileSize(SysMgr.imagePath)
        if fsize and fsize != '0':
            fsize = ' [%s]' % fsize
        else:
            fsize = ''

        SysMgr.printStat(
            "saved image into %s%s successfully" % \
                (SysMgr.imagePath, fsize))



    @staticmethod
    def addProcBuffer(data):
        SysMgr.procBuffer.insert(0, data)
        SysMgr.procBufferSize += len(data)

        bufferSize = SysMgr.bufferSize

        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") %
                        (UtilMgr.convSize2Unit(SysMgr.procBufferSize),
                        UtilMgr.convSize2Unit(SysMgr.bufferSize)))

                # create a new process #
                pid = SysMgr.createProcess(isDaemon=True, chPgid=True)
                # save output to file as child #
                if pid == 0:
                    try:
                        SysMgr.printFd.close()
                    except:
                        pass
                    finally:
                        SysMgr.printFd = None

                    # append uptime to the output file #
                    SysMgr.fileSuffix = long(SysMgr.getUptime())

                    # flush all data to the file #
                    SysMgr.newHandler()

                    sys.exit(0)
                # clear buffer as parent #
                elif pid > 0:
                    SysMgr.procBufferSize = 0
                    SysMgr.procBuffer = []
                    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") % \
                        UtilMgr.convSize2Unit(SysMgr.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:
            # convert dict data to JSON-type string #
            jsonObj = UtilMgr.convDict2Str(SysMgr.jsonData, pretty=False)
            if not jsonObj:
                SysMgr.printWarn(
                    "fail to convert report data to JSON type")
            else:
                SysMgr.printPipe(jsonObj)
        # realtime mode #
        elif not SysMgr.outPath:
            if not SysMgr.printStreamEnable:
                SysMgr.clearScreen()
            SysMgr.doPrint()
        # pipe mode #
        elif SysMgr.pipeEnable:
            SysMgr.doPrint(addLine=True)
        # buffered mode #
        else:
            SysMgr.addProcBuffer(SysMgr.bufferString+'\n')

        # 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.printStreamEnable 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

        if interval:
            signal.alarm(long(interval))
        else:
            signal.alarm(SysMgr.intervalEnable)



    @staticmethod
    def updateOutPath():
        # dir #
        if os.path.isdir(SysMgr.outPath):
            SysMgr.inputFile = \
                os.path.join(SysMgr.outPath, SysMgr.outFilePath)
        # file #
        else:
            SysMgr.inputFile = SysMgr.outPath

        # append suffix to output file #
        if SysMgr.fileSuffix:
            dirname = os.path.dirname(SysMgr.inputFile)
            filename = os.path.basename(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 printPipe(line='', newline=True, flush=False, pager=True):
        # check logging option #
        if SysMgr.loggingEnable:
            if SysMgr.dltEnable:
                DltAnalyzer.doLogDlt(msg=line)
            if SysMgr.kmsgEnable:
                LogMgr.doLogKmsg(msg=line)
            if SysMgr.syslogEnable:
                LogMgr.doLogSyslog(msg=line)
            if SysMgr.journalEnable:
                LogMgr.doLogJournal(msg=line)

        # socket output #
        if SysMgr.addrListForPrint and line:
            addrListForPrint = dict(SysMgr.addrListForPrint)
            for addr, cli in addrListForPrint.items():
                udpSeg = 65507 # maxium 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

        # 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.printStreamEnable:
            pass
        elif not SysMgr.isTopMode() or SysMgr.isHelpMode():
            try:
                if SysMgr.isLinux:
                    if UtilMgr.which('less'):
                        #defopt = '-FRSXMQi'
                        defopt = '-FRXMQi'

                        # 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')
                    elif UtilMgr.which('more'):
                        SysMgr.pipeForPager = os.popen('more', 'w')
                elif sys.platform.startswith('win'):
                    if UtilMgr.which('more'):
                        SysMgr.pipeForPager = os.popen('more', 'w')
                else:
                    # no supported OS #
                    SysMgr.pipeForPager = None

                SysMgr.encodeEnable = False

                SysMgr.setPipeHandler()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn(
                    "fail 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(
                    "fail 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:
                SysMgr.inputFile += '.gz'
                if SysMgr.outPath:
                    SysMgr.outPath += '.gz'

            # backup an exist file #
            SysMgr.backupFile(SysMgr.inputFile)

            # open file #
            try:
                # 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(0)

        # 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(
                    "fail to write to %s" % SysMgr.printFd.name, True)
        # console output #
        else:
            cols = SysMgr.ttyCols

            # rstrip by terminal size #
            try:
                # no limit #
                if cols == 0 or SysMgr.jsonEnable:
                    line = '\n'.join([nline for nline in line.split('\n')])
                # rstrip for colorful lines #
                elif SysMgr.colorEnable and ConfigMgr.ENDC in line:
                    ansi = r'(?:\x1B[@-_]|[\x80-\x9F])[0-?]*[ -/]*[@-~]'
                    ansiObj = re.compile(ansi)
                    line = '\n'.join(
                        [ansiObj.sub('', n)[:cols] \
                            if len(ansiObj.sub('', n)) > cols else n \
                            for n in line.split('\n')])
                # rstrip for normal lines #
                else:
                    line = '\n'.join(
                        [nline[:cols-1] for nline in line.split('\n')])
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn("fail to print to console", reason=True)
                return

            # convert to extended ascii #
            nline = SysMgr.convertExtAscii(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)

            if newline:
                sys.stdout.write('\n')

            # flush buffer #
            if flush or SysMgr.remoteRun:
                sys.stdout.flush()



    @staticmethod
    def convertExtAscii(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 printWarn(line, always=False, reason=False):
        # 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 = ''

        # apply color #
        if SysMgr.colorEnable:
            color = ConfigMgr.WARNING
            colorl = ConfigMgr.ENDC
        else:
            color = colorl = ''

        proc = SysMgr.getProcInfo()

        log = ('\n%s%s%s%s%s%s\n' % \
            (color, '[WARN] ', proc, line, rstring, colorl))

        # 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(start=3)
        else:
            rstring = ''

        try:
            line = line.rstrip('\n')
        except:
            pass

        # apply color #
        if SysMgr.colorEnable:
            color = ConfigMgr.FAIL
            colorl = ConfigMgr.ENDC
        else:
            color = colorl = ''

        proc = SysMgr.getProcInfo()

        log = ('\n%s%s%s%s%s%s\n' % \
            (color, '[ERROR] ', proc, line, rstring, colorl))

        # 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 getProcInfo():
        if SysMgr.parentPid > 0:
            return '<%s(%s)> ' % (SysMgr.comm, SysMgr.pid)
        else:
            return ''



    @staticmethod
    def printInfo(line, prefix=True, suffix=True, notitle=False):
        if not SysMgr.logEnable:
            return

        if notitle:
            title = ''
        else:
            title = '[INFO] '

        if prefix:
            prefix = '\n'
        else:
            prefix = ''

        # apply color #
        if SysMgr.colorEnable:
            color = ConfigMgr.BOLD
            colorl = ConfigMgr.ENDC
        else:
            color = colorl = ''

        proc = SysMgr.getProcInfo()
        log = '%s%s%s%s%s%s' % \
            (prefix, color, title, proc, line, colorl)

        if SysMgr.stdlog:
            SysMgr.stdlog.write(log)

        if suffix:
            try:
                print(log)
            except:
                return
        else:
            try:
                sys.stdout.write(log)
                sys.stdout.flush()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    'fail to flush stdout', reason=True)



    @staticmethod
    def printGood(line):
        if not SysMgr.logEnable:
            return

        # apply color #
        if SysMgr.colorEnable:
            color = ConfigMgr.OKGREEN
            colorl = ConfigMgr.ENDC
        else:
            color = colorl = ''

        proc = SysMgr.getProcInfo()

        log = '\n%s%s%s%s%s' % \
            (color, '[INFO] ', proc, line, colorl)

        if SysMgr.stdlog:
            SysMgr.stdlog.write(log)

        print(log)



    @staticmethod
    def printLine(line):
        if not SysMgr.logEnable:
            return

        # apply color #
        if SysMgr.colorEnable:
            color = ConfigMgr.UNDERLINE
            colorl = ConfigMgr.ENDC
        else:
            color = colorl = ''

        proc = SysMgr.getProcInfo()

        log = '\n%s%s%s%s' % \
            (color, proc, line, colorl)

        if SysMgr.stdlog:
            SysMgr.stdlog.write(log)

        print(log)



    @staticmethod
    def printStat(line):
        if not SysMgr.logEnable:
            return

        # apply color #
        if SysMgr.colorEnable:
            color = ConfigMgr.SPECIAL
            colorl = ConfigMgr.ENDC
        else:
            color = colorl = ''

        proc = SysMgr.getProcInfo()

        log = '\n%s%s%s%s%s' % \
            (color, '[STEP] ', proc, line, colorl)

        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):
        SysMgr.printErr(
            'fail to open %s' % path, True)



    @staticmethod
    def printOpenWarn(path, always=False):
        SysMgr.printWarn(
            'fail to open %s' % path, always, reason=True)



    @staticmethod
    def splitOptionString(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 parseOption(option=None):
        if not "ISMAIN" in os.environ:
            return

        if not option and SysMgr.optionList:
            return

        # parse options #
        parsedOpt = []
        prevIdx = long(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(0)



    @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
        convertNum = UtilMgr.convNum
        convTime = UtilMgr.convUnit2Time

        # split params #
        if value:
            repeatParams = UtilMgr.cleanItem(value.split(':'))

        if not value:
            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])

                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(0)
        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
                        SysMgr.intervalEnable = ival
                    else:
                        SysMgr.repeatCount = interval
                        SysMgr.repeatInterval = interval
                        SysMgr.intervalEnable = 1
                # record mode #
                else:
                    SysMgr.repeatCount = 1
                    SysMgr.repeatInterval = interval
                    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(0)
        else:
            SysMgr.printErr((
                "wrong value for runtime option because %s, "
                "input in the format INTERVAL:REPEAT") % \
                    SysMgr.getErrMsg())
            sys.exit(0)

        # 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(0)

        # 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" % \
                (convertNum(SysMgr.intervalEnable),
                convertNum(SysMgr.repeatCount)))
        else:
            interval = SysMgr.intervalEnable
            repeat = SysMgr.repeatCount
            totalSec = convertNum(interval)
            totalCnt = convertNum(repeat)
            totalTime = convertNum(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):
        if path:
            try:
                fd = open(path, 'r')
            except:
                SysMgr.printOpenErr(path)
                sys.exit(0)
        else:
            fd = SysMgr.printFd

        try:
            fd.seek(0, 0)
            SysMgr.procBuffer = \
                fd.read().replace('\n\n', 'NEWSTAT\n\n')
            SysMgr.procBuffer = \
                SysMgr.procBuffer.split('NEWSTAT')
            fd.seek(0, 0)
            fd.truncate()
        except:
            return



    @staticmethod
    def checkOptVal(option, value):
        if not value:
            SysMgr.printErr(
                'no input value with -%s option' % option)
            sys.exit(0)



    @staticmethod
    def applySaveOption(value=None):
        # apply default path #
        if value == '':
            value = '.'

        # change output path #
        try:
            if SysMgr.isWritable(value):
                if os.path.isdir(value):
                    SysMgr.outputFile = \
                        '%s/guider.dat' % value
                else:
                    SysMgr.outputFile = value
            else:
                raise Exception('not writable')
        except:
            SysMgr.printErr(
                "wrong path '%s' because of permission" % value)
            sys.exit(0)

        # remove double slashs #
        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 for interval, "
                            "input number bigger than 0") % option)
                        sys.exit(0)
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr((
                        "wrong value for interval, "
                        "input number in integer format") % option)
                    sys.exit(0)

            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.showAll = True

            elif option == 'D':
                SysMgr.depEnable = True

            elif option == 'P':
                SysMgr.groupProcEnable = True

            elif option == 'p':
                SysMgr.checkOptVal(option, value)

                SysMgr.preemptGroup = \
                    UtilMgr.cleanItem(value.split(','))

            elif option == 'Y':
                SysMgr.checkOptVal(option, value)
                if not SysMgr.prio:
                    SysMgr.applyPriority(value)

            elif option == 'J':
                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

                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 'O' in options:
                    SysMgr.colorEnable = False

                if 'E' in options:
                    SysMgr.execEnable = 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.generalInfoEnable = False

                if 'D' in options:
                    SysMgr.dwarfEnable = 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 option == 'W':
                SysMgr.waitEnable = True

            elif 'F' in option:
                SysMgr.checkOptVal(option, value)

                SysMgr.drawFormat = value.strip()

            elif option == 'e':
                options = value

                if 'g' in options:
                    SysMgr.graphEnable = True

                if 'D' in options:
                    SysMgr.dwarfEnable = 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(0)
                    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(0)

                if 'B' in options:
                    SysMgr.barGraphEnable = True

                if 's' in options:
                    if SysMgr.checkStackTopCond():
                        SysMgr.stackEnable = True
                    else:
                        sys.exit(0)

                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(0)

                if 'w' in options:
                    if SysMgr.checkWssTopCond():
                        SysMgr.memEnable = True
                        SysMgr.wssEnable = True
                        SysMgr.sort = 'm'
                    else:
                        sys.exit(0)

                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(0)

                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(0)

            # ignore below options for function mode #
            elif SysMgr.isFuncMode():
                SysMgr.functionEnable = True

            elif option == 'l':
                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:
                        SysMgr.printErr(
                            'fail to convert [%s] to number' % \
                                ', '.join(SysMgr.boundaryLine), True)
                        sys.exit(0)
                else:
                    options = value

                    if 'd' in options:
                        SysMgr.loggingEnable = True
                        SysMgr.dltEnable = True

                    if 'k' in options:
                        SysMgr.loggingEnable = True
                        SysMgr.kmsgEnable = True

                    if 'j' in options:
                        SysMgr.loggingEnable = True
                        SysMgr.journalEnable = True

                    if 's' in options:
                        SysMgr.loggingEnable = True
                        SysMgr.syslogEnable = True

            elif option == 'r':
                SysMgr.checkOptVal(option, value)

                SysMgr.rootPath = value

            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(0)
                # this value will be used in various mode #
                else:
                    try:
                        SysMgr.utilProc = long(value)
                    except:
                        pass

            elif option == 'O':
                SysMgr.checkOptVal(option, value)

                SysMgr.perCoreList = \
                    UtilMgr.cleanItem(value.split(','))
                if not SysMgr.perCoreList:
                    SysMgr.printErr(
                        "no input value for filter" % option)
                    sys.exit(0)

                for item in SysMgr.perCoreList:
                    if not item.isdigit():
                        SysMgr.printErr((
                            "wrong value for core list, "
                            "input number in integer format") % option)
                        sys.exit(0)

                SysMgr.printInfo(
                    "only specific cores [ %s ] are shown" % \
                    ', '.join(SysMgr.perCoreList))

                SysMgr.perCoreList = \
                    list(map(long, SysMgr.perCoreList))

                if SysMgr.isDrawMode():
                    SysMgr.perCoreDrawList = SysMgr.perCoreList
                    SysMgr.perCoreList = []

            elif option == 't' and \
                not SysMgr.isRecordMode():
                SysMgr.syscallList = \
                    UtilMgr.cleanItem(value.split(','))
                enabledSyscall = []

                for val in SysMgr.syscallList:
                    try:
                        if val[0:4] == 'sys_':
                            nrSyscall = ConfigMgr.sysList.index(val)
                        else:
                            nrSyscall = \
                                ConfigMgr.sysList.index('sys_%s' % val)

                        enabledSyscall.append(ConfigMgr.sysList[nrSyscall])
                        sidx = SysMgr.syscallList.index(val)
                        SysMgr.syscallList[sidx] = nrSyscall
                    except SystemExit:
                        sys.exit(0)
                    except:
                        SysMgr.printErr(
                            "no %s syscall in %s ABI" % \
                            (val, SysMgr.arch))
                        sys.exit(0)

                if not enabledSyscall:
                    SysMgr.printInfo("enabled syscall list [ ALL ]")
                else:
                    SysMgr.printInfo(
                        "enabled syscall list [ %s ]" % \
                        ', '.join(enabledSyscall))

            elif option == 'm':
                try:
                    SysMgr.ttyEnable = True

                    if not value:
                        SysMgr.setTTYAuto()
                    else:
                        rows = cols = long(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(0)

            elif option == 'b' and \
                not SysMgr.isRecordMode():
                SysMgr.checkOptVal(option, value)
                try:
                    if value.isdigit():
                        osize = bsize = long(value) << 10
                    else:
                        osize = UtilMgr.convUnit2Size(value)
                        bsize = osize >> 10

                    if bsize >= 0:
                        SysMgr.bufferSize = str(bsize)

                        if bsize == 0:
                            SysMgr.printInfo(
                                "set buffer size to unlimited")
                        else:
                            SysMgr.printInfo(
                                "set buffer size to %s" %
                                    UtilMgr.convSize2Unit(osize))
                    else:
                        SysMgr.printErr((
                            "wrong value for buffer size, "
                            "input number bigger than 0") % option)
                        sys.exit(0)
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr((
                            "wrong value for buffer size, "
                            "input number in integer format") % option)
                    sys.exit(0)

            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(0)

            elif option == 'x':
                SysMgr.checkOptVal(option, value)
                service, ip, port = NetworkMgr.parseAddr(value)
                NetworkMgr.setServerNetwork(ip, port)

            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(0)

            # Ignore options #
            elif SysMgr.isValidOption(option):
                continue

            else:
                SysMgr.printErr(
                    "unrecognized option -%s for analysis" % option)
                sys.exit(0)



    @staticmethod
    def parseCommonOption(option, value):
        if value:
            value = value.strip()

        if option == 'f':
            SysMgr.forceEnable = True

        elif option == 'L':
            if not value:
                SysMgr.printErr(
                    "no input value with -%s option" % option)
                sys.exit(0)
            elif SysMgr.isDrawMode():
                SysMgr.layout = value
            elif not SysMgr.stdlog:
                if os.path.isdir(value):
                    value = os.path.join(value, 'guider.log')
                SysMgr.printInfo("use '%s' for log" % 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(0)

            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(0)

        elif option == 'Q':
            SysMgr.setStream()

        elif option == 'q':
            SysMgr.checkOptVal(option, value)
            if not SysMgr.environList:
                itemList = UtilMgr.splitString(value)
                SysMgr.environList = UtilMgr.convList2Dict(itemList)

        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(',')))

        elif option == 'A':
            SysMgr.checkOptVal(option, value)
            SysMgr.archOption = value
            SysMgr.setArch(value)

        elif option == 'W':
            SysMgr.waitEnable = True

        elif option == 'C':
            if not ConfigMgr.confData:
                if value:
                    SysMgr.confFileName = os.path.abspath(value)
                else:
                    SysMgr.confFileName = \
                        os.path.abspath(SysMgr.confFileName)

                # load configuration #
                ret = SysMgr.loadConfig(SysMgr.confFileName)
                if SysMgr.isDrawMode():
                    pass
                elif not ret:
                    sys.exit(0)

        elif option == 'E':
            SysMgr.cacheDirPath = value
            SysMgr.printInfo(
                "use %s as cache directory" % value)

        elif option == 'G':
            SysMgr.checkOptVal(option, value)
            itemList = UtilMgr.splitString(value)
            SysMgr.ignoreItemList = UtilMgr.cleanItem(itemList, union=True)
            SysMgr.printInfo(
                "applied ignore keyword [ %s ]" % \
                    ', '.join(SysMgr.ignoreItemList))

        elif option == 'u':
            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

        if 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 = str(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(0)
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(
                        "wrong value for buffer size, "
                        "input number in integer format")
                    sys.exit(0)

            elif option == 'Y':
                SysMgr.applyPriority(value)

            elif option == 'e':
                options = value
                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 'I' in options:
                    SysMgr.i2cEnable = 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 not SysMgr.isValidEnableOption(options):
                    SysMgr.printErr(
                        "unrecognized option '%s' to enable" % options)
                    sys.exit(0)

            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(0)

                SysMgr.printInfo(
                    "only specific threads [ %s ] are recorded" % \
                    ', '.join(SysMgr.filterGroup))

            elif option == 'D':
                SysMgr.depEnable = True

            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 objdump path" % SysMgr.objdumpPath)

            elif option == 'F':
                SysMgr.fileEnable = True

            elif option == 'B':
                # get output path #
                if not value:
                    value = SysMgr.cmdFileName

                # change output path #
                try:
                    if SysMgr.isWritable(value):
                        if os.path.isdir(value):
                            SysMgr.cmdEnable = \
                                '%s/%s' % (value, SysMgr.cmdFileName)
                        else:
                            SysMgr.cmdEnable = value
                    else:
                        raise Exception('not writable')
                except:
                    SysMgr.printErr(
                        "wrong value for command script path" % value)
                    sys.exit(0)

                # remove double slashs #
                SysMgr.cmdEnable = \
                    os.path.normpath(SysMgr.cmdEnable)

            elif option == 't':
                SysMgr.sysEnable = True
                SysMgr.syscallList = \
                    UtilMgr.cleanItem(value.split(','))
                enabledSyscall = []

                for val in SysMgr.syscallList:
                    try:
                        if val[0:4] == 'sys_':
                            nrSyscall = ConfigMgr.sysList.index(val)
                        else:
                            nrSyscall = \
                                ConfigMgr.sysList.index('sys_%s' % val)

                        enabledSyscall.append(
                            ConfigMgr.sysList[nrSyscall])
                        sidx = SysMgr.syscallList.index(val)
                        SysMgr.syscallList[sidx] = nrSyscall
                    except SystemExit:
                        sys.exit(0)
                    except:
                        SysMgr.printErr(
                            "no %s syscall in %s ABI" % \
                            (val, SysMgr.arch))
                        sys.exit(0)

                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(
                        "fail to recognize custom events")
                    sys.exit(0)

            elif option == 'd':
                options = value

                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 'u' in options:
                    SysMgr.userEnable = 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.generalInfoEnable = False

            # Ignore options #
            elif SysMgr.isValidOption(option):
                continue

            else:
                SysMgr.printErr(
                    "unrecognized option -%s for recording" % option)
                sys.exit(0)



    @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 = long(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 SysMgr.checkMode('rec') or \
            SysMgr.checkMode('funcrec') or \
            SysMgr.checkMode('filerec') or \
            SysMgr.checkMode('sysrec') or \
            SysMgr.checkMode('genrec'):
            return True
        else:
            return False



    @staticmethod
    def isHelpMode():
        if len(sys.argv) > 1 and sys.argv[1] == 'help':
            return True
        elif '-help' in sys.argv or \
            '--help' in sys.argv or \
            '-h' in 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] == 'kill' or \
            sys.argv[1] == 'send' or \
            sys.argv[1] == '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 SysMgr.checkMode('top') or \
            SysMgr.checkMode('ttop') or \
            SysMgr.checkMode('utop') or \
            SysMgr.checkMode('btop') or \
            SysMgr.checkMode('systop') or \
            SysMgr.checkMode('pytop') or \
            SysMgr.checkMode('ftop') or \
            SysMgr.checkMode('stacktop') or \
            SysMgr.checkMode('ptop') or \
            SysMgr.checkMode('mtop') or \
            SysMgr.checkMode('wtop') or \
            SysMgr.checkMode('rtop') or \
            SysMgr.checkMode('bgtop') or \
            SysMgr.checkMode('atop') or \
            SysMgr.checkMode('ctop') or \
            SysMgr.checkMode('ntop') or \
            SysMgr.checkMode('dlttop') or \
            SysMgr.checkMode('cgtop') or \
            SysMgr.checkMode('dbustop') or \
            SysMgr.checkMode('disktop'):
            return True
        else:
            return False



    @staticmethod
    def isTraceMode():
        if SysMgr.checkMode('strace') or \
            SysMgr.checkMode('utrace') or \
            SysMgr.checkMode('btrace') or \
            SysMgr.checkMode('remote') or \
            SysMgr.checkMode('leaktrace') or \
            SysMgr.checkMode('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()

        # LIST MODE #
        if SysMgr.checkMode('list'):
            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)

            waitFlag = SysMgr.waitEnable

            while 1:
                # send signal #
                if SysMgr.checkMode('tkill'):
                    SysMgr.sendSignalArgs(
                        argList, isThread=True, wait=waitFlag)
                else:
                    SysMgr.sendSignalArgs(argList, wait=waitFlag)

                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.cleanItem(argList)
            else:
                argList = None

            SysMgr.printLogo(big=True, onlyFile=True)

            TaskAnalyzer.doDiffReports(argList)

        # TOPSUM MODE #
        elif SysMgr.checkMode('topsum'):
            # remove option args #
            SysMgr.removeOptionArgs()

            # get file path #
            if SysMgr.hasMainArg():
                fname = SysMgr.getMainArg()
            else:
                fname = SysMgr.outFilePath

            SysMgr.printLogo(big=True, onlyFile=True)

            TaskAnalyzer.doSumReport(fname)

        # PAUSE MODE #
        elif SysMgr.checkMode('pause'):
            # get target list #
            if SysMgr.hasMainArg():
                targets = SysMgr.getMainArg().split(',')
                targets = UtilMgr.cleanItem(targets)
            else:
                targets = SysMgr.filterGroup

            if not targets:
                SysMgr.printErr(
                    "no input value for COMM or TID")
                sys.exit(0)

            # convert comm to pid #
            targetList = []
            sibling = SysMgr.groupProcEnable
            for item in targets:
                targetList += SysMgr.getPids(item, sibling=sibling)
            targetList = list(set(targetList))

            if not targetList:
                SysMgr.printErr(
                    "no task related to '%s'" % ', '.join(targets))
                sys.exit(0)

            Debugger.pauseThreads(targetList)

        # READELF MODE #
        elif SysMgr.checkMode('readelf'):
            SysMgr.printLogo(big=True, onlyFile=True)

            # get path #
            if SysMgr.hasMainArg():
                path = SysMgr.getMainArg()
            elif SysMgr.inputParam:
                path = SysMgr.inputParam
            else:
                SysMgr.printErr("no input value for path")
                sys.exit(0)

            # 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)
                    SysMgr.printPipe(jsonStr)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "fail 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()

        # PRINTDIR MODE #
        elif SysMgr.checkMode('printdir'):
            SysMgr.printLogo(big=True, onlyFile=True)

            # get start dir #
            if SysMgr.hasMainArg():
                root = SysMgr.getMainArg()
            elif SysMgr.inputParam:
                root = SysMgr.inputParam
            else:
                root = '.'

            # get depth #
            if not SysMgr.funcDepth:
                maxLevel = -1
            else:
                maxLevel = SysMgr.funcDepth

            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')

        # PRINTDBUSINFO MODE #
        elif SysMgr.checkMode('printdbusinfo'):
            SysMgr.printLogo(big=True, onlyFile=True)

            DbusMgr.runDbusSnooper(mode='printstat')

        # PRINTSUB MODE #
        elif SysMgr.checkMode('printsub'):
            SysMgr.printLogo(big=True, onlyFile=True)

            DbusMgr.runDbusSnooper(mode='signal')

        elif SysMgr.isPrintLogMode():
            # set console info #
            SysMgr.setStream()

            console = SysMgr.findOption('Q')

            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'):
                # to prevent segmentation fault from python3.8 #
                TaskAnalyzer(onlyInstance=True)

                DltAnalyzer.runDltReceiver(mode='print')

        # PRINTSIG MODE #
        elif SysMgr.checkMode('printsig'):
            SysMgr.printLogo(big=True, onlyFile=True)

            SysMgr.doPrintSig()

        # PAGE MODE #
        elif SysMgr.checkMode('mem'):
            SysMgr.printLogo(big=True, onlyFile=True)

            # check input #
            if SysMgr.hasMainArg():
                target = [SysMgr.getMainArg()]
            else:
                target = SysMgr.filterGroup

            PageAnalyzer.getPageInfo(
                target, SysMgr.inputParam)

        # LIMIT MODE #
        elif SysMgr.isLimitMode():
            # change priority for process #
            if not SysMgr.prio:
                SysMgr.setPriority(SysMgr.pid, 'C', -20)

            # get argument #
            if SysMgr.hasMainArg():
                filterGroup = SysMgr.getMainArg().split(',')
            else:
                filterGroup = SysMgr.filterGroup

            if SysMgr.checkMode('limitcpu'):
                limitInfo = SysMgr.getLimitCpuInfo(filterGroup)

                SysMgr.doLimitCpu(
                    limitInfo, SysMgr.processEnable)

        # PSTREE MODE #
        elif SysMgr.checkMode('pstree'):
            SysMgr.doPstree()

        # COMP MODE #
        elif SysMgr.checkMode('comp'):
            try:
                SysMgr.doCompress()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    'fail to compress', True)

        # DECOMP MODE #
        elif SysMgr.checkMode('decomp'):
            try:
                SysMgr.doDecompress()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    'fail 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()

        # EXEC MODE #
        elif SysMgr.checkMode('exec'):
            SysMgr.doExec()

        # REQUEST MODE #
        elif SysMgr.checkMode('req'):
            SysMgr.setStream()

            SysMgr.doRequest()

        # SETCPU MODE #
        elif SysMgr.checkMode('setcpu'):
            # remove option args #
            SysMgr.removeOptionArgs()

            SysMgr.doSetCpu()

        # SETSCHED MODE #
        elif SysMgr.checkMode('setsched'):
            SysMgr.doSetSched()

        # CONVERT MODE #
        elif SysMgr.checkMode('convert'):
            SysMgr.doConvert()

        # DRAWREQ MODE #
        elif SysMgr.checkMode('drawreq'):
            SysMgr.doDrawReq()

        # STRINGS MODE #
        elif SysMgr.checkMode('strings'):
            SysMgr.setStream(cut=False)

            SysMgr.doStrings()

        # DUMP MODE #
        elif SysMgr.checkMode('dump'):
            SysMgr.doDump()

        # STRACE MODE #
        elif SysMgr.checkMode('strace'):
            if SysMgr.findOption('l'):
                SysMgr.setStream()
                for idx, item in enumerate(ConfigMgr.sysList):
                    if item == 'sys_null':
                        continue
                    elif idx > 0 and idx % 3 == 0:
                        newline = True
                    else:
                        newline = False

                    SysMgr.printPipe(
                        "%3s) %s  " % (idx, item), 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')

        # 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()

        # PRINTNS MODE #
        elif SysMgr.checkMode('printns'):
            SysMgr.doPrintNs()

        # PRINTSVC MODE #
        elif SysMgr.checkMode('printsvc'):
            SysMgr.doPrintSvc()

        # PRINTINFO MODE #
        elif SysMgr.checkMode('printinfo'):
            SysMgr.doPrintInfo()

        # AFFINITY MODE #
        elif SysMgr.checkMode('setafnt'):
            SysMgr.doSetAffinity()

        # AFFINITY MODE #
        elif SysMgr.checkMode('getafnt'):
            SysMgr.doGetAffinity()

        # 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 SysMgr.checkMode('drawavg', True) or \
            SysMgr.checkMode('drawcpuavg', True) or \
            SysMgr.checkMode('drawmemavg', True) or \
            SysMgr.checkMode('drawvssavg', True) or \
            SysMgr.checkMode('drawrssavg', True):
            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 SysMgr.checkMode('drawcpu', True):
            return True
        elif SysMgr.checkMode('drawdelay', True):
            return True
        elif SysMgr.checkMode('drawflame', True):
            return True
        elif SysMgr.checkMode('drawmem', True):
            return True
        elif SysMgr.checkMode('drawvss', True):
            return True
        elif SysMgr.checkMode('drawrss', True):
            return True
        elif SysMgr.checkMode('drawleak', True):
            return True
        elif SysMgr.checkMode('drawio', True):
            return True
        elif SysMgr.checkMode('drawtime', True):
            return True
        elif SysMgr.isDrawAvgMode():
            return True
        else:
            SysMgr.drawMode = orig
            return False



    @staticmethod
    def isPrintLogMode():
        if SysMgr.checkMode('printsys') or \
            SysMgr.checkMode('printkmsg') or \
            SysMgr.checkMode('printjrl') or \
            SysMgr.checkMode('printdlt'):
            return True
        else:
            return False



    @staticmethod
    def checkPerfTopCond():
        if not SysMgr.isRoot():
            SysMgr.printErr(
                "fail to get root permission to use PMU")
            return False
        elif not os.path.isfile('%s/sys/kernel/perf_event_paranoid' % \
            SysMgr.procPath):
            SysMgr.printErr(
                "fail to use PMU, please check kernel config")
            return False
        else:
            return True



    @staticmethod
    def checkMemTopCond():
        if not SysMgr.isRoot():
            SysMgr.printErr(
                "fail to get root permission to analyze memory details")
            return False
        else:
            return True



    @staticmethod
    def checkBgTopCond():
        if SysMgr.outPath:
            return True

        logPath = '/var/log'
        tmpPath = '/tmp'

        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(
                "fail to get path to save output, use -o option")
            return False



    @staticmethod
    def checkRepTopCond(val=None):
        # check whether report option is already enabled #
        if SysMgr.reportEnable:
            return True

        if SysMgr.printStreamEnable:
            return True
        else:
            SysMgr.printEnable = False

        if not val:
            reportPath = SysMgr.getOption('j')
        else:
            reportPath = val

        # check report path #
        if not reportPath or not reportPath:
            tmpPath = '/tmp'
            reportPath = tmpPath

        # directory path #
        if os.path.isdir(reportPath) == False:
            upDirPos = reportPath.rfind('/')
            if upDirPos > 0 and \
                not os.path.isdir(reportPath[:upDirPos]):
                SysMgr.printErr(
                    "wrong path '%s' to report stats" % \
                    reportPath)
                return False
        # file path #
        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)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenErr(reportPath)
            sys.exit(0)

        SysMgr.reportEnable = True

        SysMgr.printInfo(
            "start writing JSON format report to %s" % reportPath)

        return True



    @staticmethod
    def checkWssTopCond():
        if not SysMgr.getOption('g'):
            SysMgr.printErr(
                "wrong option for wss monitoring, "
                "use also -g option to track memory working set")
            return False
        elif not SysMgr.isRoot():
            SysMgr.printErr(
                "fail to get root permission to clear refcnts")
            return False
        else:
            return True



    @staticmethod
    def checkDiskTopCond():
        procPath = SysMgr.procPath
        if not SysMgr.isRoot():
            SysMgr.printErr(
                "fail to get root permission to analyze block I/O")
            return False
        elif not os.path.isfile('%s/self/io' % procPath):
            SysMgr.printErr(
                "fail to use bio event, please check kernel config")
            return False
        else:
            return True



    @staticmethod
    def checkStackTopCond():
        if not SysMgr.isRoot():
            SysMgr.printErr(
                "fail to get root permission to sample stack")
            return False
        elif not os.path.isfile('%s/self/stack' % SysMgr.procPath):
            SysMgr.printErr(
                "fail to sample stack, please check kernel config")
            return False
        else:
            return True



    @staticmethod
    def convertCIDR(addr):
        addrList = []
        splitAddr = [addr[i:i+2] for i in range(0, len(addr), 2)]
        for num in reversed(splitAddr):
            addrList.append(str(long(num, base=16)))
        return '.'.join(addrList)



    @staticmethod
    def getSocketPathList(addrList):
        pathList = {}
        inodeIdx = ConfigMgr.UDS_ATTR.index('Inode')
        pathIdx = ConfigMgr.UDS_ATTR.index('Path')

        UDS_ATTR = SysMgr.getUdsList()
        for uds in UDS_ATTR:
            try:
                if uds[inodeIdx] in addrList:
                    pathList[uds[pathIdx]] = None
            except:
                pass

        return list(pathList.keys())



    @staticmethod
    def mountDebugfs(mp=None):
        if not mp:
            mp = SysMgr.debugfsPath

        # check root permission #
        if not SysMgr.isRoot():
            SysMgr.printErr(
                "fail to get root permission to mount debugfs")
            sys.exit(0)

        # mount debugfs #
        SysMgr.mountCmd =\
            "mount -t debugfs nodev %s" % mp
        os.system(SysMgr.mountCmd)

        SysMgr.mountPath = SysMgr.getDebugfsPath()
        if not SysMgr.mountPath:
            SysMgr.printErr(
                "fail to mount debugfs to trace events")
            sys.exit(0)



    @staticmethod
    def handleEventInput():
        # mount debug fs #
        SysMgr.mountPath = SysMgr.getDebugfsPath()
        if not SysMgr.mountPath:
            SysMgr.printWarn(
                "fail to get debugfs mount point", True)

        # get event #
        if SysMgr.hasMainArg():
            event = SysMgr.getMainArg()
        elif SysMgr.inputParam:
            event = SysMgr.inputParam
        else:
            event = None

        # convert pid #
        try:
            target = list(set(list(map(long, SysMgr.filterGroup))))
        except:
            SysMgr.printErr(
                "fail to get pid '%s'" % \
                    ', '.join(SysMgr.filterGroup), True)
            sys.exit(0)

        # oneshot #
        if event:
            SysMgr.writeEvent("EVENT_%s" % event)
            SysMgr.broadcastEvent(event, target)
            return

        while 1:
            SysMgr.printStat(
                "input event name... [ STOP(Ctrl+c) ]")

            try:
                event = sys.stdin.readline()
            except SystemExit:
                sys.exit(0)
            except:
                continue

            if not event.strip():
                SysMgr.writeEvent("EVENT_USER")
                SysMgr.broadcastEvent('EVENT', target)
            else:
                SysMgr.writeEvent("EVENT_%s" % event[:-1])
                SysMgr.broadcastEvent(event[:-1], target)



    @staticmethod
    def getSocketAddrList(addrList):
        portList = {}
        stIdx = ConfigMgr.UDP_ATTR.index('st')
        inodeIdx = ConfigMgr.UDP_ATTR.index('inode')
        addrIdx = ConfigMgr.UDP_ATTR.index('local_address')

        # get udp list #
        udpList = SysMgr.getUdpList()
        for udp in udpList:
            try:
                if udp[inodeIdx] in addrList:
                    ip, port = udp[addrIdx].split(':')

                    # convert ip address and port #
                    ip = SysMgr.convertCIDR(ip)

                    portList["UDP:%s:%s" % (ip, long(port, base=16))] = None
            except:
                pass

        # get tcp list #
        tcpList = SysMgr.getTcpList()
        for tcp in tcpList:
            try:
                if tcp[inodeIdx] in addrList:
                    ip, port = tcp[addrIdx].split(':')

                    # convert ip address and port #
                    ip = SysMgr.convertCIDR(ip)

                    try:
                        stat = '/%s' % \
                            ConfigMgr.TCP_STAT[long(tcp[stIdx], 16)]
                    except:
                        stat = ''

                    item = "TCP:%s:%s%s" % (ip, long(port, base=16), stat)
                    portList[item] = None
            except:
                pass

        return list(portList.keys())



    @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(
                        'fail 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(
                    "fail 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(
                "fail to find %s process" % name, True)

        return None



    @staticmethod
    def getProcPids(name):
        pidList = []
        myPid = str(SysMgr.pid)

        pids = os.listdir(SysMgr.procPath)
        for pid in pids:
            if myPid == pid:
                continue

            try:
                long(pid)
            except:
                continue

            # check comm #
            comm = SysMgr.getComm(pid)
            if comm and comm.startswith(name):
                pidList.append(long(pid))

        return pidList



    @staticmethod
    def getRuntime(isSec=False):
        uptime = long(SysMgr.getUptime())
        runtime = uptime - long(SysMgr.startRunTime)
        if isSec:
            return runtime
        return UtilMgr.convTime(runtime)



    @staticmethod
    def getUptime():
        try:
            SysMgr.uptimeFd.seek(0)
            return float(SysMgr.uptimeFd.readlines()[0].split()[0])
        except:
            try:
                uptimePath = "%s/%s" % (SysMgr.procPath, 'uptime')
                SysMgr.uptimeFd = open(uptimePath, 'r')
                return float(SysMgr.uptimeFd.readlines()[0].split()[0])
            except:
                SysMgr.printOpenWarn(uptimePath)
                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

        if not pids:
            # get pid list of Guider processes #
            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 #
        SysMgr.updateUptime()

        # 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

            for addr in addrs:
                try:
                    attr, ip, port = addr.split(':')
                except:
                    SysMgr.printWarn(
                        "failed to use %s as remote address" % (addr))
                    continue

                networkObject = NetworkMgr('client', ip, long(port))
                ip = networkObject.ip
                port = networkObject.port

                if not networkObject.ip or not networkObject.port:
                    SysMgr.printWarn(
                        "failed to use %s:%s as remote address" % (ip, port))
                    continue

                for item in event:
                    try:
                        networkObject.request = item
                        networkObject.send('%s@%s' % (item, SysMgr.uptime))
                        SysMgr.printInfo(
                            "sent event '%s' to %s:%s address of %s process" % \
                                (item, ip, port, pid))
                    except:
                        SysMgr.printWarn((
                            "failed to send event '%s' "
                            "to %s:%s address of %s process") % \
                                (item, ip, port, pid))

        return pids



    @staticmethod
    def updateBgProcs(cache=False):
        if SysMgr.bgProcList and cache:
            return

        SysMgr.bgProcList = SysMgr.getBgProcList()



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

        SysMgr.updateBgProcs()

        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):
                    if not line:
                        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(cache=False):
        SysMgr.updateBgProcs(cache)

        return SysMgr.bgProcList.count('\n')



    @staticmethod
    def getBgProcString():
        if not SysMgr.bgProcList or \
            not SysMgr.bgProcList:
            return ''

        procList = SysMgr.bgProcList

        bgStr = '\n[Running Process] [TOTAL: %s]\n' % procList.count('\n')
        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)
            SysMgr.printPipe(jsonResult)
            return

        SysMgr.updateBgProcs(cache)

        procList = SysMgr.bgProcList

        if procList == '':
            SysMgr.printPipe(
                "\nno running process in the background\n", pager=False)
        else:
            SysMgr.printPipe(SysMgr.getBgProcString(), pager=False)



    @staticmethod
    def getPids(
        name, isThread=True, sibling=False,
        main=False, inc=False, cache=False):

        pidList = []

        # tid #
        if UtilMgr.isNumber(name) and \
            os.path.isdir('%s/%s' % (SysMgr.procPath, name)):
            if sibling:
                path = '%s/%s/task' % (SysMgr.procPath, name)
                pids = os.listdir(path)
                for pid in pids:
                    if pid.isdigit():
                        pidList.append(pid)
                return pidList
            elif main:
                return list(set([name, SysMgr.getTgid(name)]))
            else:
                return [name]

        # comm #
        pids = os.listdir(SysMgr.procPath)
        for pid in pids:
            if not pid.isdigit():
                continue

            # process #
            if not isThread:
                # get comm #
                comm = SysMgr.getComm(pid, cache)
                if (not inc and comm == name) or \
                    (inc and name in comm):
                    pidList.append(pid)
                continue

            # thread #
            try:
                threadPath = "%s/%s/task" % (SysMgr.procPath, pid)
                tids = os.listdir(threadPath)
            except:
                continue

            for tid in tids:
                if not tid.isdigit():
                    continue

                # get comm #
                comm = SysMgr.getComm(tid)
                if (not inc and comm != name) or \
                    (inc and not name in comm):
                    continue

                # include all siblings #
                if sibling:
                    pidList += tids
                    break

                # include the main thread #
                if main:
                    pidList.append(pid)

                # include a thread #
                pidList.append(tid)

        return list(set(pidList))



    @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 #
        SysMgr.updateUptime()

        # get my comm #
        myComm = SysMgr.getComm(SysMgr.pid)

        # get my cmdline #
        myCmdline = SysMgr.getCmdline(SysMgr.pid, True)

        pids = os.listdir(SysMgr.procPath)
        for pid in pids:
            if myPid == pid or not pid.isdigit():
                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 = '?'

            # comm #
            try:
                statPath = "%s/%s/stat" % (SysMgr.procPath, pid)
                with open(statPath, 'r') as fd:
                    statList = fd.read().split()

                statList = SysMgr.mergeCommStat(statList, commIdx)

                # runtime #
                procStart = \
                    float(statList[gstatList.index("STARTTIME")]) / 100
                runtime = long(SysMgr.uptime - procStart)

                # ppid #
                ppid = statList[gstatList.index("PPID")]

                # state #
                try:
                    state = ConfigMgr.PROC_STAT_TYPE[\
                        statList[gstatList.index("STATE")]]
                except:
                    state = 'N/A'

                # rss #
                rss = long(statList[gstatList.index("RSS")])
                rss = UtilMgr.convSize2Unit(rss << 12, True)
            except:
                pass

            # runtime #
            if runtime != '?':
                runtime = UtilMgr.convTime(runtime)

            # socket #
            try:
                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] = list()

                    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 len(netList) > 0:
                    network = '(%s)' % netList[:-1]
                else:
                    network = ''
            except:
                network = ''

            # cmdline #
            try:
                cmdline = SysMgr.getCmdline(pid)
            except:
                cmdline = '?'

            # build #
            if isJson:
                printDict[pid] = {
                    'comm': comm,
                    'ppid': ppid,
                    'state': state,
                    'rss': rss,
                    'runtime': runtime,
                    'cmdline': cmdline,
                    'network': network
                }
            else:
                printBuf = '%s%7s %7s %7s %8s %5s %12s %s %s\n' % \
                    (printBuf, pid, ppid, comm,
                        state, rss, runtime, cmdline, network)

        if isJson:
            return printDict
        else:
            return printBuf



    @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

        # set default message #
        if not msg:
            if SysMgr.idList:
                msg = "input a task index... ( Help / Quit)"
            else:
                msg = "input a command... ( Help / Quit )"

        # wait for user input #
        try:
            SysMgr.inWaitStatus = True

            if newline:
                suffix = '\n'
            else:
                suffix = ''

            # there was user input #
            if selectObj.select(
                [sys.stdin], [], [], 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 IOError:
            SysMgr.printWarn("fail to read user input", reason=True)
            sys.stdin = None
        except:
            SysMgr.printWarn("fail to read user input", reason=True)
        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 -stop 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

        # hotkey #
        if SysMgr.idList and ulist[0].isdigit():
            try:
                pid = SysMgr.idList[long(ulist[0])]
            except:
                return

            SysMgr.executeCommand(pid=pid)
            return

        # help #
        if ulist[0].upper() == 'HELP' or \
            ulist[0].upper() == 'H':
            _printHelp()
        # kill #
        elif ulist[0].upper() == 'KILL' or \
            ulist[0] == 'k':
            if len(ulist) > 1:
                SysMgr.sendSignalArgs(ulist[1:])
            else:
                _printHelp()
        # sched #
        elif ulist[0].upper() == 'SCHED' or \
            ulist[0] == 's':
            if len(ulist) > 1:
                SysMgr.applyPriority((' '.join(ulist[1:])))
            else:
                _printHelp()
        # sort #
        elif ulist[0].upper() == 'SORT' or \
            ulist[0] == 'S':
            if len(ulist) > 1:
                SysMgr.setSortValue(ulist[1])
            else:
                _printHelp()
        # affinity #
        elif ulist[0].upper() == 'AFFINITY' or \
            ulist[0] == 'a':
            if len(ulist) > 2:
                pids = (' '.join(ulist[2:])).split(',')
                pids = SysMgr.convPidList(pids, isThread=True)
                SysMgr.setAffinity(ulist[1], pids)
            else:
                _printHelp()
        # filter #
        elif ulist[0].upper() == 'FILTER' or ulist[0] == '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 ulist[0].upper() == 'OPTION' or \
            ulist[0] == 'o':
            if len(ulist) > 1:
                SysMgr.parseAnalOption(uinput[1:].strip())
            else:
                _printHelp()
        # run #
        elif ulist[0].upper() == 'RUN' or \
            ulist[0] == '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(0)

                # ignore signals and wait for child #
                SysMgr.setIgnoreSignal()
                os.wait()
                SysMgr.setNormalSignal()
            else:
                _printHelp()
        # quit #
        elif ulist[0].upper() == 'QUIT' or \
            ulist[0].upper() == '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(0)

        limitList = {}
        try:
            for item in limitInfo:
                (tid,per) = item.split(':')

                # get id for tasks #
                if tid.isdigit():
                    limitList[tid] = long(per)
                else:
                    tidList = SysMgr.getPids(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(0)

        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 = SysMgr.splitOptionString(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(
                        "fail to launch %s" % __module__, reason=True)
            # launch command #
            else:
                ret = SysMgr.createProcess(cmd.split())

            # check return #
            if ret < 0:
                continue

            # ignore signals and wait for child #
            SysMgr.setIgnoreSignal()
            os.wait()
            SysMgr.setNormalSignal()



    @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)
            if not 'ENV' in SysMgr.environList and \
                not 'ENVFILE' in SysMgr.environList:
                return myEnv

            # parse new variables #
            if 'ENV' in SysMgr.environList:
                envList = SysMgr.environList['ENV']
            else:
                envList = []
            applyList(myEnv, envList)

            # parse new variables from file #
            if 'ENVFILE' in SysMgr.environList:
                envFileList = SysMgr.environList['ENVFILE']
            else:
                envFileList = []

            # read variables from files #
            for fname in envFileList:
                try:
                    with open(fname, 'r') as fd:
                        envList = fd.readlines()
                        applyList(myEnv, envList)
                except:
                    SysMgr.printErr(
                        'fail to parse environment variable from %s' % \
                            fname, True)
                    sys.exit(0)

            return myEnv
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                'fail to parse enviroment variable', 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(
                "fail to execute '%s'" % ' '.join(cmd), True)
            return -1



    @staticmethod
    def initEnvironment():
        # 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 io #
        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 comm #
        SysMgr.setComm(__module__)
        SysMgr.comm = SysMgr.getComm(SysMgr.pid)

        # set arch #
        SysMgr.setArch(SysMgr.getArch())

        # set default signal #
        SysMgr.setSimpleSignal()

        # reset terminal #
        SysMgr.resetTTY()

        # shrink heap #
        SysMgr.shrinkHeap()



    @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 = '%s%s' % (output, line)



    @staticmethod
    def launchGuider(
        cmd, log=False, mute=False, pipe=True, stderr=False,
        wait=False, stream=True, logo=True):
        '''
        - desc: launch a new Guider process as a child
        - pros: save memory such as ELF caches
        - pros: control Guider functions such as logo, stdio
        '''

        # 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 child temrination #
            if wait:
                SysMgr.waitChild(pid)
                return pid

            if pipe:
                return (pid, rdFd)
            else:
                return pid

        # child #
        elif pid == 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()
            SysMgr.inputFile = None
            SysMgr.outPath = None
            SysMgr.printFd = None
            SysMgr.printEnable = True
            SysMgr.encodeEnable = False
            SysMgr.reportEnable = SysMgr.jsonEnable = False

            # inherit enable and disable option value #
            disOptVal = SysMgr.getOption('d')
            enOptVal = SysMgr.getOption('e')
            if disOptVal or enOptVal:
                applyDisable = False
                applyEnable = False

                # append option values #
                for idx, val in enumerate(cmd):
                    if val.startswith('-d'):
                        cmd[idx] = val + disOptVal
                        applyDisable = True
                    elif val.startswith('-e'):
                        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()

            # initialize variables #
            SysMgr.parsedAnalOption = False
            SysMgr.optionList = []
            ConfigMgr.confData = {}
            SysMgr.thresholdData = {}
            SysMgr.procBuffer = []
            SysMgr.clearPrint()
            SysMgr.groupProcEnable = False

            # launch Guider command #
            main(cmd)

            sys.exit(0)

        # error #
        else:
            SysMgr.printErr(
                "fail 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(
                "fail to execute %s because of fork failure" % cmd)
            return -1



    @staticmethod
    def waitChild(pid=None, hang=True):
        # wait for all childs #
        if not pid:
            while 1:
                try:
                    os.waitpid(-1, 0)
                except:
                    pass

                if SysMgr.condExit:
                    break

                # check childs #
                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(
                "fail to wait %s task" % pid, reason=True)



    @staticmethod
    def spawnProcess(func, args, cnt=1, wait=True):
        multiprocessing = SysMgr.getPkg('multiprocessing')
        plist = []
        for seq in range(0, cnt):
            try:
                p = multiprocessing.Process(target=func, args=args)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    'fail to create a new process', reason=True)
                continue
            p.start()
            plist.append(p)

        if wait:
            for p in plist:
                p.join()



    @staticmethod
    def createProcess(
        cmd=None, isDaemon=False, mute=False, chPgid=False, chMid=False):
        # flush print buffer before fork #
        SysMgr.flushAllForPrint()

        # create a new process #
        pid = os.fork()

        # parent #
        if pid > 0:
            if not isDaemon:
                SysMgr.childList[pid] = True

            return pid
        # child #
        elif pid == 0:
            # update parent PID #
            SysMgr.parentPid = SysMgr.pid

            # initialize child list #
            SysMgr.clearChildList()

            if chPgid:
                os.setpgid(0, 0)

            # close fd for output #
            try:
                SysMgr.printFd.close()
            except SystemExit:
                sys.exit(0)
            except:
                pass
            finally:
                SysMgr.printFd = None

            # Guider #
            if not cmd:
                # update master pid #
                if chMid:
                    SysMgr.masterPid = SysMgr.pid

                # update pid #
                SysMgr.fileSuffix = SysMgr.pid = os.getpid()

                if mute:
                    SysMgr.closeStdFd(stderr=False)

                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(
                "fail to create process")
            return -1



    @staticmethod
    def closeStdFd(stdin=False, stdout=True, stderr=True):
        if not SysMgr.nullFd:
            SysMgr.nullFd = open(SysMgr.nullPath, 'w')

        # get null fd #
        nullFd = SysMgr.nullFd.fileno()

        # redirect stds to null #
        if stdin:
            os.dup2(nullFd, sys.stdin.fileno())
        if stdout:
            os.dup2(nullFd, sys.stdout.fileno())
        if stderr:
            os.dup2(nullFd, sys.stderr.fileno())



    @staticmethod
    def resetFileTable(mute=True, closeFd=True):
        # redirect stdout and stderr to null #
        if mute:
            try:
                SysMgr.closeStdFd(stderr=False)
            except SystemExit:
                sys.exit(0)
            except:
                pass

        # close all fds without standard #
        if closeFd:
            try:
                path = '%s/self/fd' % SysMgr.procPath
                fdList = os.listdir(path)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "fail to read file descriptors in %s" % path, reason=True)
                return

            for fd in fdList:
                try:
                    fd = long(fd)
                    if fd > 2:
                        os.close(fd)
                except SystemExit:
                    sys.exit(0)
                except:
                    pass



    @staticmethod
    def runBackgroundMode():
        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:
            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:
            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:
            return

        signal.signal(signal.SIGPIPE, SysMgr.exitHandler)



    @staticmethod
    def setCommonSignal():
        if not SysMgr.isLinux:
            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:
            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 setNormalSignal():
        if not SysMgr.isLinux:
            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 = {}

        def _sendErrMsg(netObj, message):
            message = 'ERROR|%s:%s:%s' % \
                (message, netObj.ip, netObj.port)
            netObj.send(message)

        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

            # verify path #
            targetPath = src
            if not os.path.isfile(targetPath):
                SysMgr.printWarn(
                    'failed to find %s to transfer' % targetPath, True)
                _sendErrMsg(netObj, "wrong path '%s'" % targetPath)
                return

            # response from command request #
            netObj.send(response)

            remotePath = des
            addr = '%s:%s' % (netObj.ip, netObj.port)

            # transfer file #
            try:
                # send file size #
                stat = os.stat(targetPath)
                st_size = '%s' % stat.st_size
                netObj.send(UtilMgr.encodeStr(st_size))

                # read for ACK #
                while 1:
                    ret = netObj.recv(3)
                    if ret is None:
                        continue
                    elif ret is False:
                        sys.exit(0)
                    else:
                        break

                # send file #
                with open(targetPath, 'rb') as fd:
                    buf = fd.read(netObj.sendSize)
                    while (buf):
                        netObj.send(buf)
                        buf = fd.read(netObj.sendSize)

                SysMgr.printInfo(
                    "uploaded %s [%s] to %s:%s successfully" % \
                        (targetPath, UtilMgr.getFileSize(targetPath),
                            addr, remotePath))
            except:
                SysMgr.printErr(
                    "fail to upload %s to %s in %s" % \
                    (targetPath, remotePath, addr), True)
            finally:
                netObj.close()

        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 = 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)

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

            # get connection info #
            addr = '%s:%s' % (netObj.ip, netObj.port)

            # receive file #
            try:
                curSize = long(0)
                totalSize = None
                origPath = src
                targetPath = des

                # receive file size #
                while 1:
                    size = netObj.recv(netObj.recvSize)
                    if not size:
                        continue
                    else:
                        totalSize = long(size.decode())
                        netObj.send('ACK')
                        break

                # receive file #
                with open(targetPath, 'wb') as fd:
                    while 1:
                        [read, write, error] = \
                            selectObj.select([netObj.socket], [], [], 3)

                        buf = netObj.recv(netObj.recvSize)
                        if buf:
                            fd.write(buf)
                            curSize += len(buf)
                        else:
                            break

                        #UtilMgr.printProgress(curSize, totalSize)

                SysMgr.printInfo(
                    "downloaded %s [%s] from %s:%s successfully" % \
                    (targetPath, UtilMgr.getFileSize(targetPath),
                        addr, origPath))
            except:
                SysMgr.printErr(
                    'fail to download %s from %s in %s' % \
                        (origPath, targetPath, addr), True)
            finally:
                netObj.close()

        def _updateNodeList(ret=False):
            for addr in list(nodeList.keys()):
                ret = NetworkMgr.requestPing(addr, verb=False)
                if not ret:
                    try:
                        nodeList[addr]['sock'].close()
                    except:
                        pass
                    finally:
                        nodeList.pop(addr, None)

            # print node list #
            idx = 0
            current = time.time()
            listStr = '[Service Node List]\n%s\n' % twoLine
            listStr += '{0:^5} {1:^25} {2:^10}\n{3:1}\n'.format(
                'Idx', 'Addr', 'Time', oneLine)
            for addr, value in sorted(
                nodeList.items(), key=lambda e:e[1]['time']):
                diff = current - value['time']
                listStr += '[{0:>3}] {1:>25} {2:>10}\n'.format(
                    idx, addr, UtilMgr.convTime(diff))
                idx += 1
            if nodeList:
                listStr += '%s\n' % oneLine
            else:
                listStr += '\tNone\n%s\n' % oneLine
            SysMgr.printWarn(listStr, True)

            if ret:
                return listStr

        def _onNew(connObj, value, response):
            try:
                # reply message #
                connObj.send('PONG')

                # register node info #
                if not value in nodeList or \
                    nodeList[value]['sock'] != connObj:
                    nodeList[value] = \
                        {'sock': connObj, 'time': time.time()}

                SysMgr.printInfo(
                    "registered the service node(%s) successfully" %  value)

                # update service node list #
                _updateNodeList()
            except:
                SysMgr.printWarn(
                    'fail to register the service node(%s)' % value,
                    reason=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 io buffer size #
                if 'READCHUNK' in SysMgr.environList:
                    try:
                        readChunkSize = \
                            long(SysMgr.environList['READCHUNK'][0])
                    except:
                        pass
                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(
                    "fail to execute '%s' from %s" % (value, addr), True)
            finally:
                try:
                    connObj.socket.shutdown(socket.SHUT_RDWR)
                    connObj.close()

                    # send TERM signal first #
                    os.killpg(procObj.pid, signal.SIGINT)

                    time.sleep(SysMgr.waitDelay)

                    # send KILL signal #
                    os.killpg(procObj.pid, signal.SIGKILL)
                except:
                    pass

        def _onBroadcast(connObj, value, response):
            cmd = 'run:' + value

            # reply message #
            if nodeList:
                # send message packet #
                connObj.send(
                    'MSG:"%s" is executed by %s node' % \
                        (cmd, len(nodeList)))

                '''
                receive an ACK packet
                to prevent receiving two packets at once
                '''
                connObj.recv()

                # send reply  packet for command #
                connObj.send('run|%s' % value)
            else:
                connObj.send('NO_SERV_NODE')
                return

            # execute remote commands #
            for addr in list(nodeList.keys()):
                # create worker process #
                pid = SysMgr.createProcess()
                if pid > 0:
                    continue

                # execute a command from a remote node #
                try:
                    SysMgr.printInfo(
                        "execute '%s' at %s for %s:%s" % \
                            (cmd, addr, connObj.ip, connObj.port))

                    # disable log #
                    SysMgr.logEnable = False

                    rcmd = '%s|%s' % (addr, cmd)
                    SysMgr.runClientMode(rcmd, connObj)
                except SystemExit:
                    pass
                except:
                    SysMgr.logEnable = True
                    SysMgr.printErr(
                        "fail 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:
                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 = NetworkMgr.setRemoteServer(raddr, tcp=True)
            errMsg = None

            while 1:
                try:
                    # create a new socket for TCP #
                    if not cliObj.socket:
                        cliObj = NetworkMgr.setRemoteServer(raddr, tcp=True)

                    SysMgr.printWarn(
                        'try to connect to the agent node(%s)' % raddr)

                    # connect to an agent node #
                    cliObj.connect()
                    cliObj.connected = True
                    errMsg = None
                    SysMgr.printInfo(
                        'connected to the agent node(%s)' % raddr)

                    # register to another server #
                    pipe = NetworkMgr.getCmdPipe(cliObj, 'new:%s' % caddr)

                    # monitor connection #
                    cliObj.recv()
                except SystemExit:
                    sys.exit(0)
                except:
                    # print error message #
                    curErrMsg = SysMgr.getErrMsg()
                    if errMsg != curErrMsg:
                        SysMgr.printErr((
                            'fail to keep connection with the agent node '
                            'to %s') % raddr, True)
                        SysMgr.printInfo(
                            'start trying to connect to the agent node(%s)' % \
                                raddr)

                    # update latest error message #
                    errMsg = curErrMsg

                    # close invalid socket #
                    if cliObj.connected:
                        cliObj.close()

                    time.sleep(1)

        def _handleConn(connObj, connMan):
            # 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(
                            "fail to get address of client from message")
                        return False

                SysMgr.printInfo(
                    "received 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 = {
                'DOWNLOAD': _onDownload,
                'UPLOAD': _onUpload,
                'RUN': _onRun,
                'BROADCAST': _onBroadcast,
                'NEW': _onNew,
                'PING': _onPing,
                'LIST': _onList,
            }

            # check request type #
            if not request in requestList:
                SysMgr.printWarn(
                    "fail to recognize the request '%s'" % message, True)

                _sendErrMsg(connObj, "no support the request '%s'" % message)

                return False
            elif request == 'NEW':
                requestList[request](connObj, value, None)
                return False
            elif request == 'BROADCAST':
                # update service node list #
                _updateNodeList()

            # build response data #
            response = '%s|%s' % (request, value)

            # create worker process #
            pid = SysMgr.createProcess()
            if pid > 0:
                return True

            # close listen socket of parent #
            connMan.close()

            before = time.time()

            # handle request #
            requestList[request](connObj, value, response)

            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")

        # 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 anoter 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 %s(%s) as a server" % \
                (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(
                'fail to listen to prepare for connection', True)
            sys.exit(0)

        # run mainloop #
        while 1:
            # accept #
            try:
                sock, addr = connMan.accept()
            except SystemExit:
                sys.exit(0)
            except socket.timeout:
                continue
            except:
                SysMgr.printWarn(
                    'fail to accept to prepare for connection', reason=True)
                continue

            SysMgr.printInfo(
                "connected to the 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):
                connObj.close()
                SysMgr.printBgProcs()

        sys.exit(0)



    @staticmethod
    def runClientMode(cmds=None, writer=None):
        def _printMenu():
            sys.stdout.write(
                '\n<Command List>\n'
                '- DOWNLOAD:RemotePath@LocalPath\n'
                '- UPLOAD:LocalPath@RemotePath\n'
                '- RUN:Command\n'
                '- BROADCAST:Command\n'
                '- PING\n'
                '- LIST\n'
                '- HISTORY\n'
                '- QUIT\n'
                '\n'
            )

        def _doPing(uinput):
            # get addrs from string #
            cmd = 'ping'
            addrs = uinput.strip(cmd).strip(cmd.upper())
            if addrs and not addrs[0].isdigit():
                addrs = addrs[1:]

            # classify IP and PORT #
            if addrs:
                service, ip, port = NetworkMgr.parseAddr(addrs)
                if service == ip == port == None:
                    SysMgr.printErr(
                        "fail to recognize command %s" % uinput, True)
                    return
                else:
                    NetworkMgr.setRemoteServer(addrs, tcp=True)

            ret = NetworkMgr.requestPing()
            if ret:
                SysMgr.printInfo('server is alive')

        def _printHistory(hlist):
            print('\n<History>')
            if hlist:
                for idx, cmd in enumerate(hlist):
                    print('[%0d] %s' % (idx, cmd))
                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 == 'H':
                uinput = 'history'
            elif uinputUpper == 'P':
                uinput = 'ping'
            elif uinputUpper == 'L':
                uinput = 'list'
            elif uinputUpper == 'Q':
                uinput = 'quit'

            return uinput

        def _execUserCmd(uinput, addr=None, retPipe=False):
            def _unsetAlarm():
                if not SysMgr.isLinux:
                    return
                signal.signal(signal.SIGALRM, SysMgr.defaultHandler)

            def _setAlarm():
                if not SysMgr.isLinux:
                    return

                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

            # launch remote command #
            pipe = NetworkMgr.execRemoteCmd(uinput, addr)
            if not pipe:
                if addr:
                    addrstr = ' at %s' % addr
                else:
                    addrstr = ''
                SysMgr.printErr(
                    "fail 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 SysMgr.isLinux:
                        pass
                    else:
                        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.getMainArg().split(',')
            cmdList = UtilMgr.cleanItem(cmdList, False)
        elif SysMgr.customCmd:
            cmdList = SysMgr.customCmd
        else:
            cmdList = []

        # set environment for parallel commands #
        if cmdList:
            SysMgr.setDefaultSignal()

            selectObj = SysMgr.getPkg('select')

            if not SysMgr.ttyEnable:
                SysMgr.setTTYAuto(True)

            # 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' % (time.time()-start))
                    sys.exit(0)
                break

            try:
                # set fds #
                listenFds = [ item for item in cmdPipeList.keys() ]

                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(
                    "fail to handle multiple commands", reason=True)

        # run mainloop for user interaction #
        hlist = list()
        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 getNrCore():
        if SysMgr.nrCore > 0:
            return SysMgr.nrCore

        try:
            cpuBuf = None
            SysMgr.statFd.seek(0)
            cpuBuf = SysMgr.statFd.readlines()
        except SystemExit:
            sys.exit(0)
        except:
            try:
                cpuPath = "%s/stat" % SysMgr.procPath
                SysMgr.statFd = open(cpuPath, 'r')
                cpuBuf = SysMgr.statFd.readlines()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenWarn(cpuPath)

        nrCore = long(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 grid #
                xticks(fontsize=4)
                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, list())
                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()
                xtickLabel = list(map(long, xtickLabel))
                xtickLabel[-1] = 'Time'
                ax.set_xticks(ax.get_xticks())
                ax.set_xticklabels(xtickLabel)
            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 range(-1, 2):
                    brange.append(start + idx/10)
                ax.bar(brange, data, width=width,
                    edgecolor='white', label=req[:maxLabelLen])

                # draw text for stat #
                for idx, value in enumerate(data):
                    text(start + (idx-1)/10, value, '%.3f' % value,
                        color='black', fontweight='bold', fontsize=2)

                # draw text for request #
                text(start-1/2, maxval/2, req[:maxLabelLen],
                    color='black', fontsize=3, rotation=35)

                start += 1

            # set ticks #
            try:
                xtickLabel = ax.get_xticks().tolist()
                xtickLabel = list(map(long, xtickLabel))
                xtickLabel = list(range(-1, len(totalStats)+1))
                ax.set_xticks(xtickLabel)
                xtickLabel[0] = ''
                xtickLabel[-1] = 'Req'
                for idx in range(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(
                    "fail to read '%s'" % path, reason=True)
                sys.exit(0)

            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.lstrip('Task:').strip().rstrip(']')
                    startPos = idx+4
                    break

            # check start pos #
            if startPos == -1:
                SysMgr.printErr(
                    "fail to recognize '%s'" % path)
                sys.exit(0)

            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)

                if SysMgr.filterGroup:
                    if not UtilMgr.isValidStr(req):
                        continue

                reqtimeList = []
                restimeList = []
                timeList = times.split(',')
                for item in timeList:
                    reqtime, restime = item.split('/')
                    reqtimeList.append(float(reqtime))
                    restimeList.append(float(restime))

                # initialize lists #
                reqid = '%s_%s' % (task, req)
                resTable.setdefault(reqid, dict())
                resTable[reqid].setdefault('reqtime', list())
                resTable[reqid].setdefault('restime', list())

                resTable[reqid]['reqtime'] += reqtimeList
                resTable[reqid]['restime'] += restimeList

            return resTable

        # initialize environment for drawing #
        TaskAnalyzer.initDrawEnv()

        # get argument #
        if SysMgr.hasMainArg():
            inputParam = SysMgr.getMainArg(True).split(',')
        elif SysMgr.inputParam:
            inputParam = UtilMgr.convPath(SysMgr.inputParam)
        else:
            inputParam = [SysMgr.outFilePath]

        # get response time from file #
        stats = {}
        for path in inputParam:
            try:
                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(
                    "fail to get stats from '%s'" % path, reason=True)
                sys.exit(0)

        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(0)

        # check file #
        if not os.path.isfile(value):
            SysMgr.printErr(
                "wrong path '%s' for converting" % value)
            sys.exit(0)

        # 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(
                "fail to read data from %s" % value)
            sys.exit(0)

        # 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(
                "fail to find CPU node for governor")
            sys.exit(0)

        # get argument #
        if SysMgr.hasMainArg():
            filterGroup = SysMgr.getMainArg().split(',')
        elif SysMgr.filterGroup:
            filterGroup = SysMgr.filterGroup
        else:
            SysMgr.printErr("no input for core info")
            sys.exit(0)

        # 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 \
                not vals[1].isdigit():
                SysMgr.printErr(
                ("wrong value to set CPU clock, "
                "input in the format CORE:CLOCK(HZ){:GOVERNOR}"))
                sys.exit(0)

            targetlist.append(vals)

        # get available CPU list #
        cpulist = {}
        for f in 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] = dict()

            # 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

            if not core:
                cpuRange = list(cpulist.keys())
            else:
                cpuRange = [core]

            # check support #
            if not core:
                pass
            elif not core in cpulist:
                SysMgr.printErr((
                    "fail to set CPU(%s) clock because "
                    "it doesn't support governor") % core)
                sys.exit(0)
            # check available clock #
            elif ('avail' in cpulist[core] 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((
                    "fail to set CPU(%s) clock because it only supports \n\t"
                    "-clock: [%s]\n\t-governor: [%s]") % \
                        (core, avail, governors))
                sys.exit(0)

            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

                # set clock range #
                try:
                    minres = maxres = govres = False

                    if 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(
                        "fail to set %s of CPU(%s)" % (res, core), True)
                    sys.exit(0)

                # 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 = ''

                SysMgr.printInfo(
                    "set CPU(%s)'s clock to %shz in [%s] successfuly %s" %
                        (core, UtilMgr.convNum(clock),
                            curgovernor, affectstring))



    @staticmethod
    def doSetSched():
        isProcess = False
        SysMgr.warnEnable = True

        # get argument #
        if SysMgr.hasMainArg(dash=True):
            value = SysMgr.getMainArg().split(',')
        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(0)

        value = ','.join(value)

        while 1:
            SysMgr.applyPriority(value)

            if SysMgr.intervalEnable:
                time.sleep(SysMgr.intervalEnable)
            else:
                break



    @staticmethod
    def doPrintEnv():
        SysMgr.printLogo(big=True, onlyFile=True)

        SysMgr.checkRootPerm()

        # get argument #
        if SysMgr.hasMainArg():
            filterGroup = SysMgr.getMainArg().split(',')
        elif SysMgr.filterGroup:
            filterGroup = SysMgr.filterGroup
        else:
            filterGroup = [str(SysMgr.pid)]

        pids = SysMgr.convPidList(filterGroup, exceptMe=True)
        if not pids:
            SysMgr.printErr("fail to find %s process" % \
                ', '.join(filterGroup))
            sys.exit(0)

        # print empty for initialization #
        SysMgr.printPipe()
        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[ %s(%s) ] < %s >\n%s\n' % \
                    (comm, pid, cmdline, oneLine[:lenLine]))

            # filter variables #
            if filters:
                filteredList = []
                for env in envs:
                    if UtilMgr.isValidStr(env, key=filters, inc=True):
                        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 = dict()
            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(
                        "fail 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 accessable directory" % d)
                    sys.exit(0)
        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(
                '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))
                    cnt += 1

                if cnt > 0:
                    SysMgr.printPipe('[ %s ]' % node)
                    SysMgr.doPrint(clear=True)
                    nrItems += 1
                else:
                    SysMgr.clearPrint()
                    filteredList[node] = value

            if nrItems == 0:
                SysMgr.printPipe('\tNone')
            SysMgr.printPipe('%s\n' % oneLine)

        # print filtered list #
        if len(filteredList) > 0:
            SysMgr.printPipe(
                '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

        obj = TaskAnalyzer(onlyInstance=True)
        obj.saveSystemStat()

        cv = UtilMgr.convNum
        for ns, val in sorted(obj.nsData.items(), key=lambda e: e[0]):
            SysMgr.printPipe(
                '[%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.keys()), key=lambda e:long(e))[0]
                comm = obj.procData[tid]['stat'][obj.commIdx][1:-1]
                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.keys(), key=lambda e:long(e)):
                    comm = obj.procData[tid]['stat'][obj.commIdx][1:-1]
                    SysMgr.printPipe('%s - %s(%s)' % (indentStr, comm, tid))
            SysMgr.printPipe('%s\n' % oneLine)

        sys.exit(0)



    @staticmethod
    def doPrintInfo():
        SysMgr.printLogo(big=True, onlyFile=True)

        SysMgr()
        SysMgr.sysInstance.saveSysStat()

        if SysMgr.jsonEnable:
            # convert dict data to JSON-type string #
            jsonObj = UtilMgr.convDict2Str(SysMgr.jsonData)
            if not jsonObj:
                SysMgr.printWarn(
                    "fail to convert report data to JSON type")
            else:
                SysMgr.printPipe(jsonObj)
        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.getMainArg().split(',')
            opList = UtilMgr.cleanItem(opList, False)
        elif SysMgr.filterGroup:
            opList = SysMgr.filterGroup
        else:
            opList = ["."]

        targetList = []
        targetInfo = {}

        # parse items #
        for item in opList:
            args = item.split(':')
            path = 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, verb=True)
                if not ret:
                    break

                current = SysMgr.updateUptime()

                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

                    # convert path #
                    fpath = os.path.realpath(os.path.expanduser(fpath))

                    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("fail to watch", reason=True)
                sys.exit(0)



    @staticmethod
    def doTrace(mode):
        def _doCommonJobs(pids, procList):
            # check STOP condition #
            if 'STOPTARGET' in SysMgr.environList:
                needStop = True
            else:
                needStop = False

            # 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, list())
                    procList[pid].append(tid)
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

            pidList = list(map(long, procList.keys()))

            # merge map files #
            mapList = []
            getProcMapInfo = FileAnalyzer.getProcMapInfo
            for pid in pidList:
                mapList += getProcMapInfo(pid, onlyExec=True).keys()
            mapList = list(set(mapList))

            # load symbol caches at once #
            printLog = True
            for item in mapList:
                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

            if mode != 'breakcall':
                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, dict())
                exceptBpList.setdefault(pid, dict())
                targetBpList.setdefault(pid, dict())
                targetBpFileList.setdefault(pid, dict())
                exceptBpFileList.setdefault(pid, dict())

                # create object #
                procObj = Debugger(pid=pid, execCmd=execCmd, mode='break')
                if not procObj:
                    continue

                # register signal sender for resume #
                SysMgr.addExitFunc(
                    SysMgr.sendSignalProcs,
                    [signal.SIGCONT, [pid], False, False])

                # load common ELF cache files #
                if procObj.loadSymbols():
                    procObj.updateBpList()

                # save per-process breakpoint info #
                bpList[pid] = \
                    deepcopy(procObj.bpList)
                exceptBpList[pid] = \
                    deepcopy(procObj.exceptBpList)
                targetBpList[pid] = \
                    deepcopy(procObj.targetBpList)
                targetBpFileList[pid] = \
                    deepcopy(procObj.targetBpFileList)
                exceptBpFileList[pid] = \
                    deepcopy(procObj.exceptBpFileList)

                # create a lock for a target multi-threaded process #
                if SysMgr.getPids(pid, sibling=True):
                    lockList[pid] = \
                        Debugger.getGlobalLock(pid, len(bpList[pid]))

                procObj.detach()
                del procObj

                # remove signal sender #
                SysMgr.removeExitFunc(
                    SysMgr.sendSignalProcs,
                    [signal.SIGCONT, [pid], False, False])

        SysMgr.printLogo(big=True, onlyFile=True)

        # no use pager #
        if not SysMgr.isTopMode() and not SysMgr.outPath:
            SysMgr.setStream()

        # define wait syscall #
        wait = None
        multi = False
        execCmd = None
        lockObj = None
        procList = {}
        bpList = {}
        lockList = {}
        exceptBpList = {}
        targetBpList = {}
        targetBpFileList = {}
        exceptBpFileList = {}

        # get argument #
        if 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(0)

        # check condition #
        if mode == 'remote' or mode == 'hook':
            if not SysMgr.customCmd:
                SysMgr.printErr("fail to get remote command")
                sys.exit(0)
            elif inputParam:
                SysMgr.printErr("executing a program is not supported")
                sys.exit(0)

        # set priority #
        if not SysMgr.prio:
            SysMgr.setPriority(SysMgr.pid, 'C', -20)

        # create event memory #
        Debugger.globalEvent = SysMgr.createShm()

        # check symbol requirement #
        needSymbol = (
            mode == 'usercall' or mode == 'sample' or \
            mode == 'breakcall' or mode == 'hook' or \
            mode == 'bind' or SysMgr.funcDepth > 0)

        # set dwarf flag #
        SysMgr.setDwarfFlag()

        # get pids #
        if not inputParam:
            # convert comm to pid #
            pids = SysMgr.convPidList(
                SysMgr.filterGroup, isThread=True,
                    sibling=SysMgr.groupProcEnable)

            # get pids of process groups #
            if mode == 'breakcall':
                allpids = SysMgr.convPidList(
                    SysMgr.filterGroup, isThread=True, sibling=True)
            else:
                allpids = pids

        # check command #
        if inputParam:
            pid = None
            execCmd = inputParam.split()
        # check permission #
        elif not SysMgr.isRoot():
            SysMgr.printErr(
                "fail to get root permission to trace %s" % mode)
            sys.exit(0)
        # 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(0)
        # check targets #
        elif len(allpids) > 1 or mode == 'breakcall':
            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 child tracers as their parent #
            if SysMgr.pid == parent:
                if isFinished:
                    while 1:
                        SysMgr.waitEvent(ignChldSig=False, block=False)
                        if SysMgr.condExit:
                            break

                        # check childs #
                        SysMgr.updateChildList()
                        if SysMgr.isNoChild():
                            break

                # disable printing to file #
                SysMgr.outPath = SysMgr.printFd = None

                # broadcast term signal to childs and wait for them #
                signal.signal(signal.SIGCHLD, signal.SIG_IGN)
                SysMgr.killChilds(
                    sig=signal.SIGINT, wait=True, group=True)

                # continue processes #
                if SysMgr.isAlive(tid):
                    SysMgr.sendSignalProcs(
                        signal.SIGCONT, list(procList.keys()), verbose=False)

                # remove temporary files #
                if mode == 'breakcall':
                    # 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 == '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 == 'breakcall':
                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

                Debugger(pid=pid, execCmd=execCmd).\
                    trace(mode='break', 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')
            elif mode == 'pycall':
                dobj = Debugger(pid=pid, execCmd=execCmd, attach=False)
                dobj.trace(mode='pycall', wait=wait, multi=multi)
            else:
                # syscall / signal / remote #
                dobj = Debugger(
                    pid=pid, execCmd=execCmd, attach=False, mode=mode)
                dobj.trace(mode=mode, wait=wait, multi=multi)
        except SystemExit:
            sys.exit(0)
        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(0)

        # check symbol #
        if not SysMgr.filterGroup:
            SysMgr.printErr("no input for offset")
            sys.exit(0)
        else:
            addrList = list()
            for idx, addr in enumerate(SysMgr.filterGroup):
                if not UtilMgr.isNumber(addr):
                    SysMgr.printErr(
                        "fail to recognize '%s' as a number" % addr)
                    sys.exit(0)

                try:
                    addrList.append(long(addr, 16))
                except:
                    addrList.append(long(addr))

        resInfo = {}
        menu1st = 'Offset'
        menu2nd = 'Address'
        maxSymLen = 5

        # get pid list #
        pids = SysMgr.getPids(inputArg)
        taskList = []
        for tid in pids:
            taskList.append(SysMgr.getTgid(tid))
        pids = list(set(taskList))
        procInfo = ''

        # single file #
        if not pids:
            # check file #
            if not os.path.isfile(inputArg):
                SysMgr.printErr(
                    "fail to recognize %s as a file or a process" % inputArg)
                sys.exit(0)

            menu1st = 'Address'
            menu2nd = 'Offset'

            filePath = inputArg

            # create ELF object #
            try:
                binObj = ElfAnalyzer.getObject(filePath)
                if not binObj:
                    err = SysMgr.getErrMsg()
                    raise Exception(err)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "fail to load %s as an ELF object" % filePath, True)
                sys.exit(0)

            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']
        # multiple process #
        elif len(pids) > 1:
            SysMgr.printErr((
                "fail to find a unique process because "
                "[ %s ] are found") % SysMgr.getCommList(pids))
            sys.exit(0)
        # single process #
        else:
            pid = pids[0]
            comm = SysMgr.getComm(pid)
            procInfo = '%s(%s)' % (comm, pid)

            try:
                dobj = Debugger(pid=pid, attach=False)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("fail to analyze %s" % procInfo, True)
                sys.exit(0)

            for addr in addrList:
                ret = dobj.getSymbolInfo(addr, onlyFunc=False, onlyExec=False)
                if not ret:
                    SysMgr.printErr("fail to analyze %s" % procInfo, True)
                    sys.exit(0)
                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']

        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')



    @staticmethod
    def printDirs(path='.', maxLevel=-1):
        def _getDirs(result, parentPath, level, maxLevel):
            fileList = os.listdir(parentPath)
            parentAbsPath = "%s" % (os.path.abspath(parentPath))

            if not fileList or \
                    (maxLevel != -1 and maxLevel <= level):
                return (0, 0, 0)

            totalSize = long(0)
            totalFile = long(0)
            totalDir = long(0)

            # sort by size #
            if SysMgr.showAll:
                fileList.sort(
                    key=lambda name: os.path.getsize(
                        '%s/%s' % (parentPath, name)), reverse=True)
            # sort by type #
            else:
                fileList.sort(
                    key=lambda f: os.path.isfile(os.path.join(parentPath, f)))

            for idx, subPath in enumerate(fileList):

                fullPath = os.path.join(parentPath, subPath)

                if os.path.islink(fullPath):
                    continue

                subAbsPath = "%s" % (os.path.abspath(fullPath))

                if os.path.isdir(fullPath):
                    totalDir += 1

                    if SysMgr.showAll:
                        info = dict(subDirs=dict(), subFiles=dict())
                    else:
                        info = dict(subDirs=dict())

                    result[parentAbsPath]['subDirs'][subAbsPath] = info
                    totalInfo = \
                        _getDirs(result[parentAbsPath]['subDirs'],
                            fullPath, level + 1, maxLevel)

                    totalSize += totalInfo[0]
                    totalDir += totalInfo[1]
                    totalFile += totalInfo[2]

                elif os.path.isfile(fullPath):
                    totalFile += 1
                    size = os.stat(fullPath).st_size
                    totalSize += size

                    if not SysMgr.showAll:
                        continue

                    if 'subFiles' not in result[parentAbsPath]:
                        result[parentAbsPath]['subFiles'] = dict()
                    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 _recurse(parentPath, fileList, prefix, result, level, maxLevel):
            totalSize = long(0)
            totalFile = long(0)
            totalDir = long(0)

            if not fileList or (maxLevel != -1 and maxLevel <= level):
                return (0, 0, 0)

            UtilMgr.printProgress()

            # sort by size #
            if SysMgr.showAll:
                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 #
            else:
                fileList.sort(
                    key=lambda f: os.path.isfile(os.path.join(parentPath, f)))

            for idx, subPath in enumerate(fileList):
                idc = "|-"

                fullPath = os.path.join(parentPath, subPath)

                # check link #
                if os.path.islink(fullPath):
                    pass

                # check dir #
                if os.path.isdir(fullPath):
                    totalDir += 1
                    isEffective = False

                    # apply filter #
                    if SysMgr.filterGroup:
                        if UtilMgr.isValidStr(subPath, inc=False):
                            isEffective = True
                            SysMgr.printPipe('[%s]' % fullPath)
                    else:
                        isEffective = True
                        string = "%s%s[%s]" % (prefix, idc, subPath)
                        result.append(string)

                    # apply command #
                    if isEffective and SysMgr.customCmd:
                        _executeCmd(fullPath)

                    # update prefix #
                    tmpPrefix = prefix + "|  "

                    # get subdir #
                    try:
                        subdirs = os.listdir(fullPath)
                    except SystemExit:
                        sys.exit(0)
                    except:
                        SysMgr.printWarn(
                            "fail to access %s" % fullPath,
                            always=True, reason=True)
                        continue

                    # traverse subdirs #
                    rlist = _recurse(
                        fullPath, subdirs, tmpPrefix,
                            result, level + 1, maxLevel)

                    totalSize += rlist[0]
                    totalFile += rlist[2]
                    if isEffective:
                        totalDir += rlist[1]
                # check file #
                elif os.path.isfile(fullPath):
                    size = ''

                    # apply filter #
                    if SysMgr.filterGroup:
                        if not UtilMgr.isValidStr(subPath, inc=False):
                            continue

                        # get size #
                        try:
                            size = os.stat(fullPath).st_size
                            totalSize += size
                            size = ' <%s>' % UtilMgr.convSize2Unit(size)
                        except SystemExit:
                            sys.exit(0)
                        except:
                            size = ''

                        string = '%s%s' % (fullPath, size)
                        SysMgr.printPipe(string)

                        # apply command #
                        if SysMgr.customCmd:
                            _executeCmd(fullPath)

                    totalFile += 1

                    # get size #
                    try:
                        if not size:
                            size = os.stat(fullPath).st_size
                            totalSize += size
                            size = ' <%s>' % UtilMgr.convSize2Unit(size)
                    except SystemExit:
                        sys.exit(0)
                    except:
                        SysMgr.printWarn(
                            'fail to get size of %s' % fullPath, reason=True)
                        size = ''

                    if not SysMgr.showAll or SysMgr.filterGroup:
                        continue

                    # apply command #
                    if SysMgr.customCmd:
                        _executeCmd(fullPath)

                    string = "%s%s%s%s" % (prefix, idc, subPath, size)
                    result.append(string)

            if totalSize:
                tsize = 'SIZE: %s, ' % \
                        UtilMgr.convSize2Unit(totalSize)
            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 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 = ['*']

        # print start path #
        if SysMgr.jsonEnable:
            result = dict()
            if SysMgr.showAll:
                result[os.path.abspath(path)] = \
                    dict(subDirs=dict(), subFiles=dict())
            else:
                result[os.path.abspath(path)] = dict(subDirs=dict())

            _getDirs(result, path, 0, -1)
            jsonResult = UtilMgr.convDict2Str(result)
            SysMgr.printPipe(jsonResult)
        else:
            try:
                initDir = os.listdir(path)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "fail to access %s" % path, reason=True)
                sys.exit(0)

            abspath = "[%s]" % (os.path.abspath(path))
            result = [abspath]

            SysMgr.printStat(
                r"start traversing dirs from %s..." % abspath)

            _recurse(path, initDir, "  ", result, 0, maxLevel)
            output = "\n%s\n" % "\n".join(result)
            UtilMgr.deleteProgress()

            SysMgr.printPipe(output)



    @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("fail to get memory map for %s" % procInfo)
            return resInfo

        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("fail to get [ %s ] from memory map for %s" % \
                    (', '.join(fileFilter), procInfo))
                sys.exit(0)
            fileList = newFileList

        magicStr = SysMgr.magicStr
        for filePath, attr in sorted(
            fileList.items(), key=lambda e: e[1]['vstart']):
            for sym in symbolList:
                # create 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(
                        "fail to save offset info", True, reason=True)

        return resInfo



    @staticmethod
    def setDwarfFlag():
        # check DWARF requirement #
        if not SysMgr.dwarfEnable and \
            (SysMgr.arch != 'AARCH64' or SysMgr.arch != 'ARM'):
            disableList = SysMgr.getOption('d')
            if not disableList or not 'D' in disableList:
                SysMgr.dwarfEnable = True



    @staticmethod
    def doMkCache():
        SysMgr.printLogo(big=True, onlyFile=True)

        # set dwarf flag #
        SysMgr.setDwarfFlag()

        # check input #
        if SysMgr.hasMainArg():
            inputArg = SysMgr.getMainArg().split(',')
            inputArg = UtilMgr.cleanItem(inputArg, True)
        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(0)

        # get pid list #
        pids = []
        for item in inputArg:
            pids = SysMgr.getPids(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(
                        "fail to recognize %s as a file or a process" % item)
                    sys.exit(0)

                ElfAnalyzer.getObject(item)
        else:
            procList = {}

            # get pid list #
            for tid in pids:
                try:
                    pid = SysMgr.getTgid(tid)
                    if not pid:
                        continue

                    procList.setdefault(pid, list())
                    procList[pid].append(tid)
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

            pidList = list(map(long, procList.keys()))

            # merge map files #
            mapList = []
            getProcMapInfo = FileAnalyzer.getProcMapInfo
            for pid in pidList:
                mapList += getProcMapInfo(pid, onlyExec=True).keys()
            mapList = list(set(mapList))

            # load symbol caches at once #
            printLog = True
            for item in mapList:
                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



    @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(0)

        # 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))

        resInfo = {}
        maxSymLen = 5

        # get pid list #
        pids = SysMgr.getPids(inputArg)
        taskList = []
        for tid in pids:
            taskList.append(SysMgr.getTgid(tid))
        pids = list(set(taskList))
        procInfo = ''

        # single file #
        if not pids:
            # check file #
            if not os.path.isfile(inputArg):
                SysMgr.printErr(
                    "fail to recognize %s as a file or a process" % inputArg)
                sys.exit(0)

            filePath = inputArg

            for sym in SysMgr.filterGroup:
                # create ELF object #
                try:
                    offset = ElfAnalyzer.getSymOffset(sym, inputArg)
                    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(
                        "fail to get '%s' info" % sym, True)
                    sys.exit(0)
        # multiple process #
        elif len(pids) > 1:
            SysMgr.printErr((
                "fail to find a unique process because "
                "[ %s ] are found") % SysMgr.getCommList(pids))
            sys.exit(0)
        # single process #
        else:
            pid = pids[0]
            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])

        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')



    @staticmethod
    def initTaskMon(pid, update=True):
        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):
        path = '%s/%s' % (SysMgr.procPath, SysMgr.pid)
        SysMgr.updateUptime()
        tobj.saveProcData(path, pid)
        tobj.setProcUsage()



    @staticmethod
    def doLeaktrace():
        def _waitAndKill(tobj, pid, comm, cond, sig, purpose, hookCmd=None):
            # define RSS index #
            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:
                condUnit = ''
            else:
                condUnit = '/%s' % UtilMgr.convSize2Unit(cond)

            # wait for RSS #
            previous = 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(
                            "fail to get RSS of %s(%s)" % (comm, pid))
                    return -1

                procData = tobj.procData[pid]['stat']
                vss = UtilMgr.convSize2Unit(long(procData[vssIdx]))
                rss = long(procData[rssIdx]) << 12
                rssUnit = UtilMgr.convSize2Unit(rss)
                if previous != rssUnit:
                    SysMgr.printInfo(
                        '%s(%s)\'s VSS(%s), RSS(%s%s) for %s' % \
                            (comm, pid, vss, rssUnit, condUnit, purpose),
                                prefix=False)
                previous = rssUnit

                if cond <= rss:
                    break
                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)

            # send signal #
            try:
                os.kill(long(pid), sig)
                SysMgr.printStat(
                    'sent %s to %s(%s) to %s profiling' % \
                        (ConfigMgr.SIG_LIST[sig], comm, pid, purpose))
            except:
                SysMgr.printErr(
                    "fail to send signal %s to %s profiling" % \
                        (ConfigMgr.SIG_LIST[startSig], purpose), reason=True)
                return -1

            return 0



        # check package #
        SysMgr.getPkg('ctypes')

        # check target id #
        targetList = SysMgr.filterGroup
        if not targetList:
            SysMgr.printErr("no input for PID or COMM")
            sys.exit(0)

        # convert comm to pid #
        pid = None
        isMulti = False
        startTime = endTime = 0
        pids = SysMgr.convPidList(targetList, exceptMe=True)
        if not pids:
            SysMgr.printErr("no %s process" % \
                ', '.join(targetList))
            sys.exit(0)
        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 #
        comm = SysMgr.getComm(pid)

        # get environment variables of 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)',
            'operator delete(void*)',
            'operator delete[](void*)',
        ]

        # check preload result #
        libPath = None
        ret = FileAnalyzer.getMapFilePath(pid, 'libleaktracer')
        if ret:
            SysMgr.printStat(
                '%s is already preloaded to %s(%s)' % (ret, comm, pid))
        else:
            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(0)
                elif len(newPath) > 1:
                    SysMgr.printErr(
                        "found multiple libraries [ %s ]" % \
                            ', '.join(newPath))
                    sys.exit(0)

                # convert to absolute path #
                libPath = os.path.abspath(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(
                    'fail to find libleaktracer.so on memory map '
                    'because the library is not preloaded')
                sys.exit(0)
            else:
                SysMgr.printErr(
                    'fail to find libleaktracer.so on memory map '
                    'because the library is not preloaded\n'
                    '\tIf the target process is on secure-execution mode,n'
                    '\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(0)

        # create a task object #
        tobj = SysMgr.initTaskMon(pid, update=False)
        path = '%s/%s' % (SysMgr.procPath, pid)

        # set input file path #
        autostart = False
        if 'LEAKTRACER_ONSIG_REPORTFILENAME' in envList:
            fname = envList['LEAKTRACER_ONSIG_REPORTFILENAME']
        elif 'LEAKTRACER_AUTO_REPORTFILENAME' in envList:
            autostart = True
            fname = envList['LEAKTRACER_AUTO_REPORTFILENAME']
            startTime = SysMgr.uptime - tobj.procData[pid]['runtime']
        else:
            fname = None
            if SysMgr.inputParam:
                fname = os.path.abspath(SysMgr.inputParam)
                if os.path.isdir(fname):
                    if isMulti:
                        fname = '%s/leaks_%s.out' % (fname, pid)
                    else:
                        fname = '%s/leaks.out' % fname
            elif os.path.exists(SysMgr.tmpPath):
                if isMulti:
                    fname = '%s/leaks_%s.out' % (SysMgr.tmpPath, pid)
                else:
                    fname = '%s/leaks.out' % SysMgr.tmpPath
            elif SysMgr.isWritable('.'):
                current = os.path.abspath('.')
                if isMulti:
                    fname = '%s/leaks_%s.out' % (current, pid)
                else:
                    fname = '%s/leaks.out' % current
            else:
                SysMgr.printErr(
                    "no input for temporary file path")
                sys.exit(0)

            # 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 signal #
        startSig = stopSig = None
        if 'LEAKTRACER_ONSIG_STARTALLTHREAD' in envList:
            startSig = long(envList['LEAKTRACER_ONSIG_STARTALLTHREAD'])
        if 'LEAKTRACER_ONSIG_REPORT' in envList:
            stopSig = long(envList['LEAKTRACER_ONSIG_REPORT'])

        # get signals #
        if SysMgr.killFilter:
            sigList = SysMgr.killFilter

            if len(sigList) >= 2:
                startSig = SysMgr.getSigNum(sigList[0][0])
                if not startSig:
                    SysMgr.printErr(
                        "wrong signal %s for start" % sigList[0][0])
                    sys.exit(0)

                stopSig = SysMgr.getSigNum(sigList[1][0])
                if not stopSig:
                    SysMgr.printErr(
                        "wrong signal %s for stop" % sigList[1][0])
                    sys.exit(0)
            else:
                stopSig = SysMgr.getSigNum(sigList[0][0])
                if not stopSig:
                    SysMgr.printErr(
                        "wrong signal %s for stop" % sigList[0][0])
                    sys.exit(0)

        # add an environment for start signal #
        if not autostart and not startSig:
            startSig = LeakAnalyzer.startSig
            remoteCmd.insert(
                0, 'setenv:LEAKTRACER_ONSIG_STARTALLTHREAD#"%s"' % startSig)

        # add an environment for stop signal #
        if not stopSig:
            stopSig = LeakAnalyzer.stopSig
            remoteCmd.insert(
                0, 'setenv:LEAKTRACER_ONSIG_REPORT#"%s"' % stopSig)

        if remoteCmd:
            if not libPath:
                remoteCmd.append(
                    'usercall:leaktracer::MemoryTrace::init_full_from_once()')

        # check signal handler #
        tryCnt = 0
        retryCnt = 5
        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(
                        'fail to find libleaktracer.so on memory map')
                    continue

                tobj.saveProcStatusData(path, pid)

                # check start signal #
                sigList = tobj.procData[pid]['status']['SigCgt']
                if startSig and not UtilMgr.isBitEnabled(startSig, sigList):
                    SysMgr.printWarn(
                        "fail to find start handler for %s(%s)" % \
                            (ConfigMgr.SIG_LIST[startSig], startSig), True)

                    tryCnt += 1
                    if tryCnt >= retryCnt:
                        break

                    time.sleep(1)
                    continue

                # check stop signal #
                if stopSig and not UtilMgr.isBitEnabled(stopSig, sigList):
                    SysMgr.printWarn(
                        "fail to find stop handler for %s(%s)" % \
                            (ConfigMgr.SIG_LIST[stopSig], stopSig), True)

                    tryCnt += 1
                    if tryCnt >= retryCnt:
                        break

                    time.sleep(1)
                    continue

                break
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("fail to check signal", reason=True)

        # set hook command #
        if hookCmd:
            hcmd = \
                ['hook', '-g%s' % pid, '-c%s' % ','.join(hookCmd), '-I']

        # START #
        cmd = SysMgr.customCmd
        startSize = endSize =  0
        convUnit = UtilMgr.convUnit2Size
        if cmd:
            if len(cmd) >= 2:
                startSize = convUnit(cmd[0])
                endSize = convUnit(cmd[1])
            else:
                endSize = convUnit(cmd[0])

            # 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(0)
        elif startSig:
            # hook #
            if hookCmd:
                SysMgr.launchGuider(
                    hcmd, pipe=False, stderr=True, log=True, wait=True)

            # send signal for start #
            try:
                os.kill(long(pid), startSig)
                SysMgr.printStat(
                    'sent %s to %s(%s) to start profiling' % \
                        (ConfigMgr.SIG_LIST[startSig], comm, pid))
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "fail to send signal %s to start profiling" % \
                        ConfigMgr.SIG_LIST[startSig], reason=True)
                sys.exit(0)

        # update start time #
        if not startTime:
            SysMgr.updateUptime()
            startTime = SysMgr.uptime

        # STOP #
        if endSize > 0:
            ret = _waitAndKill(tobj, pid, comm, endSize, stopSig, 'stop')
            if ret < 0:
                sys.exit(0)
        elif stopSig:
            try:
                # wait for stop threshold #
                try:
                    SysMgr.printStat(
                        r'start monitoring... [ STOP(Ctrl+c) ]')

                    ret = 0
                    ret = _waitAndKill(tobj, pid, comm, sys.maxsize, 0, 'stop')
                except:
                    pass

                if ret < 0:
                    sys.exit(0)

                os.kill(long(pid), stopSig)

                SysMgr.printStat(
                    'sent %s to %s(%s) to stop profiling' % \
                        (ConfigMgr.SIG_LIST[stopSig], comm, pid))
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "fail to send signal %s to stop profiling" % \
                        ConfigMgr.SIG_LIST[stopSig], reason=True)
                sys.exit(0)

        # 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:
            runtime = '?'
            profiletime = '?'

        SysMgr.printStat('wait for %s' % fname)

        # wait for the output file is 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)

        # create leaktracer parser #
        try:
            lt = LeakAnalyzer(fname, pid)
            lt.printLeakage(runtime, profiletime)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "fail 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(0)
            elif prot == 'udp':
                tcp = False
            else:
                SysMgr.printErr(
                    "%s protocol is not supported" % prot)
                sys.exit(0)

            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(0)

        # run tasks #
        ioTasks = dict()
        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(0)

        # set alarm #
        signal.signal(signal.SIGALRM, SysMgr.onAlarm)
        signal.alarm(SysMgr.intervalEnable)

        # wait for childs #
        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 doIoTest():
        # snapshot system info including mount #
        SysMgr()

        workload = []
        writeData = b'0' * 4096

        def _flushCache(verb=False):
            try:
                ret = SysMgr.checkRootPerm(exit=False, verb=False)
                if not ret:
                    raise Exception('no root permission')

                dropCachePath = \
                    '%s/sys/vm/drop_caches' % SysMgr.procPath
                with open(dropCachePath, 'w') as fd:
                    if verb:
                        SysMgr.printInfo(
                            'start flushing system cache... ', suffix=False)
                    ret = fd.write('3')
                    if verb:
                        SysMgr.printInfo("[Done]", prefix=False, notitle=True)
            except:
                SysMgr.printWarn(
                    'fali to flush system cache', reason=True)

        def _iotask(num, load):
            def _readChunk(fobj, size=4096):
                while 1:
                    ret = os.read(fobj, size)
                    yield ret

            def _writeChunk(fobj, sync=False, size=4096):
                while 1:
                    ret = os.write(fobj, writeData[:size])
                    if sync:
                        os.fsync(fobj)
                    yield ret

            SysMgr.setDefaultSignal()

            op = load['op']
            path = load['path']
            if op == 'read':
                flag = os.O_RDONLY
            elif op == 'write':
                flag = os.O_WRONLY | os.O_CREAT | os.O_TRUNC

            # set operation #
            if op == 'read':
                opFunc = _readChunk
            elif op == 'write':
                opFunc = _writeChunk
            else:
                SysMgr.printErr(
                    "failed to recognize operation %s" % op)
                sys.exit(0)

            # set direction #
            if op == 'write':
                direct = 'to'
            elif op == 'read':
                direct = 'from'

            # 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

            SysMgr.printInfo(
                "created a new process to %s %s '%s'" % \
                    (op, direct, path))

            # run loop #
            while 1:
                # flush page caches #
                _flushCache()

                # FILE #
                if target == 'file':
                    try:
                        fd = os.open(path, flag)
                        for piece in opFunc(fd):
                            if not piece:
                                return
                        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):
                                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)

        # get tasks #
        try:
            if SysMgr.hasMainArg():
                opList = SysMgr.getMainArg().split(',')
                opList = UtilMgr.cleanItem(opList, False)
            elif SysMgr.filterGroup:
                opList = SysMgr.filterGroup
            else:
                opList = None

            if opList:
                for item in opList:
                    item = item.split(':')
                    if len(item) == 1:
                        op = 'read'
                        path = item[0]
                    else:
                        op, path = item

                    if op != 'write' and \
                        not os.path.exists(path):
                        SysMgr.printErr(
                            "fail to access %s" % path)
                        sys.exit(0)

                    workload.append(
                        {'op': op, 'path': path})

            elif SysMgr.showAll:
                for path, value in SysMgr.sysInstance.mountInfo.items():
                    if path.startswith('/dev/') and \
                        not 'loop' in path:

                        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})
            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(
                        "fail to access to %s" % mountPoint)
                    sys.exit(0)

                workload.append(
                    {'op': 'read', 'path': mountPoint})

        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(0)

        # drop cache #
        _flushCache(verb=True)

        # run tasks #
        ioTasks = dict()
        for cnt in range(0, 1):
            for idx in range(0, len(workload)):
                try:
                    pid = SysMgr.createProcess()
                    if pid == 0:
                        _iotask(idx, workload[idx])
                    else:
                        ioTasks[pid] = workload[idx]
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(
                        "failed to create process", True)
                    sys.exit(0)

        # set alarm #
        SysMgr.repeatCount = sys.maxsize
        signal.signal(signal.SIGALRM, SysMgr.onAlarm)
        signal.alarm(1)

        # wait for childs #
        while 1:
            if not ioTasks:
                break
            SysMgr.waitEvent(ignChldSig=False, exit=True)
            SysMgr.updateChildList()
            if SysMgr.isNoChild():
                break



    @staticmethod
    def getGpuInfo():
        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, return a default value

        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 range(nGpus.value):
            result = cuda.cuDeviceGet(byref(device), i)
            if result != CUDA_SUCCESS:
                return None

            gpuInfo[i] = dict()

            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.

            if cuda.cuDeviceGetAttribute(
                byref(clockrate), CU_DEVICE_ATTRIBUTE_MEMORY_CLOCK_RATE, device) == CUDA_SUCCESS:
                gpuInfo[i]['memClock(MHz)'] = clockrate.value / 1000.

            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 _convPath2Data(path, enc=False):
            if not path or not isinstance(path, str):
                return path

            # define keys #
            skey = '@@@FILE:'
            ekey = '@@@'

            # get start pos #
            start = path.find(skey)
            if start < 0:
                return path
            secStart = start+len(skey)
            end = path[secStart:].find(ekey)
            if end < 0:
                return path

            # 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 #
            if req in cache:
                cmd, method, content, arg, timeout, auth, \
                    verify, cookies, headers, reqstr, files, json = cache[req]
            # parse request #
            else:
                timeout = None
                auth = None
                verify = False
                cookies = None
                headers = None

                # GET #
                if req.startswith('GET#'):
                    method = 'GET'
                    cmd = requests.get
                    remain = req[len(method)+1:]
                # POST #
                elif req.startswith('POST#'):
                    method = 'POST'
                    cmd = requests.post
                    remain = req[len(method)+1:]
                # default #
                else:
                    method = 'GET'
                    cmd = requests.get
                    remain = req

                # 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().decode()

                            # 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(
                                "fail to get data from '%s'" % path,
                                reason=True)
                            sys.exit(0)
                    elif remain.startswith('FILE:'):
                        try:
                            orig = remain
                            data, remain = remain.split('#', 1)

                            # pass file descriptor #
                            path = '??'
                            fileInfo = data.split(':')[1:]
                            name = fileInfo[0]
                            path = fileInfo[1]
                            fileInfo.insert(2, open(path, 'rb'))
                            fileArgs = tuple(fileInfo[1:])
                            files.append((name, fileArgs))
                        except SystemExit:
                            sys.exit(0)
                        except:
                            SysMgr.printErr(
                                "fail to get data from '%s'" % path,
                                reason=True)
                            sys.exit(0)
                    elif remain.startswith('TIMEOUT:'):
                        timestr, remain = remain.split('#', 1)
                        timeout = timestr.split(':', 1)[1].strip()
                        if not timeout.isdigit():
                            SysMgr.printErr(
                                'fail to get timeout(sec) in %s' % timestr)
                            sys.exit(0)
                        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(
                                'fail to get verify(TRUE/FALSE) value')
                            sys.exit(0)
                    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 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)

            # 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)

            # update time #
            after = time.time()
            elapsed = after - before

            # save statistics #
            stats['perReqTime'].setdefault(req, list())
            stats['perReqTime'][req].append(elapsed)
            stats['perReqTimeAll'][req].append([before, elapsed])

            # 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

            # check mute flag #
            if mute:
                return

            # 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))

        def _task(reqs, repeat, delay, cache):
            # initialize statistics #
            stats = {
                'perReqTime': dict(),
                'perReqTimeAll': dict(),
                'perReqErr': dict(),
                'perCycleTime': list(),
            }


            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 range(1, repeat+1):
                    before = time.time()

                    for req in reqs:
                        try:
                            stats['perReqTimeAll'].setdefault(req, list())
                            stats['perReqErr'].setdefault(req, 0)

                            # do request #
                            _request(req, cache, stats,
                                idx, lastReqTime, verb, mute)

                            # make a delay #
                            time.sleep(delay)
                        except SystemExit:
                            sys.exit(0)
                        except:
                            stats['perReqTimeAll'][req].append(
                                [lastReqTime[0], 0])
                            stats['perReqErr'][req] += 1
                            SysMgr.printErr(
                                "fail 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:
                    tcpu = convNum(tcpu)
                    acpu = convNum(acpu)
                else:
                    tcpu = acpu = 0
            except SystemExit:
                sys.exit(0)
            except:
                tcpu = '?'
                acpu = '?'

            # 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), convNum(len(reqs)*repeat), delay,
                        tcpu, acpu, twoLine))

                SysMgr.printPipe(
                    '{0:^50} | {1:^80}\n{2:1}'.format(
                        'Reqest', '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), convNum(len(reqs)*repeat), 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

                cnt = convNum(cnt)

                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, idx))

            # 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('[%0d] %s' % (idx, cmd))
                    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 = uinput.strip(cmd).strip(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(
                        "fail to set repeat count to '%s'", True)



            # run mainloop for user interaction #
            hlist = list()
            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(
                        'fail 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:
            requests.packages.urllib3.util.ssl_.DEFAULT_CIPHERS += \
                ':DES-CBC3-SHA'
            requests.packages.urllib3.disable_warnings(
                requests.packages.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 = ''

        SysMgr.printInfo(
            'request %s times%s%s' % \
                (UtilMgr.convNum(repeat), delayStr, procStr))

        start = time.time()

        try:
            # process #
            if SysMgr.utilProc > 1:
                if SysMgr.isLinux:
                    for idx in range(1, SysMgr.utilProc+1):
                        # create a new worker #
                        pid = SysMgr.createProcess()
                        if pid == 0:
                            _task(reqs, repeat, delay, cache)

                            sys.exit(0)

                    # wait for childs #
                    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(
                'fail to request', reason=True)
            sys.exit(0)

        # print elapsed time #
        elapsed = time.time() - start
        SysMgr.printInfo(
            'finished all requests for %.6f sec' % elapsed)



    @staticmethod
    def doExec():
        def _customRange(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'" % cmd)

            # get environment variables #
            env = SysMgr.getEnvList()

            startTime = time.time()

            # create process to communicate #
            procObj = subprocess.Popen(
                cmd, shell=True, bufsize=0, env=env)

            # run mainloop #
            try:
                procObj.wait()
            except SystemExit:
                sys.exit(0)
            except:
                duration = time.time() - startTime

                SysMgr.printErr(
                    "fail to wait termination for '%s'" % cmd, True)

                sys.exit(0)

            duration = time.time() - startTime

            SysMgr.printInfo(
                "terminated '%s' and elapsed %s" % (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 _customRange(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(
                            "fail to execute '%s'" % tcmd, True)
                        sys.exit(0)
            elif len(item) == 2 and os.path.isdir(item[1]):
                key = item[0]
                flist = UtilMgr.getFiles(item[1], incDir=True)
                for item in flist:

                    tcmd = cmd.replace(key, item)

                    try:
                        _iterVarCmd(tcmd, list(var))
                    except SystemExit:
                        sys.exit(0)
                    except:
                        SysMgr.printErr(
                            "fail to execute '%s'" % tcmd, True)
                        sys.exit(0)
            else:
                SysMgr.printErr("wrong variable '%s'" % conv)
                sys.exit(0)

        # get command #
        if SysMgr.hasMainArg():
            cmd = SysMgr.getMainArg()
        elif SysMgr.inputParam:
            cmd = SysMgr.inputParam
        else:
            SysMgr.printErr("no input for command")
            sys.exit(0)

        # 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.getMainArg().split(',')
            inputList = UtilMgr.cleanItem(inputList)
        elif SysMgr.inputParam:
            inputList = SysMgr.inputParam.split(',')
            inputList = UtilMgr.cleanItem(inputList)
        else:
            SysMgr.printErr("no input for path")
            sys.exit(0)

        # get config path #
        if SysMgr.getOption('C'):
            config = SysMgr.confFileName
        else:
            config = None

        # 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
            )



    @staticmethod
    def doCpuTest():
        random = SysMgr.getPkg('random')

        def _cputask(idx, load):
            try:
                SysMgr.setDefaultSignal()
            except:
                pass

            # print profile #
            tid = SysMgr.syscall('gettid')
            SysMgr.printWarn(
                "started %sth %s(%s)" % \
                    (UtilMgr.convNum(idx), SysMgr.comm, tid))

            # run loop #
            while 1:
                if load == 0:
                    signal.pause()
                else:
                    sorted([random.random() for i in range(1<<10)])

        # get the number of task and load #
        try:
            if SysMgr.hasMainArg():
                value = SysMgr.getMainArg().split(':')
            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 = 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(0)

        # check target type #
        if SysMgr.processEnable:
            taskType = 'process'
        else:
            taskType = 'thread'

        # check target number #
        if nrTask > 1:
            taskstr = '%s %s' % (UtilMgr.convNum(nrTask), taskType)
        else:
            taskstr = 'a %s' % taskType

        # run tasks #
        limitInfo = dict()
        try:
            # process #
            if SysMgr.processEnable:
                for idx in range(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 range(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(0)

        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.keys()):
            for item in SysMgr.affinityFilter:
                SysMgr.setAffinity(item[1], [pid])

        # set alarm #
        signal.signal(signal.SIGALRM, SysMgr.onAlarm)
        signal.alarm(SysMgr.intervalEnable)

        # ignore SIGCHLD #
        signal.signal(signal.SIGCHLD, signal.SIG_DFL)

        # limit CPU usage of tasks #
        SysMgr.doLimitCpu(limitInfo, verbose=False)



    @staticmethod
    def doMemTest():
        def _getMeminfo():
            # save mem info #
            try:
                memBuf = None
                SysMgr.memFd.seek(0)
                memBuf = SysMgr.memFd.readlines()
            except:
                try:
                    memPath = "%s/%s" % (SysMgr.procPath, 'meminfo')
                    SysMgr.memFd = open(memPath, 'r')

                    memBuf = SysMgr.memFd.readlines()
                except:
                    SysMgr.printOpenWarn(memPath)

            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:
                memAvail = conv(memData['MemAvailable'] << 10)
                memAvailPer = \
                    (memData['MemAvailable'] / float(memData['MemTotal'])) * 100
                memAvailPer = '%.1f%%' % memAvailPer
            except:
                memAvail = memAvailPer = '-'
            memCache = conv(memData['Cached'] << 10)
            swapTotal = conv(memData['SwapTotal'] << 10)
            swapFree = conv(memData['SwapFree'] << 10)
            if swapTotal == '0':
                swapFreePer = 100.0
            else:
                swapFreePer = \
                    (memData['SwapFree'] / float(memData['SwapTotal'])) * 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 #
            try:
                vmBuf = None
                SysMgr.vmstatFd.seek(0)
                vmBuf = SysMgr.vmstatFd.readlines()
            except:
                try:
                    vmstatPath = "%s/%s" % (SysMgr.procPath, 'vmstat')
                    SysMgr.vmstatFd = open(vmstatPath, 'r')
                    vmBuf = SysMgr.vmstatFd.readlines()
                except:
                    SysMgr.printOpenWarn(vmstatPath)

            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():
            # save zone info #
            try:
                memBuf = None
                SysMgr.zoneFd.seek(0)
                memBuf = SysMgr.zoneFd.readlines()
            except:
                try:
                    memPath = "%s/%s" % (SysMgr.procPath, 'zoneinfo')
                    SysMgr.zoneFd = open(memPath, 'r')

                    memBuf = SysMgr.zoneFd.readlines()
                except:
                    SysMgr.printOpenWarn(memPath)

            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] = dict()
                elif item == 'pages' and zl[1] == 'free':
                    memData[zone]['free'] = long(zl[2])
                elif item == 'min' or item == 'low' or item == 'high' or \
                    item == 'spanned' or item == 'present' or item == '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

            zonestr = '\n'
            for zone, items in sorted(memData.items()):
                zonestr += '[%9s] ' % zone
                for name, val in sorted(items.items(),
                    key=lambda e: long(e[1]) if type(e[1]) != list else sys.maxsize):
                    if name != 'protection':
                        zonestr += "%s:%7s, " % (name, conv(val << 12))

                if 'protection' in items:
                    zonestr += "%s: %7s" % \
                        ('protection', ', '.join(items['protection']))
                    zonestr += ", "

                zonestr = zonestr + '\n'

            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)

            # threshold list #
            threshold = \
                ['FGAPP', 'VISAPP', 'SECSER', 'HIDAPP', 'CONPRO', 'EMPAPP']

            if not memBuf:
                return ''

            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(
                    "fail to allocate memory", True)
                sys.exit(0)

            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("fail to get memory stat", True)
                return

            # get vmstat #
            try:
                vmstr = _getVminfo()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("fail to get virtual memory stat", True)
                return

            # get zone stat #
            try:
                zonestr = _getZoneinfo()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("fail to get zone memory stat", True)
                return

            # get LMK stat #
            try:
                lmkstr = _getLMKinfo()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn("fail 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)
                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(
                        "fail to get memory size of Guider")
                    sys.exit(0)

                # get memory size #
                rssIdx = ConfigMgr.STATM_TYPE.index("RSS")
                statstr = "RSS: %s" % conv(long(mlist[rssIdx]) << 12)

            # get new task #
            newTasks = set(procs.keys()) - set(prevProcs.keys())
            if newTasks:
                newstr = '\n[%9s]' % 'NEW'
                for pid in sorted(newTasks):
                    comm = procs[pid]['stat'][obj.commIdx][1:-1]
                    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.keys()) - set(procs.keys())
            if dieTasks:
                diestr = '\n[%9s]' % 'DIE'
                for pid in sorted(dieTasks):
                    comm = prevProcs[pid]['stat'][obj.commIdx][1:-1]
                    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] %s' % ('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.getMainArg().split(':')
            else:
                value = ['100M']

            # parse option #
            if len(value) == 3:
                size, interval, count = value
            elif len(value) == 2:
                size, interval = value
                count = long(0)
            elif len(value) == 1:
                size = value[0]
                interval = count = long(0)
            else:
                raise Exception('wrong arguments')

            if interval:
                interval = UtilMgr.convUnit2Time(interval)
            else:
                interval = long(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(0)

        # set alarm #
        signal.signal(signal.SIGALRM, SysMgr.onAlarm)
        signal.alarm(SysMgr.intervalEnable)

        # create task object #
        obj = TaskAnalyzer(onlyInstance=True)
        obj.saveProcStat()
        pid = SysMgr.pid

        pidList = list()
        if count > 0:
            for idx in range(0, count):
                try:
                    # create a pipe #
                    rd, wr = os.pipe()

                    pid = SysMgr.createProcess()
                except SystemExit:
                    pass
                except:
                    SysMgr.printErr(
                        "failed to start process", True)
                    sys.exit(0)

                if pid == 0:
                    try:
                        _allocMemory(size, wr)
                    except SystemExit:
                        sys.exit(0)
                    except:
                        SysMgr.printErr("fail to alloc memory", True)
                        sys.exit(0)
                else:
                    pidList.append(pid)
                    os.close(wr)

                    os.read(rd, 1)
                    os.close(rd)

                    # print stats #
                    try:
                        _printUsage(obj, pid, size)
                    except SystemExit:
                        sys.exit(0)
                    except:
                        SysMgr.printErr(
                            "fail to print memory stats", reason=True)

                time.sleep(interval)
        elif interval > 0:
            while 1:
                # create a pipe #
                rd, wr = os.pipe()

                try:
                    pid = SysMgr.createProcess()
                except SystemExit:
                    pass
                except:
                    SysMgr.printErr(
                        "failed to start process", True)
                    sys.exit(0)

                if pid == 0:
                    try:
                        _allocMemory(size, wr)
                    except SystemExit:
                        sys.exit(0)
                    except:
                        SysMgr.printErr("fail to alloc memory", True)
                        sys.exit(0)
                else:
                    pidList.append(pid)
                    os.close(wr)

                    os.read(rd, 1)
                    os.close(rd)

                    # print stats #
                    try:
                        _printUsage(obj, pid, size)
                    except SystemExit:
                        sys.exit(0)
                    except:
                        SysMgr.printErr(
                            "fail to print memory stats", reason=True)

                time.sleep(interval)
        else:
            try:
                interval = 1

                pidList.append(pid)

                _allocMemory(size, ret=True)

                # print stats #
                try:
                    _printUsage(obj, pid, size)
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(
                        "fail to print memory stats", reason=True)

                time.sleep(interval)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("fail to alloc memory", True)
                sys.exit(0)

        # wait for childs #
        if len(pidList) > 0:
            while 1:
                try:
                    _printUsage(obj, pid, size, alloc=False)
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(
                        "fail to print memory stats", reason=True)

                time.sleep(interval)



    @staticmethod
    def doPstree(isProcess=True):
        SysMgr.printLogo(big=True, onlyFile=True)

        obj = TaskAnalyzer(onlyInstance=True)

        obj.saveSystemStat()

        TaskAnalyzer.printProcTree(obj.procData, title=True)



    @staticmethod
    def doCompress():
        SysMgr.printFd = None
        SysMgr.setStream()
        SysMgr.setDefaultSignal()

        # check input #
        if SysMgr.hasMainArg():
            infile = SysMgr.getMainArg()
        else:
            SysMgr.printErr("no path for compression")
            sys.exit(0)

        # check file #
        if not os.path.isfile(infile):
            SysMgr.printErr("wrong path '%s' for decompression" % infile)
            sys.exit(0)

        # 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(0)

        # check exist file #
        if os.path.exists(outfile):
            SysMgr.backupFile(outfile)

        # 1MB chunk size #
        chunkSize = 1 << 20

        # get compressor #
        compressor = SysMgr.getPkg('gzip')

        # 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')

        SysMgr.printInfo(
            "start compressing %s[%s] to %s" % \
                (infile, infileSizeStr, outfile))

        while 1:
            chunk = infd.read(chunkSize)
            if not chunk:
                outfd.flush()
                break

            outfd.write(chunk)

            wroteSize += len(chunk)
            UtilMgr.printProgress(wroteSize, fileSize)

        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))



    @staticmethod
    def doDecompress():
        SysMgr.printFd = None
        SysMgr.setStream()
        SysMgr.setDefaultSignal()

        # check input #
        if SysMgr.hasMainArg():
            infile = SysMgr.getMainArg()
        else:
            SysMgr.printErr("no path for decompression")
            sys.exit(0)

        # check file #
        if not os.path.isfile(infile):
            SysMgr.printErr("wrong path '%s' for decompression" % infile)
            sys.exit(0)

        # 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(0)

        # check exist file #
        if os.path.exists(outfile):
            SysMgr.backupFile(outfile)

        # 1MB chunk size #
        chunkSize = 1 << 20

        # get compressor #
        compressor = SysMgr.getPkg('gzip')

        # 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')

        SysMgr.printInfo(
            "start decompressing %s[%s] to %s" % \
                (infile, infileSizeStr, outfile))

        while 1:
            chunk = infd.read(chunkSize)
            if not chunk:
                outfd.flush()
                break

            outfd.write(chunk)

            wroteSize += len(chunk)
            UtilMgr.printProgress(wroteSize, fileSize)

        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))




    @staticmethod
    def doPrintSig():
        SysMgr.printLogo(big=True, onlyFile=True)

        # check target #
        if not SysMgr.filterGroup:
            SysMgr.printErr("no input for PID or COMM")
            sys.exit(0)

        # get pid list #
        pids = []
        for item in SysMgr.filterGroup:
            pids += SysMgr.getPids(item)
        if not pids:
            SysMgr.printErr("no target thread")

        tobj = TaskAnalyzer(onlyInstance=True)
        for pid in 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 #
            SysMgr.printPipe(
                '\n[Signal Status Info] %s\n%s' % (proc, twoLine))

            # get signal info #
            printed = False
            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 range(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])

                if not sigList:
                    continue

                printed = True

                SysMgr.printPipe(
                    '%s: %s' % (name, '|'.join(sigList)))

            if 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.printProcUsage()
        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, verbose=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 = long(0)
        nowTime = None
        taskList = {}

        def _openStatFd(tid, isProcess):
            if isProcess:
                statPath = "%s/%s/stat" % (SysMgr.procPath, tid)
            else:
                statPath = "%s/%s/task/%s/stat" % \
                    (SysMgr.procPath, tid, tid)

            try:
                return open(statPath, 'r')
            except:
                return None

        def _getTaskStat(fd):
            try:
                fd.seek(0)
                statBuf = fd.read()
            except:
                return None

            # convert string to list #
            statList = statBuf.split()

            # merge comm parts that splited by space #
            statList = SysMgr.mergeCommStat(statList, COMM_IDX)

            comm = statList[COMM_IDX][1:-1]
            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': long(0), 'prevTick': long(0),
                'ticks': long(0), 'running': True}

            if isProcess:
                taskList[task]['group'] = SysMgr.getThreadList(task)
                if not taskList[task]['group']:
                    SysMgr.printErr(
                        "fail to get thread list of '%s' process" % task)
                    return

                taskList[task]['fd'] = _openStatFd(task, isProcess)
                if not taskList[task]['fd']:
                    SysMgr.printErr(
                        "fail 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(
                        "fail to get stats of %s thread" % task)
                    return

        # set alarm #
        signal.signal(signal.SIGALRM, SysMgr.onAlarm)
        signal.alarm(SysMgr.intervalEnable)

        try:
            while 1:
                # backup time #
                prevTime = nowTime

                # get current time #
                nowTime = time.time()

                # check task #
                if not taskList:
                    SysMgr.printErr(
                        "fail to find task to limit CPU usage")
                    return

                for tid in list(taskList.keys()):
                    val = taskList[tid]
                    val['prevTick'] = val['nowTick']

                    # get current tick #
                    stat = _getTaskStat(val['fd'])
                    if not stat:
                        SysMgr.printErr(
                            "fail 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 = long(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 verbose:
                            SysMgr.printInfo((
                                "limited CPU usage of %s(%s) %s to %s%%, "
                                "it used %s%%") % \
                                (val['comm'], tid, tasktype,
                                val['per'], val['ticks']))

                        val['ticks'] = long(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:
                                    os.kill(tid, signal.SIGSTOP)
                                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:
                                    os.kill(tid, signal.SIGCONT)
                                except SystemExit:
                                    raise Exception('exit')
                                except:
                                    SysMgr.printSigError(tid, 'SIGCONT')

                time.sleep(SLEEP_SEC)
        except:
            pass
        finally:
            for task, val in taskList.items():
                for tid in val['group']:
                    try:
                        os.kill(tid, signal.SIGCONT)
                    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:
                kill(pid, sig)
            except:
                SysMgr.printSigError(pid, 'SIGKILL')



    @staticmethod
    def convPidList(
        procList, isThread=False, exceptMe=False,
        sibling=False, inc=False, cache=False):

        if not procList:
            return

        targetList = []

        # get pids #
        for pid in procList:
            if not inc and '*' in pid:
                inc = True
                pid = pid.replace('*', '')

            taskList = SysMgr.getPids(
                pid, isThread, sibling, False, inc, 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, wait=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

                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

        # convert pid list #
        if SysMgr.filterGroup:
            argList = SysMgr.filterGroup
        elif argList:
            try:
                argList = (''.join(argList)).split(',')
            except SystemExit:
                sys.exit(0)
            except:
                pass

        isPrinted = False

        # convert comm to pid #
        while 1:
            targets = SysMgr.convPidList(
                argList, isThread=isThread, exceptMe=True, cache=wait)
            if targets:
                targetList = targets
            else:
                targetList = argList

            # check break condition #
            if not wait:
                break
            elif targets:
                break

            if not isPrinted:
                SysMgr.printInfo(
                    "start busy-waiting for '%s'" % ', '.join(argList))
                isPrinted = True

        # send signal #
        SysMgr.sendSignalProcs(sig, targetList, isThread=isThread)



    @staticmethod
    def sendSignalProcs(
        nrSig, pidList=[], isThread=False, verbose=True, exceptList=[]):
        def _kill(pid, nrSig):
            if isThread:
                return SysMgr.syscall('tkill', pid, nrSig)
            else:
                return os.kill(pid, nrSig)

        myPid = str(SysMgr.pid)
        SIG_LIST = ConfigMgr.SIG_LIST
        exceptList = list(map(long, exceptList))

        if isThread:
            taskType = 'thread'
        else:
            taskType = 'process'

        nrProc = long(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(
                        "fail 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 verbose:
                        SysMgr.printInfo(
                            "sent signal %s to %s(%s) %s" % \
                                (SIG_LIST[nrSig], comm, pid, taskType))
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printSigError(pid, SIG_LIST[nrSig], False)

            if isSent:
                return

        # get my comm #
        myComm = SysMgr.getComm(SysMgr.pid)
        if not myComm:
            SysMgr.printErr(
                "fail to get my comm", True)
            sys.exit(0)

        # get my cmdline #
        myCmdline = SysMgr.getCmdline(SysMgr.pid)
        if myCmdline:
            myCmdline = myCmdline.split()
        else:
            SysMgr.printErr(
                "fail to get my cmdline", True)
            sys.exit(0)

        # handle Guider processes #
        nrProc = long(0)
        for pid in os.listdir(SysMgr.procPath):
            if myPid == pid or not pid.isdigit():
                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 verbose:
                        if SysMgr.checkMode('start') and waitStatus:
                            SysMgr.printInfo(
                                "started %s(%s) to profile" % (comm, pid))
                        else:
                            SysMgr.printInfo(
                                "sent signal %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 verbose:
                        SysMgr.printInfo(
                            "sent signal %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 verbose:
            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(0)

        SysMgr.checkRootPerm()

        schedGroup = value.split(',')
        schedGroup = UtilMgr.cleanItem(schedGroup)
        for item in schedGroup:
            lastIdx = 4
            schedSet = item.split(':')

            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
                targetList = SysMgr.getPids(task, sibling=sibling)
                targetList = list(map(long, targetList))
                if not targetList:
                    SysMgr.printWarn(
                        "no thread related to '%s'" % task)

                # change priority for tasks #
                for task in 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:
                        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(0)



    @staticmethod
    def setDeadlinePriority(pid, runtime, deadline, period):
        # 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((
                    "fail to set priority for %s(%s) "
                    "because kernel version %g is lesser than 3.14") % \
                    (comm, pid, ver))
                return -1
        except:
            err = sys.exc_info()[1]
            SysMgr.printWarn(
                ("fail 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),
        ]

        # get the number of sched_setattr syscall #
        nrSyscall = ConfigMgr.sysList.index('sys_sched_setattr')

        # define syscall parameters for sched_setattr() #
        SysMgr.libcObj.syscall.argtypes = \
            [c_int, c_int, POINTER(struct_sched_attr), c_uint]
        SysMgr.libcObj.syscall.restype = c_int

        # 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((
                "fail to set 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.libcObj.syscall(
            nrSyscall, pid, pointer(sched_attr), 0)

        # check return value #
        if ret == 0:
            SysMgr.printInfo((
                "changed the priority for %s(%s) to "
                "runtime(%d)/deadline(%d)/period(%d)[D]") % \
                (comm, pid, runtime, deadline, period))
        else:
            SysMgr.printErr((
                "fail to set 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(
                        'fail 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(
                "fail 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 setPriority(
        pid, policy, pri, runtime=0, deadline=0, period=0, verb=True):
        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 == 'I' or upolicy == 'C' or upolicy == 'B':
                argPriority = long(0)
            else:
                argPriority = pri

            # prepare for libc call #
            if not SysMgr.guiderObj:
                argPriority = c_int(argPriority)

            # set scheduler policy #
            if not SysMgr.guiderObj:
                ret = SysMgr.libcObj.sched_setscheduler(
                    pid, argPolicy, byref(argPriority))
            else:
                func = SysMgr.guiderObj.sched_setscheduler # pylint: disable=no-member
                ret = func(pid, argPolicy, argPriority)

            if ret != 0:
                policy = upolicy
                raise Exception('no sched_setscheduler')

            # set nice value #
            if upolicy == 'C' or upolicy == 'B':
                if not SysMgr.guiderObj:
                    argPriority = c_int(pri)
                    ret = SysMgr.libcObj.setpriority(
                        0, pid, argPriority)
                else:
                    argPriority = pri
                    func = SysMgr.guiderObj.setpriority # pylint: disable=no-member
                    ret = func(0, pid, argPriority)

                if ret != 0:
                    policy = upolicy
                    raise Exception('no setpriority')

            if verb:
                SysMgr.printInfo(
                    'changed priority for %s(%s) to %d[%s]' % \
                        (comm, pid, pri, upolicy))
        except SystemExit:
            sys.exit(0)
        except:
            err = "fail to set priority for %s(%s) to %s[%s]" % \
                (comm, pid, pri, upolicy)
            SysMgr.printWarn(err, always=True, reason=True)
            return



    @staticmethod
    def setTTYAuto(setRows=True, setCols=True):
        if not SysMgr.isLinux:
            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)

        # 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(
                "fail to remove buffer for fd %s" % fd, reason=True)



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

        # reset terminal for recovery #
        try:
            SysMgr.getPkg('subprocess').Popen(
                ['stty', 'sane'],
                stdout=open(os.devnull, 'wb'),
                stderr=open(os.devnull, 'wb'))
        except SystemExit:
            sys.exit(0)
        except:
            pass



    @staticmethod
    def setTTY(rows, cols):
        if not SysMgr.isLinux:
            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()

            SysMgr.printInfo("set terminal size [ %sx%s ]" % \
                (SysMgr.ttyRows, SysMgr.ttyCols))

            return
        except:
            pass

        # set terminal size by command #
        try:
            if not UtilMgr.which('stty'):
                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:
            return



    @staticmethod
    def getTty(update=False):
        if not SysMgr.isLinux:
            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:
            pass

        # update tty info by stty #
        try:
            if not UtilMgr.which('stty'):
                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:
            SysMgr.printWarn(
                "fail 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(
                "fail 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



    def saveSysStat(self, initialized=True):
        SysMgr.updateUptime()

        # update resource usage #
        self.updateMemInfo()
        self.updateStorageInfo(isGeneral=True)
        self.updateNetworkInfo()
        self.updateIPCInfo()
        self.saveMacAddr()

        # save system/user 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()

            # os specific info #
            self.saveWebOSInfo()
            self.saveLinuxInfo()

            # write 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(
                "fail to save CPU info", reason=True)



    def saveCpuCacheInfo(self):
        cpuPath = '/sys/devices/system/cpu'

        try:
            corelist = os.listdir(cpuPath)

            for core in corelist:
                cachePath = '/sys/devices/system/cpu/%s/cache' % core

                self.cpuCacheInfo[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()

                        self.cpuCacheInfo[core] = '%sL%s(%s)=%s   ' % \
                            (self.cpuCacheInfo[core], level[:-1],
                            type[:-1], size[:-1])
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

                if not self.cpuCacheInfo[core]:
                    del self.cpuCacheInfo[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(
                "fail to save deice info", reason=True)



    def saveStorageInfo(self, isGeneral):
        blockDir = '/sys/class/block'
        partFile = '%s/partitions' % SysMgr.procPath

        # update disk data #
        SysMgr.updateDiskStats()

        # 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 #
        self.mountData = SysMgr.getMountData()

        # 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

                    with open(sizePath, 'r') as sizeFd:
                        size = sizeFd.readline()[:-1]

                    if any(char.isdigit() for char in subdirname):
                        with open(startPath, 'r') as startFd:
                            start = startFd.readline()[:-1]
                    else:
                        start = long(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)
                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(
                "fail 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.writeCmd("../buffer_size_kb", bufferSize)



    @staticmethod
    def copyPipeToFile(pipePath, filePath):
        try:
            pd = open(pipePath, 'r')
        except:
            SysMgr.printOpenErr(pipePath)
            sys.exit(0)

        try:
            # use os.O_DIRECT | os.O_RDWR | os.O_TRUNC | os.O_CREAT #
            fd = open(filePath, 'w')
        except:
            SysMgr.printOpenErr(filePath)
            sys.exit(0)

        pageSize = SysMgr.pageSize

        while 1:
            try:
                # read each 4k data through pipe #
                buf = pd.read(pageSize)

                fd.write(buf)

                # print to console #
                if SysMgr.printStreamEnable:
                    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.sysInstance.saveSysStat()

                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)

                SysMgr.printInfo(
                    "wrote data to '%s' [%s] successfully" % \
                    (path, UtilMgr.getFileSize(path)))

                return



    @staticmethod
    def getDebugfsPath():
        try:
            lines = SysMgr.procReadlines('mounts')
        except:
            SysMgr.printErr(
                "fail 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 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.keys())

        for pid in childList:
            if not SysMgr.isAlive(pid):
                try:
                    os.waitpid(pid, os.WNOHANG)
                except:
                    pass

                SysMgr.childList.pop(pid, None)



    @staticmethod
    def killChilds(sig=None, childs=None, wait=False, group=False):
        if not sig:
            sig = ConfigMgr.SIGKILL

        SysMgr.updateChildList()

        if childs is None:
            childs = list(SysMgr.childList.keys())

        # kill childs #
        SysMgr.terminateTasks(childs, sig, group)

        # remove child list #
        SysMgr.clearChildList()

        if not wait:
            return

        # wait for termination for all childs #
        childs = set(map(str, childs))
        while 1:
            # get all task list #
            tasks = set(os.listdir(SysMgr.procPath))

            # check terminated tasks #
            termTasks = childs - tasks
            if termTasks == childs:
                break

            remainTasks = childs - termTasks

            # wait for task termination #
            try:
                monFiles = ['/proc/%s/comm' % tid for tid in remainTasks]
                SysMgr.inotify(monFiles)
            except SystemExit:
                sys.exit(0)
            except:
                pass



    @staticmethod
    def removeExitFunc(func, args=None):
        newList = list()
        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

        # call functions registered #
        for func, args in SysMgr.exitFuncList:
            try:
                func(*args)
            except SystemExit:
                sys.exit(0)
            except OSError:
                pass
            except:
                SysMgr.printErr(
                    "fail to execute %s" % func, True)

        # destroy termination hooks #
        del SysMgr.exitFuncList

        # release all resources #
        SysMgr.releaseResource()

        os._exit(0)



    @staticmethod
    def releaseResource():
        # kill child tasks #
        SysMgr.killChilds()

        # 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:
            SysMgr.printFd.flush()

            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" % \
                (SysMgr.printFd.name, fsize))

            SysMgr.printFd.close()
        except SystemExit:
            sys.exit(0)
        except:
            pass
        finally:
            SysMgr.printFd = None



    @staticmethod
    def clearTraceBuffer():
        SysMgr.printInfo(
            r'clear trace buffer... ', suffix=False, prefix=False)
        SysMgr.writeCmd("../trace", '')
        SysMgr.printInfo("[done]", prefix=False, notitle=True)



    @staticmethod
    def clearTraceFilter():
        SysMgr.writeCmd("../set_ftrace_filter", '')
        SysMgr.writeCmd("../set_ftrace_pid", '')
        SysMgr.writeCmd("../set_ftrace_notrace", '')
        SysMgr.writeCmd("../set_event", '')
        SysMgr.writeCmd("../set_event_pid", '')
        SysMgr.writeCmd("../set_graph_function", '')
        SysMgr.writeCmd("../set_graph_notrace", '')
        SysMgr.writeCmd("../uprobe_events", '')
        SysMgr.writeCmd("../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["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["filemap/mm_filemap_add_to_page_cache"] = 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
        self.cmdList["block/block_rq_complete"] = bioFlag
        self.cmdList["writeback/writeback_dirty_page"] = bioFlag
        self.cmdList["writeback/wbc_writepage"] = bioFlag

        # disk #
        diskFlag = sm.diskEnable
        self.cmdList["f2fs/f2fs_sync_file_enter"] = diskFlag
        self.cmdList["f2fs/f2fs_sync_file_exit"] = diskFlag
        self.cmdList["f2fs/f2fs_write_begin"] = diskFlag
        self.cmdList["f2fs/f2fs_write_end"] = diskFlag
        self.cmdList["ext4/ext4_da_write_begin"] = diskFlag
        self.cmdList["ext4/ext4_da_write_end"] = diskFlag
        self.cmdList["ext4/ext4_sync_file_enter"] = diskFlag
        self.cmdList["ext4/ext4_sync_file_exit"] = diskFlag

        # network #
        netFlag = sm.networkEnable
        self.cmdList["net/net_dev_xmit"] = netFlag
        self.cmdList["net/netif_receive_skb"] = 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_lock"] = binderFlag
        self.cmdList["binder/binder_locked"] = binderFlag
        self.cmdList["binder/binder_unlock"] = binderFlag
        self.cmdList["binder/binder_transaction"] = binderFlag
        self.cmdList["binder/binder_transaction_received"] = 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

        # i2c #
        self.cmdList["i2c"] = sm.i2cEnable



    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.readCmdVal('../tracing_on')
        if stat == '0':
            pass
        elif SysMgr.forceEnable:
            # write command to stop tracing #
            SysMgr.writeCmd('../tracing_on', '0')
        elif stat == '1':
            # no running Guider process except for myself #
            if SysMgr.getBgProcCount(cache=True) <= 1:
                res = SysMgr.readCmdVal('enable')
                # default status #
                if res == '0':
                    pass
                # tracing status #
                else:
                    SysMgr.printErr(
                        "fail to start tracing because "
                        "tracing is already in progress on system\n"
                        "\tit would be stopped so that try to record again")
                    sys.exit(0)
            else:
                SysMgr.printErr(
                    "fail to start tracing because "
                    "another Guider is already running")
                os._exit(0)

        # clean up ring buffer for tracing #
        SysMgr.clearTraceBuffer()

        # clear trace filter #
        SysMgr.clearTraceFilter()



    def startTracing(self):
        # write command to start tracing #
        SysMgr.writeCmd('../tracing_on', '1')

        # write start event #
        SysMgr.writeEvent("EVENT_START", False)



    def enableEvents(self):
        for cmd, value in self.cmdList.items():
            if value:
                SysMgr.writeCmd('%s/enable' % cmd, '1')



    def startRecording(self):
        def _printStartLog():
            # write user command #
            SysMgr.writeTraceCmd('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.writeCmd(
                        'signal/signal_deliver/filter', commonFilter)
                    SysMgr.writeCmd(
                        'signal/signal_generate/filter', genFilter)

        def _startFuncGraph(self):
            # check save option #
            if not SysMgr.outputFile:
                SysMgr.printErr(
                    "use also -s option to save data")
                sys.exit(0)

            # reset events #
            SysMgr.stopRecording()

            # set function_graph tracer #
            if SysMgr.writeCmd(
                '../current_tracer', 'function_graph') < 0:
                SysMgr.printErr(
                    "enable CONFIG_FUNCTION_GRAPH_TRACER kernel option")
                sys.exit(0)

            # apply filter #
            for pid in SysMgr.filterGroup:
                try:
                    pid = str(long(pid))
                    SysMgr.writeCmd('../set_ftrace_pid', pid, True)
                except:
                    SysMgr.printErr((
                        "fail to add %s to PID filter "
                        "for function graph tracing") % pid)
                    sys.exit(0)

            optPath = '../trace_options'
            SysMgr.writeCmd(optPath, 'nofuncgraph-proc')
            SysMgr.writeCmd(optPath, 'funcgraph-abstime')
            SysMgr.writeCmd(optPath, 'funcgraph-overhead')
            SysMgr.writeCmd(optPath, 'funcgraph-duration')
            SysMgr.writeCmd(
                '../max_graph_depth', str(SysMgr.funcDepth))

            if not SysMgr.customCmd:
                SysMgr.writeCmd('../set_ftrace_filter', '')
            else:
                params = ' '.join(SysMgr.customCmd)
                SysMgr.printStat(
                    "wait for setting function filter [ %s ]" % params)
                if SysMgr.writeCmd(
                    '../set_ftrace_filter', params) < 0:
                    SysMgr.printErr(
                        "fail to set function filter")
                    sys.exit(0)
                else:
                    SysMgr.printStat(
                        "finished function filter [ %s ]" % params)

            # start tracing #
            self.startTracing()



        # check root permission #
        if not SysMgr.isRoot():
            SysMgr.printErr(
                "fail to get root permission to trace system")
            sys.exit(0)

        # 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(0)

        # write user command #
        SysMgr.writeTraceCmd('BEFORE')

        # set size of trace buffer per core #
        if SysMgr.bufferSize == -1:
            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(
                "fail 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.writeCmd('../saved_cmdlines_size', '32767')

        # set log format #
        SysMgr.writeCmd('../trace_options', 'noirq-info')
        SysMgr.writeCmd('../trace_options', 'noannotate')
        SysMgr.writeCmd('../trace_options', 'print-tgid')
        SysMgr.writeCmd('../trace_options', 'record-tgid')
        SysMgr.writeCmd('../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:
                    cmd = "%s%s" % (cmd, SysMgr.getPidFilter())
                    if not cmd:
                        raise Exception('no command')
                except:
                    SysMgr.printErr(
                        "wrong TID %s" % SysMgr.filterGroup)
                    sys.exit(0)

            # trace except for swapper threads #
            if cmd == "":
                cmd = "(common_pid != 0)"

            if SysMgr.userEnable:
                SysMgr.writeCmd('../trace_options', 'userstacktrace')
                SysMgr.writeCmd('../trace_options', 'sym-userobj')
            else:
                SysMgr.writeCmd('../trace_options', 'nouserstacktrace')
                SysMgr.writeCmd('../trace_options', 'nosym-userobj')

            SysMgr.writeCmd('../trace_options', 'sym-addr')
            SysMgr.writeCmd('../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.writeCmd('signal/filter', sigCmd)

            # CPU events #
            if SysMgr.cpuEnable:
                addr = SysMgr.getKerAddr('tick_sched_timer')
                if addr:
                    SysMgr.writeCmd(
                        'timer/hrtimer_start/filter',
                        '%s && function == 0x%s' % (cmd, addr))
                SysMgr.writeCmd('timer/hrtimer_start/enable', '1')
            else:
                SysMgr.writeCmd('timer/hrtimer_start/enable', '0')

            # page events #
            if SysMgr.memEnable:
                SysMgr.writeCmd('kmem/mm_page_alloc/filter', cmd)

                if SysMgr.writeCmd('kmem/mm_page_free/filter', cmd) < 0:
                    SysMgr.writeCmd(
                        'kmem/mm_page_free_direct/filter', cmd)

                SysMgr.writeCmd('kmem/mm_page_alloc/enable', '1')

                if SysMgr.writeCmd('kmem/mm_page_free/enable', '1') < 0:
                    SysMgr.writeCmd(
                        'kmem/mm_page_free_direct/enable', '1')
            else:
                SysMgr.writeCmd('kmem/mm_page_alloc/enable', '0')

                if SysMgr.writeCmd('kmem/mm_page_free/enable', '0') < 0:
                    SysMgr.writeCmd(
                        'kmem/mm_page_free_direct/enable', '0')

            # all syscall events #
            if SysMgr.sysEnable:
                if SysMgr.heapEnable or SysMgr.lockEnable:
                    SysMgr.printErr(
                        "fail to enable syscall events with other events")
                    sys.exit(0)
                elif not SysMgr.syscallList:
                    pass
            else:
                # heap events #
                if SysMgr.heapEnable:
                    if SysMgr.arch == 'arm':
                        mmapId = ConfigMgr.sysList.index('sys_mmap2')
                    else:
                        mmapId = ConfigMgr.sysList.index('sys_mmap')

                    brkId = ConfigMgr.sysList.index('sys_brk')

                    SysMgr.syscallList.append(mmapId)
                    SysMgr.syscallList.append(brkId)

                    self.cmdList["raw_syscalls"] = True

                # lock events #
                if SysMgr.lockEnable:
                    futexId = ConfigMgr.sysList.index('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.writeCmd('block/block_bio_queue/filter', blkCmd)
                SysMgr.writeCmd('block/block_bio_queue/enable', '1')
                SysMgr.writeCmd(
                    'writeback/writeback_dirty_page/filter', cmd)
                SysMgr.writeCmd(
                    'writeback/writeback_dirty_page/enable', '1')
                SysMgr.writeCmd('writeback/wbc_writepage/filter', cmd)
                SysMgr.writeCmd('writeback/wbc_writepage/enable', '1')
            else:
                SysMgr.writeCmd('block/block_bio_queue/enable', '0')
                SysMgr.writeCmd(
                    'writeback/writeback_dirty_page/enable', '0')
                SysMgr.writeCmd('writeback/wbc_writepage/enable', '0')

            # special events #
            _writeCommonCmd()

            # write user command #
            SysMgr.writeTraceCmd('AFTER')

            # start tracing #
            self.startTracing()

            _printStartLog()
            return

        #-------------------- THREAD MODE --------------------#
        def _applySchedFilter():
            cmd = "prev_pid == 0 || next_pid == 0 || "

            # apply filter #
            for comm in list(SysMgr.filterGroup):
                # comm #
                cmd += \
                    "prev_comm == \"*%s*\" || next_comm == \"*%s*\" || " % \
                    (comm, comm)

                # tid #
                try:
                    pid = long(comm)
                    cmd += "prev_pid == \"%s\" || next_pid == \"%s\" || " % \
                        (pid, pid)
                except:
                    try:
                        ldir = comm.find('>')
                        if ldir == 0:
                            cmd += "prev_pid >= %s || " % long(comm[1:])
                            cmd += "next_pid >= %s || " % long(comm[1:])
                        elif ldir == len(comm) - 1:
                            cmd += "prev_pid <= %s || " % long(comm[:-1])
                            cmd += "next_pid <= %s || " % long(comm[:-1])

                        rdir = comm.find('<')
                        if rdir == 0:
                            cmd += "prev_pid <= %s || " % long(comm[1:])
                            cmd += "next_pid <= %s || " % long(comm[1:])
                        elif rdir == len(comm) - 1:
                            cmd += "prev_pid >= %s || " % long(comm[:-1])
                            cmd += "next_pid >= %s || " % long(comm[:-1])
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass

            cmd = cmd[0:cmd.rfind("||")]
            if SysMgr.writeCmd('sched/sched_switch/filter', cmd) < 0:
                SysMgr.printErr(
                    "fail to set filter [ %s ]" % \
                    ' '.join(SysMgr.filterGroup))
                sys.exit(0)

        # sched events #
        if self.cmdList["sched/sched_switch"]:
            if SysMgr.filterGroup:
                _applySchedFilter()
            else:
                SysMgr.writeCmd('sched/sched_switch/filter', '0')

            if SysMgr.writeCmd('sched/sched_switch/enable', '1') < 0:
                SysMgr.printErr("fail to enable sched events")
                sys.exit(0)

        # build sched filter #
        if SysMgr.filterGroup:
            cmd = ""

            # apply filter #
            for comm in list(SysMgr.filterGroup):
                cmd += "comm == \"*%s*\" || " % (comm)
                try:
                    pid = long(comm)
                    cmd += "pid == \"%s\" || " % (pid)
                except:
                    try:
                        ldir = comm.find('>')
                        if ldir == 0:
                            cmd += "pid >= %s || " % long(comm[1:])
                        elif ldir == len(comm) - 1:
                            cmd += "pid <= %s || " % long(comm[:-1])

                        rdir = comm.find('<')
                        if rdir == 0:
                            cmd += "pid <= %s || " % long(comm[1:])
                        elif rdir == len(comm) - 1:
                            cmd += "pid >= %s || " % long(comm[:-1])
                    except:
                        pass

            cmd = cmd[0:cmd.rfind("||")]
        else:
            cmd = "0"

        if self.cmdList["sched/sched_wakeup"]:
            if SysMgr.writeCmd('sched/sched_wakeup/filter', cmd) < 0:
                SysMgr.printErr(
                    "fail to set filter [ %s ]" % \
                    ' '.join(SysMgr.filterGroup))
                sys.exit(0)

        if self.cmdList["sched/sched_wakeup_new"]:
            if SysMgr.writeCmd('sched/sched_wakeup_new/filter', cmd) < 0:
                SysMgr.printErr(
                    "fail to set filter [ %s ]" % \
                    ' '.join(SysMgr.filterGroup))
                sys.exit(0)

        if self.cmdList["sched/sched_migrate_task"]:
            if SysMgr.writeCmd(
                'sched/sched_migrate_task/filter', cmd) < 0:
                SysMgr.printErr(
                    "fail to set filter [ %s ]" % \
                    ' '.join(SysMgr.filterGroup))
                sys.exit(0)

        if self.cmdList["sched/sched_process_wait"]:
            if SysMgr.writeCmd(
                'sched/sched_process_wait/filter', cmd) < 0:
                SysMgr.printWarn(
                    "fail to set filter [ %s ]" % \
                    ' '.join(SysMgr.filterGroup))

        # events for dependency tracing #
        if SysMgr.depEnable:
            ecmd = \
                "(id == %s || id == %s" % \
                (ConfigMgr.sysList.index("sys_write"),
                ConfigMgr.sysList.index("sys_futex"))
            rcmd = \
                "((id == %s || id == %s" % \
                (ConfigMgr.sysList.index("sys_write"),
                ConfigMgr.sysList.index("sys_futex"))

            if SysMgr.arch == 'arm':
                ecmd = \
                    ("%s || id == %s || id == %s || id == %s || "
                    "id == %s || id == %s || id == %s || id == %s)") % \
                    (ecmd, ConfigMgr.sysList.index("sys_recv"),
                    ConfigMgr.sysList.index("sys_epoll_wait"),
                    ConfigMgr.sysList.index("sys_poll"),
                    ConfigMgr.sysList.index("sys_select"),
                    ConfigMgr.sysList.index("sys_recvfrom"),
                    ConfigMgr.sysList.index("sys_recvmmsg"),
                    ConfigMgr.sysList.index("sys_recvmsg"))
                rcmd = \
                    ("%s || id == %s || id == %s || id == %s || "
                    "id == %s || id == %s || id == %s || id == %s) && ret > 0)") % \
                    (rcmd, ConfigMgr.sysList.index("sys_recv"),
                    ConfigMgr.sysList.index("sys_poll"),
                    ConfigMgr.sysList.index("sys_epoll_wait"),
                    ConfigMgr.sysList.index("sys_select"),
                    ConfigMgr.sysList.index("sys_recvfrom"),
                    ConfigMgr.sysList.index("sys_recvmmsg"),
                    ConfigMgr.sysList.index("sys_recvmsg"))
            elif SysMgr.arch == 'aarch64':
                ecmd = "%s || id == %s || id == %s || id == %s)" % \
                    (ecmd, ConfigMgr.sysList.index("sys_recvfrom"),
                    ConfigMgr.sysList.index("sys_recvmmsg"),
                    ConfigMgr.sysList.index("sys_recvmsg"))
                rcmd = "%s || id == %s || id == %s || id == %s) && ret > 0)" % \
                    (rcmd, ConfigMgr.sysList.index("sys_recvfrom"),
                    ConfigMgr.sysList.index("sys_recvmmsg"),
                    ConfigMgr.sysList.index("sys_recvmsg"))
            else:
                ecmd = ("%s || id == %s || id == %s || id == %s || "
                "id == %s || id == %s || id == %s)") % \
                    (ecmd, ConfigMgr.sysList.index("sys_recvfrom"),
                    ConfigMgr.sysList.index("sys_poll"),
                    ConfigMgr.sysList.index("sys_epoll_wait"),
                    ConfigMgr.sysList.index("sys_select"),
                    ConfigMgr.sysList.index("sys_recvmmsg"),
                    ConfigMgr.sysList.index("sys_recvmsg"))
                rcmd = \
                    ("%s || id == %s || id == %s || id == %s || "
                    "id == %s || id == %s || id == %s) && ret > 0)") % \
                    (rcmd, ConfigMgr.sysList.index("sys_recvfrom"),
                    ConfigMgr.sysList.index("sys_poll"),
                    ConfigMgr.sysList.index("sys_epoll_wait"),
                    ConfigMgr.sysList.index("sys_select"),
                    ConfigMgr.sysList.index("sys_recvmmsg"),
                    ConfigMgr.sysList.index("sys_recvmsg"))

            SysMgr.writeCmd('raw_syscalls/sys_enter/filter', ecmd)
            SysMgr.writeCmd('raw_syscalls/sys_exit/filter', rcmd)
        elif SysMgr.lockEnable:
            nrFutex = ConfigMgr.sysList.index("sys_futex")
            if nrFutex not in SysMgr.syscallList:
                SysMgr.syscallList.append(nrFutex)
        else:
            SysMgr.writeCmd('raw_syscalls/sys_enter/filter', '0')
            SysMgr.writeCmd('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.writeCmd('kmem/mm_page_free/enable', '1') < 0:
                SysMgr.writeCmd('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.writeCmd('block/block_bio_queue/filter', cmd)
        if self.cmdList["block/block_rq_complete"]:
            SysMgr.writeCmd('block/block_rq_complete/filter', cmd)

        # special events #
        _writeCommonCmd()

        # enable events #
        self.enableEvents()

        # start tracing #
        self.startTracing()

        _printStartLog()
        return



    @staticmethod
    def stopRecording():
        if not (SysMgr.isRecordMode() and \
            (SysMgr.isThreadMode() or \
            SysMgr.isFuncMode())):
            return

        # write signal command #
        if SysMgr.cmdEnable is not False and \
            SysMgr.cmdFd:

            if SysMgr.signalCmd:
                try:
                    SysMgr.cmdFd.write(SysMgr.signalCmd)
                    SysMgr.signalCmd = None
                    SysMgr.printInfo(
                        "write commands to %s" % SysMgr.cmdEnable)
                except:
                    SysMgr.printErr("fail to write signal command")
            elif SysMgr.outputFile:
                SysMgr.saveCmd =\
                    'cat %s../trace > %s\n' % \
                        (SysMgr.mountPath, SysMgr.outputFile)

        # start tracing #
        SysMgr.writeCmd('../tracing_on', '0')

        # disable all ftrace options registered #
        for idx, val in SysMgr.cmdList.items():
            if val:
                if SysMgr.writeCmd(str(idx) + '/enable', '0') >= 0:
                    SysMgr.writeCmd(str(idx) + '/filter', '0')

        if not SysMgr.graphEnable and \
            SysMgr.customCmd:

            for cmd in SysMgr.customCmd:
                event = cmd.split(':')[0]
                SysMgr.writeCmd(event + '/enable', '0')
                SysMgr.writeCmd(event + '/filter', '0')

        if SysMgr.isFuncMode():
            SysMgr.writeCmd('../options/stacktrace', '0')
            SysMgr.writeCmd('../trace_options', 'nouserstacktrace')
            SysMgr.writeCmd('../tracing_on', '0')

        # write save command #
        if SysMgr.saveCmd:
            try:
                SysMgr.cmdFd.write(SysMgr.saveCmd)
                SysMgr.cmdFd.write(
                    "echo '\nsaved command for tracing into %s\n'\n"\
                    % SysMgr.outputFile)
            except:
                SysMgr.printErr("fail to write save command")



    def printResourceInfo(self):
        if not SysMgr.generalInfoEnable:
            return

        self.printSystemInfo()

        self.printOSInfo()

        self.printCpuInfo()

        self.printCpuCacheInfo()

        self.printMemInfo()

        self.printStorageInfo()

        self.printNetworkInfo()

        self.printGpuInfo()

        self.printGpuMemInfo()

        self.printIPCInfo()

        self.printCgroupInfo()

        self.printLimitInfo()

        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', dict())
            SysMgr.jsonData['general']['os'] = dict()
            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("fail 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 printLimitInfo(self):
        if not self.limitData:
            return

        # add JSON stats #
        if SysMgr.jsonEnable:
            SysMgr.jsonData.setdefault('general', dict())
            SysMgr.jsonData['general'].setdefault('limit', dict())
            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, dict())
                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', dict())
            jsonData = SysMgr.jsonData['general']

        SysMgr.infoBufferPrint('\n\n[System General Info]')
        SysMgr.infoBufferPrint(twoLine)
        SysMgr.infoBufferPrint(
            "{0:^20} {1:100}".format("TYPE", "Information"))
        SysMgr.infoBufferPrint(twoLine)

        # launch option #
        try:
            launchOption = '%s%s' % (' '.join(sys.argv), ' -')
            SysMgr.infoBufferPrint("{0:20} # {1:<100}".\
                format('Launch', launchOption))

            if SysMgr.jsonEnable:
                jsonData['launch'] = launchOption
        except:
            pass

        # version #
        try:
            SysMgr.infoBufferPrint("{0:20} {1:<100}".\
                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:<100}".\
                format('Python', pv))

            if SysMgr.jsonEnable:
                jsonData['python'] = pv
        except:
            pass

        # hostname #
        try:
            hostname = self.uname[1]
            SysMgr.infoBufferPrint("{0:20} {1:<100}".\
                format('Host', hostname))

            if SysMgr.jsonEnable:
                jsonData['host'] = hostname
        except:
            pass

        # os #
        try:
            osInfo = self.uname[0]
            SysMgr.infoBufferPrint("{0:20} {1:<100}".\
                format('OS', osInfo))

            if SysMgr.jsonEnable:
                jsonData['os'] = osInfo
        except:
            pass

        # kernel #
        try:
            kernelInfo = self.uname[2]
            SysMgr.infoBufferPrint(
                "{0:20} {1:<100}".format('Kernel', kernelInfo))

            if SysMgr.jsonEnable:
                jsonData['kernel'] = kernelInfo
        except:
            pass

        # release #
        try:
            releaseInfo = self.uname[3]
            SysMgr.infoBufferPrint(
                "{0:20} {1:<100}".format('Release', releaseInfo))

            if SysMgr.jsonEnable:
                jsonData['release'] = releaseInfo
        except:
            pass

        # CPU architecture #
        try:
            SysMgr.infoBufferPrint("{0:20} {1:<100}".\
                format('Arch', SysMgr.arch))

            if SysMgr.jsonEnable:
                jsonData['arch'] = SysMgr.arch
        except:
            pass

        # time #
        try:
            timeInfo = '%s %s' % \
                (self.systemInfo['date'], self.systemInfo['time'])
            SysMgr.infoBufferPrint(
                "{0:20} {1:<100}".format('Date', timeInfo))

            if SysMgr.jsonEnable:
                jsonData['date'] = self.systemInfo['date']
                jsonData['time'] = self.systemInfo['time']
        except:
            pass

        # user name #
        try:
            uid = str(SysMgr.getUid('self'))

            SysMgr.infoBufferPrint(
                "{0:20} {1:<100}".format('User', self.userData[uid]['name']))

            if SysMgr.jsonEnable:
                jsonData['user'] = self.userData[uid]['name']
        except:
            pass

        # system uptime #
        try:
            uptime = UtilMgr.convTime(SysMgr.uptime)
            SysMgr.infoBufferPrint(
                "{0:20} {1:<100}".format('Uptime', uptime))

            if SysMgr.jsonEnable:
                jsonData['uptime'] = uptime
        except:
            pass

        # Guider runtime #
        try:
            runtime = \
                long(SysMgr.uptime) - long(SysMgr.startRunTime)
            runtime = UtilMgr.convTime(runtime)
            SysMgr.infoBufferPrint(
                "{0:20} {1:<100}".format('Runtime', runtime))

            if SysMgr.jsonEnable:
                jsonData['runtime'] = runtime
        except:
            pass

        # system 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

        # MAC #
        try:
            if self.macAddr is None:
                raise Exception('no MAC address')

            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

        # kernel args #
        try:
            title = 'Cmdline'
            splitLen = SysMgr.lineLength - 21
            cmdlineList = \
                [self.cmdlineData[i:i+splitLen] for i in \
                range(0, len(self.cmdlineData), splitLen)]
            for string in cmdlineList:
                SysMgr.infoBufferPrint(
                    "{0:20} {1:<100}".format(title, string))
                title = ''

            if SysMgr.jsonEnable:
                jsonData['cmdline'] = self.cmdlineData
        except:
            pass

        SysMgr.infoBufferPrint(twoLine)



    def printCpuCacheInfo(self):
        if not self.cpuCacheInfo:
            return

        # add JSON stats #
        if SysMgr.jsonEnable:
            SysMgr.jsonData.setdefault('general', dict())
            SysMgr.jsonData['general']['cache'] = dict()
            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 = long(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', dict())
            SysMgr.jsonData['general']['cpu'] = dict()
            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

        SysMgr.infoBufferPrint(twoLine)



    def updateDiskInfo(self, time, data):
        self.diskInfo[time] = dict()

        if 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(
                        "fail to parse all diskstat because of overflow")
                    break
                diskStat[ConfigMgr.DISKSTAT[idx]] = item

            self.diskInfo[time][diskStat['name']] = dict()
            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):
        class MountException(Exception):
            pass

        if not self.mountData:
            return

        # 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:])

            # 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,
            }



    def updateShmInfo(self):
        try:
            SysMgr.shmFd.seek(0)
            data = SysMgr.shmFd.readlines()[1:]
        except SystemExit:
            sys.exit(0)
        except:
            try:
                path = '%s/sysvipc/shm' % SysMgr.procPath
                SysMgr.shmFd = open(path, 'r')
                data = SysMgr.shmFd.readlines()[1:]
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenWarn(path)
                return

        # backup shm data #
        try:
            self.prevIpcData['shm'] = self.ipcData['shm']
        except:
            pass

        # initialize shm variable #
        self.ipcData['shm'] = dict()

        # 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] = dict()
            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):
        try:
            SysMgr.msgqFd.seek(0)
            data = SysMgr.msgqFd.readlines()[1:]
        except:
            try:
                path = '%s/sysvipc/msg' % SysMgr.procPath
                SysMgr.msgqFd = open(path, 'r')
                data = SysMgr.msgqFd.readlines()[1:]
            except:
                SysMgr.printOpenWarn(path)
                return

        # backup msgq data #
        try:
            self.prevIpcData['msgq'] = self.ipcData['msgq']
        except:
            pass

        # initialize msgq variable #
        self.ipcData['msgq'] = dict()

        # 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] = dict()
            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):
        try:
            SysMgr.semFd.seek(0)
            data = SysMgr.semFd.readlines()[1:]
        except:
            try:
                path = '%s/sysvipc/sem' % SysMgr.procPath
                SysMgr.semFd = open(path, 'r')
                data = SysMgr.semFd.readlines()[1:]
            except:
                SysMgr.printOpenWarn(path)
                return

        # backup sem data #
        try:
            self.prevIpcData['sem'] = self.ipcData['sem']
        except:
            pass

        # initialize sem variable #
        self.ipcData['sem'] = dict()

        # 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] = dict()
            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 self.macAddr:
            return

        # mac address #
        try:
            self.macAddr = NetworkMgr.getRepMacAddr()
        except:
            pass



    def updateIPCInfo(self):
        # 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 updateNetworkInfo(self):
        # check update time #
        if self.netUpdate == SysMgr.uptime:
            return
        else:
            self.netUpdate = SysMgr.uptime

        try:
            SysMgr.netdevFd.seek(0)
            data = SysMgr.netdevFd.readlines()[2:]
        except SystemExit:
            sys.exit(0)
        except:
            try:
                devPath = '%s/net/dev' % SysMgr.procPath
                SysMgr.netdevFd = open(devPath, 'r')
                data = SysMgr.netdevFd.readlines()[2:]
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenWarn(devPath)
                return

        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, dict())

                # set IP addr #
                try:
                    if not SysMgr.localServObj:
                        NetworkMgr.setServerNetwork(None, None, reuse=False)

                    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'] = list()

                    for idx, val in enumerate(rlist):
                        self.networkInfo[dev]['rdiff'].append(
                            val - self.networkInfo[dev]['recv'][idx])
                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'] = list()

                    for idx, val in enumerate(tlist):
                        self.networkInfo[dev]['tdiff'].append(
                            val - self.networkInfo[dev]['tran'][idx])
                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

        try:
            with open('%s/sys/fs/file-nr' % SysMgr.procPath) as fd:
                stats = list(map(long, fd.readline()[:-1].split()))
                self.openFileData['cur'] = stats[0]
                self.openFileData['max'] = stats[2]
        except SystemExit:
            sys.exit(0)
        except:
            pass



    def saveUnameInfo(self):
        if self.uname:
            return

        try:
            self.uname = os.uname()
        except:
            pass



    def saveUserInfo(self):
        # check user data #
        if len(self.userData) > 0 or \
            SysMgr.isAndroid:
            return

        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.decode().split(':')

                self.userData[uid] = {
                    'name': user,
                    'gid': gid,
                    'info': info,
                    'home': home,
                    'shell': shell,
                }
            except:
                pass



    def updateStorageInfo(self, isGeneral=False):
        # check update time #
        if self.storageUpdate == SysMgr.uptime:
            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 = dict()
        init_storageData = \
            {'total': long(0), 'free': long(0), 'favail': long(0),
            'read': long(0), 'write': long(0), 'usage': long(0),
            'usagePer': long(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:]

                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 variable of this device info #
                beforeInfo = self.diskInfo['prev'][dev]
                afterInfo = self.diskInfo['next'][dev]

                # get interval load of this device #
                read = \
                    (long(afterInfo['sectorRead']) - \
                    long(beforeInfo['sectorRead'])) << 9
                read = read >> 20

                write = \
                    (long(afterInfo['sectorWrite']) - \
                    long(beforeInfo['sectorWrite'])) << 9
                write = write >> 20

                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 stat #
                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 stat #
            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
        elif 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] = dict()

                # 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])

        cgroupPath = self.getCgroupPath()
        if not cgroupPath:
            return None

        # get full path list #
        dirList = dict()
        _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

            # chek type #
            if type(root) is not dict:
                return

            tempRoot = deepcopy(root)

            # calculate sum for subdirs #
            newTotal = 0
            for curdir, subdir in tempRoot.items():
                if 'cpu.shares' in subdir:
                    for parent, childs in subdir.items():
                        if type(childs) is not dict:
                            continue
                        if 'cpu.shares' in childs:
                            value = childs['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 = long(0)
                nrTasks = long(0)

                # check subdir type #
                if type(subdir) is not dict:
                    continue

                tempSubdir = deepcopy(subdir)
                for val in list(subdir.keys()):
                    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 = '%d' % (num / float(total) * 100)
                        value = '%s/%s%%' % \
                            (subdir[val], UtilMgr.convColor(per, '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 idx in range(0, depth):
                    indent = '%s%s|' % (indent, '     ')

                if len(cstr) > 0:
                    cstr = ' <%s>' % cstr[:-2]

                # define worker info #
                if nrProcs != '0':
                    procstr = UtilMgr.convColor(nrProcs, 'YELLOW')
                else:
                    procstr = nrProcs
                if nrTasks != '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 len(tempSubdir) > 0:
                    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, inc=True, 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.getMainArg().split(',')
            items = UtilMgr.cleanItem(items)

            # remove subsystems from tree #
            for subsystem in list(cgroupTree.keys()):
                if not UtilMgr.isValidStr(
                    subsystem, key=items, inc=True, ignCap=True):
                    cgroupTree.pop(subsystem, None)

        # print cgroup tree #
        _printDirTree(cgroupTree, 0)

        if printTitle:
            SysMgr.infoBufferPrint(twoLine)

        # add JSON stats #
        if SysMgr.jsonEnable:
            SysMgr.jsonData.setdefault('general', dict())
            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:^70} | {1:^24} | {2:^15} | {3:^36} ".format(
            "ID", "Segment", "Attr", "Time"))
        SysMgr.infoBufferPrint(oneLine)
        SysMgr.infoBufferPrint((
            "{0:^26}   {1:^14}   {2:^24} | "
            "{3:^6}   {4:^6}   {5:^6} | "
            "{6:^6}   {7:^6} | {8:^10}   {9:^10}   {10:^10}".format(
                "OWNER", "SHM", "USER", "SIZE", "RSS",
                "SWAP", "REF", "PERM", "ATIME", "DTIME", "CTIME")))
        SysMgr.infoBufferPrint(twoLine)

        # get attr #
        cnt = long(0)
        prevOwner = None
        now = time.mktime(time.gmtime())
        convertSizeFunc = UtilMgr.convSize2Unit
        convTimeFunc = UtilMgr.convTime

        # merge stats per-owner #
        ownerData = dict()
        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] = dict()
                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, 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 = 70 - 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

            owner = ''

            try:
                pid = stats['lpid']
                comm = SysMgr.getComm(pid)
                if not comm:
                    raise Exception('no comm')

                access = '%s (%s)' % (comm, 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:>26}   {1:>14}   {2:>24}   {3:>6}   {4:>6}   "
                    "{5:>6}   {6:>6}   {7:>6}   {8:>10}   {9:>10}   "
                    "{10:>10}").format(
                        owner, shmid, 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', dict())
            SysMgr.jsonData['general']['gpu'] = dict()
            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, dict())

            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):
        try:
            path = '/sys/kernel/debug/nvmap/iovmm/clients'
            with open(path, 'rb') as fd:
                gpuInfo = fd.readlines()[1:]
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printOpenWarn(path)
            return

        # add JSON stats #
        if SysMgr.jsonEnable:
            SysMgr.jsonData.setdefault('general', dict())
            SysMgr.jsonData['general'].setdefault('gpu', dict())
            SysMgr.jsonData['general'].setdefault('gpumem', dict())
            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 item in gpuInfo:
            try:
                comm, pid, size = item.decode().split()[1:]
            except SystemExit:
                sys.exit(0)
            except:
                continue

            # convert size to number #
            size = UtilMgr.convUnit2Size(size)
            if size == 0:
                continue
            else:
                total += size

            # reconvert size to unit #
            size = UtilMgr.convSize2Unit(size)

            proc = '%s(%s)' % (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', dict())
            SysMgr.jsonData['general']['network'] = dict()
            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)

        convertFunc = 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 = list()
                for idx, stat in enumerate(val['recv']):
                    rdiff.append(stat - val['initrecv'][idx])

                # tran diff #
                tdiff = list()
                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, 'DIFF',
                        convertFunc(rdiff[0]), convertFunc(rdiff[1]),
                        convertFunc(rdiff[2]), convertFunc(rdiff[3]),
                        convertFunc(rdiff[-1]),
                        convertFunc(tdiff[0]), convertFunc(tdiff[1]),
                        convertFunc(tdiff[2]), convertFunc(tdiff[3]),
                        convertFunc(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',
                        convertFunc(rlist[0]), convertFunc(rlist[1]),
                        convertFunc(rlist[2]), convertFunc(rlist[3]),
                        convertFunc(rlist[-1]),
                        convertFunc(tlist[0]), convertFunc(tlist[1]),
                        convertFunc(tlist[2]), convertFunc(tlist[3]),
                        convertFunc(tlist[-1])))

                if cnt < len(self.networkInfo):
                    SysMgr.infoBufferPrint(
                        "{0:1}".format(oneLine))

                cnt += 1

                if SysMgr.jsonEnable:
                    jsonData[dev] = dict()

                    jsonData[dev]['ipaddr'] = val['ipaddr']

                    jsonData[dev]['recv'] = {
                        'bytes': convertFunc(rlist[0]),
                        'packets': convertFunc(rlist[1]),
                        'errs': convertFunc(rlist[2]),
                        'drop': convertFunc(rlist[3]),
                        'fifo': convertFunc(rlist[4]),
                        'frame': convertFunc(rlist[5]),
                        'compressed': convertFunc(rlist[6]),
                        'multicast': convertFunc(rlist[7]),
                    }

                    jsonData[dev]['trans'] = {
                        'bytes': convertFunc(tlist[0]),
                        'packets': convertFunc(tlist[1]),
                        'errs': convertFunc(tlist[2]),
                        'drop': convertFunc(tlist[3]),
                        'fifo': convertFunc(tlist[4]),
                        'frame': convertFunc(tlist[5]),
                        'compressed': convertFunc(tlist[6]),
                        'multicast': convertFunc(tlist[7]),
                    }
            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',
                    convertFunc(rdiff[0]), convertFunc(rdiff[1]),
                    convertFunc(rdiff[2]), convertFunc(rdiff[3]),
                    convertFunc(rdiff[-1]),
                    convertFunc(tdiff[0]), convertFunc(tdiff[1]),
                    convertFunc(tdiff[2]), convertFunc(tdiff[3]),
                    convertFunc(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',
                    convertFunc(rtotal[0]), convertFunc(rtotal[1]),
                    convertFunc(rtotal[2]), convertFunc(rtotal[3]),
                    convertFunc(rtotal[-1]),
                    convertFunc(ttotal[0]), convertFunc(ttotal[1]),
                    convertFunc(ttotal[2]), convertFunc(ttotal[3]),
                    convertFunc(ttotal[-1])))

        SysMgr.infoBufferPrint("%s" % twoLine)



    def printStorageInfo(self):
        # add JSON stats #
        if SysMgr.jsonEnable:
            SysMgr.jsonData.setdefault('general', dict())
            SysMgr.jsonData['general']['storage'] = dict()
            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)

        devInfo = {}
        totalInfo = \
            {'total': long(0), 'free': long(0), 'favail': long(0),
            'read': long(0), 'write': long(0)}
        outputCnt = long(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 = readSize = \
                    (long(afterInfo['sectorRead']) - \
                        long(beforeInfo['sectorRead'])) << 9
                readSize = UtilMgr.convSize2Unit(readSize)

                write = writeSize = \
                    (long(afterInfo['sectorWrite']) - \
                        long(beforeInfo['sectorWrite'])) << 9
                writeSize = UtilMgr.convSize2Unit(writeSize)

                if val['fs'] != 'tmpfs':
                    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

            # 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:
                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 len(val['option']) > 0:
                    mountList = '%s <%s>' % (val['path'], val['option'])
                else:
                    mountList = val['path']

                mountList = \
                    [mountList[i:i+splitLen] for i in \
                    range(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:
                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 = long(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 data #
        time = 'prev'
        self.memInfo[time] = dict()
        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']

        time = 'next'
        self.memInfo[time] = dict()
        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 #
        convertFunc = 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" % \
            (convertFunc(long(before['MemTotal']) << 10),
            convertFunc(long(before['SwapTotal']) << 10)))

        SysMgr.infoBufferPrint("[ FREE ] %10s %10s" % \
            (convertFunc(long(before['MemFree']) << 10),
            convertFunc(long(before['SwapFree']) << 10)))
        if 'MemAvailable' in before:
            SysMgr.infoBufferPrint("[ AVAIL] %10s %10s" % \
                (convertFunc(long(before['MemAvailable']) << 10),
                convertFunc(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") % \
                (convertFunc(memBeforeUsage << 10),
                convertFunc(swapBeforeUsage << 10),
                convertFunc(long(before['Buffers']) << 10),
                convertFunc(long(before['Cached']) << 10),
                convertFunc(long(before['Shmem']) << 10),
                convertFunc(long(before['Mapped']) << 10),
                convertFunc(long(before['Active']) << 10),
                convertFunc(long(before['Inactive']) << 10),
                convertFunc(long(before['PageTables']) << 10),
                convertFunc(long(before['Slab']) << 10),
                convertFunc(long(before['SReclaimable']) << 10),
                convertFunc(long(before['SUnreclaim']) << 10),
                convertFunc(long(before['Mlocked']) << 10)))

        SysMgr.infoBufferPrint((
            "[ LAST ] %10s %10s %10s %10s %10s %10s %10s "
            "%10s %10s %10s %10s %10s %10s") % \
                (convertFunc(memAfterUsage << 10),
                convertFunc(swapAfterUsage << 10),
                convertFunc(long(after['Buffers']) << 10),
                convertFunc(long(after['Cached']) << 10),
                convertFunc(long(after['Shmem']) << 10),
                convertFunc(long(after['Mapped']) << 10),
                convertFunc(long(after['Active']) << 10),
                convertFunc(long(after['Inactive']) << 10),
                convertFunc(long(after['PageTables']) << 10),
                convertFunc(long(after['Slab']) << 10),
                convertFunc(long(after['SReclaimable']) << 10),
                convertFunc(long(after['SUnreclaim']) << 10),
                convertFunc(long(after['Mlocked']) << 10)))

        SysMgr.infoBufferPrint(oneLine)

        SysMgr.infoBufferPrint((
            "[ DIFF ] %10s %10s %10s %10s %10s %10s %10s "
            "%10s %10s %10s %10s %10s %10s") % \
                (convertFunc((memAfterUsage - memBeforeUsage ) << 10),
                convertFunc((swapAfterUsage - swapBeforeUsage) << 10),
                convertFunc((long(after['Buffers']) - \
                    long(before['Buffers'])) << 10),
                convertFunc((long(after['Cached']) - \
                    long(before['Cached'])) << 10),
                convertFunc((long(after['Shmem']) - \
                    long(before['Shmem'])) << 10),
                convertFunc((long(after['Mapped']) - \
                    long(before['Mapped'])) << 10),
                convertFunc((long(after['Active']) - \
                    long(before['Active'])) << 10),
                convertFunc((long(after['Inactive']) - \
                    long(before['Inactive'])) << 10),
                convertFunc((long(after['PageTables']) - \
                    long(before['PageTables'])) << 10),
                convertFunc((long(after['Slab']) - \
                    long(before['Slab'])) << 10),
                convertFunc((long(after['SReclaimable']) - \
                    long(before['SReclaimable'])) << 10),
                convertFunc((long(after['SUnreclaim']) - \
                    long(before['SUnreclaim'])) << 10),
                convertFunc((long(after['Mlocked']) - \
                    long(before['Mlocked'])) << 10)))

        SysMgr.infoBufferPrint(twoLine)

        # add JSON stats #
        if SysMgr.jsonEnable:
            SysMgr.jsonData.setdefault('general', dict())
            SysMgr.jsonData['general']['mem'] = {
                'memTotal': convertFunc(long(after['MemTotal']) << 10),
                'memFree': convertFunc(long(after['MemFree']) << 10),
                'swapTotal': convertFunc(long(after['SwapTotal']) << 10),
                'swapFree': convertFunc(long(after['SwapFree']) << 10),
                'buffer': convertFunc(long(after['Buffers']) << 10),
                'cache': convertFunc(long(after['Cached']) << 10),
                'shmem': convertFunc(long(after['Shmem']) << 10),
                'mapped': convertFunc(long(after['Mapped']) << 10),
                'active': convertFunc(long(after['Active']) << 10),
                'inactive': convertFunc(long(after['Inactive']) << 10),
                'pagetable': convertFunc(long(after['PageTables']) << 10),
                'slab': convertFunc(long(after['Slab']) << 10),
                'sreclaimable': \
                    convertFunc(long(after['SReclaimable']) << 10),
                'sunreclaimable': \
                    convertFunc(long(after['SUnreclaim']) << 10),
                'mlock': convertFunc(long(after['Mlocked']) << 10),
            }

            if 'MemAvailable' in after:
                SysMgr.jsonData['general']['mem']['memAvailable'] = \
                    convertFunc(long(after['MemAvailable']) << 10)





class DbusMgr(object):
    """ Analyzer for D-Bus """

    errObj = None
    dbusErrObj = None
    sentData = {}
    recvData = {}
    prevData = {}
    msgSentTable = {}
    msgRecvTable = {}
    msgColorList = {}
    connCache = {}
    dbgObj = None

    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': long(0),
        'max': long(0),
        'err': long(0),
        'cnt': long(0),
        'size': long(0),
        'total': long(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(
                    "fail 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("fail 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):
                        address = c_char_p(env.lstrip(ADDRENV)[1:].encode())
                        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(
                        "fail to register D-Bus %s bus for %s because %s" % \
                            (bus, procInfo, DbusMgr.getErrInfo()))
                    return None
            else:
                SysMgr.printWarn(
                    "fail 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(
                "fail 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(
                "fail 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("fail 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("fail 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("fail 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("fail 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("fail 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("fail 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(
                "fail to call a D-Bus remote method because %s at %s line" % \
                    (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("fail 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(
                "fail to call a D-Bus remote method because %s at %s line" % \
                    (DbusMgr.getErrInfo(), SysMgr.getLine()))
            return msg, reply

        return msg, reply



    @staticmethod
    def getStats(bus, request, des=None, tid=None, procStr=None):
        def _printWarn(procStr, line, err):
            SysMgr.printWarn((
                'fail to parse from D-Bus message for %s at %s line '
                '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(0)

        # 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 = dict()

            # 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, list())

                    # 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, dict())
                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))
                    if not sigInfo.value:
                        _printWarn(procStr, getLine(), getErr())
                        dbusObj.dbus_message_unref(msg)
                        dbusObj.dbus_message_unref(reply)
                        #dbusObj.dbus_connection_unref(conn)
                        return

                    # parse items #
                    sinfo = {}
                    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, dict())
                        procSigList[sender].setdefault(addr, dict())
                        if 'arg0' in sinfo:
                            argList = [ '%s' % sinfo[i] for i in sorted(list(sinfo.keys())) if i.startswith('arg') ]
                            procSigList[sender][addr].setdefault(', '.join(argList))

                        # save perSignal items #
                        perSigList.setdefault(sender, dict())
                        sigProcList = perSigList[sender]
                        sigProcList.setdefault(addr, dict())
                        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("fail 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("fail 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(
                "fail to call a D-Bus remote method because %s at %s line" % \
                    (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(
                "fail 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(
                "fail to parse D-Bus message args because %s" % \
                    DbusMgr.getErrInfo())
            return

        slist = []
        for idx in range(0, 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(
                "fail to load library to analyze D-Bus packets", True)
            sys.exit(0)

        # 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 printStatInfo(tid, statList):
        conv = UtilMgr.convNum
        totalSubscription = 0
        procId = '%s(%s)' % (SysMgr.getComm(tid, cache=True), tid)

        if not statList:
            SysMgr.printErr('no stat for %s' % procId)
            return

        # print title #
        SysMgr.printPipe(
            '\nD-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((
            '\nD-Bus Signal Proxy Info [Target: %s] '
            '[nrProcess: %s] [nrSubscription: %s]\n%s') % \
                (procId, conv(len(perProc)), conv(totalSubscription), twoLine))
        SysMgr.printPipe(
            "{0:^23} {1:<23} {2:^10} {3:>1}".format(
                'Client', 'Server', 'Interface', 'Args'))
        SysMgr.printPipe(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} {1:<23} {2:<12}".format(
                            ' ', ' ', name))
                    for key in sorted(list(arg.keys())):
                        SysMgr.printPipe(
                            "{0:>23} {1:<23} {2:<10} ({3:<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': dict(), 'nrSignal': 0, 'interface': dict()}
            nrPerSigProcs.setdefault(proc, dict(initDict))
            nrPerSigProcs[proc]['interface'].setdefault(sender, dict())
            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((
            '\nD-Bus Signal Stub Info [Target: %s] '
            '[nrProcess: %s] [nrSubscription: %s]\n%s') % \
                (procId, conv(len(perSig)), conv(totalSubscription), twoLine))
        SysMgr.printPipe(
            "{0:^23} {1:^12} {2:<23}".format(
                'Server', 'Interface', 'Client'))
        SysMgr.printPipe(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.keys()) ]
                    # print proxy process stat #
                    for name in sorted(procs):
                        if name in procInfo:
                            cproc = procInfo[name]
                        else:
                            cproc = name

                        SysMgr.printPipe(
                            "{0:>23} {1:<12} {2:<12} {3:<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(
                    "fail to update system stat", True)

            convertNum = UtilMgr.convNum
            convertSize = UtilMgr.convSize2Unit

            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' % \
                            (convertNum(dbusCnt),
                            convertNum(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 = long(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 = long(0)

                        if data['err'] > 0:
                            errstr = ', Err: %s' % data['err']
                        else:
                            errstr = ''

                        if data['max'] > 0:
                            name = \
                                '%s {Min: %.3f, Avr: %.3f, Max: %.3f%s} %s' % \
                                (name, data['min'], avr, data['max'],
                                    errstr, wstat)

                        count = convertNum(value['cnt'])
                        size = convertSize(data['size'])

                        dbusList.append(
                            "{0:>4}({1:>6}/{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(
                        "fail to update task info", True, reason=True)

        def printSummary(signum, frame):
            def _checkRepeatCnt():
                if SysMgr.repeatCount > 0:
                    SysMgr.progressCnt += 1
                    if SysMgr.repeatCount <= SysMgr.progressCnt:
                        os.kill(SysMgr.pid, signal.SIGINT)
                        sys.exit(0)

            if SysMgr.checkMode('printdbus'):
                _checkRepeatCnt()
                return

            # disable alarm #
            signal.signal(signal.SIGALRM, signal.SIG_IGN)

            # check user input #
            SysMgr.waitUserInput(0.000001)

            # get summary list #
            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': long(0), 'totalErr': long(0)}

            if lock and lock.locked():
                try:
                    lock.release()
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

            convertNum = UtilMgr.convNum

            # update CPU usage of tasks #
            _updateTaskInfo(prevDbusData, prevSentData, prevRecvData)

            if DbusMgr.dbgObj:
                cpuUsage = DbusMgr.dbgObj.getCpuUsage()
                ttime = cpuUsage[0] / SysMgr.uptimeDiff
                utime = cpuUsage[1] / SysMgr.uptimeDiff
                stime = cpuUsage[2] / SysMgr.uptimeDiff
                cpuStr = '%d%%(Usr:%d%%/Sys:%d%%)' % (ttime, utime, stime)
            else:
                cpuStr = '?'

            # print title #
            SysMgr.addPrint(
                ("[%s] [Time: %7.3f] [Interval: %.1f] "
                "[NrMsg: %s] [NrErr: %s] [CPU: %s]\n") % \
                    ('D-Bus Info', SysMgr.uptime,
                    SysMgr.uptimeDiff,
                    convertNum(prevDbusData['totalCnt']),
                    convertNum(prevDbusData['totalErr']),
                    cpuStr))

            # print resource usage of tasks #
            taskManager.printSystemUsage()
            taskManager.printProcUsage()
            taskManager.reinitStats()
            SysMgr.printTopStats()

            # check repeat count #
            _checkRepeatCnt()

            # enable alarm #
            signal.signal(signal.SIGALRM, printSummary)

            # reset 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()

            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:
                return

            # check args #
            try:
                # check syscall #
                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(
                    "fail to handle %s for %s(%s)" % \
                        ([jsonData], jsonData['comm'], jsonData['tid']),
                            reason=True)

        def _handleMsg(ctype, msgList, jsonData, data):
            try:
                tid, params, bus, service = data

                libgioObj = SysMgr.libgioObj
                libgObj = SysMgr.libgObj

                mlist = {}
                cnt = long(0)
                gdmsg = long(0)

                if type(msgList) is not dict:
                    return

                G_IO_ERROR_TYPE = DbusMgr.G_IO_ERROR_TYPE

                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 = long(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] = dict()
                        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 = libgioObj.g_dbus_message_bytes_needed(
                        buf, c_ulong(len(call)), byref(errp))
                    if direction == 'OUT' and errp:
                        SysMgr.printWarn((
                            "fail 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))
                        libgioObj.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 = libgioObj.g_dbus_message_new_from_blob(
                        buf, c_ulong(len(call)), 0, byref(errp))

                    # check error #
                    if not gdmsg and errp:
                        SysMgr.printWarn((
                            "fail 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))
                        libgioObj.g_error_free(byref(errp.contents))
                        TaskAnalyzer.dbusData['totalErr'] += 1
                        continue

                    # get address of the message #
                    addr = c_ulong(gdmsg)

                    # get sender #
                    srcInfo = '??'
                    src = libgioObj.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, None, service)
                                if src in service:
                                    srcInfo = service[src]

                    # get receiver #
                    desInfo = '??'
                    des = libgioObj.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, None, service)
                                if des in service:
                                    desInfo = service[des]

                    # get message type #
                    try:
                        nrType = libgioObj.g_dbus_message_get_message_type(addr)
                        mtype = DbusMgr.GDBusMessageType[nrType]
                    except SystemExit:
                        sys.exit(0)
                    except:
                        SysMgr.printWarn(
                            "fail to get type of GDbusMessage", reason=True)
                        TaskAnalyzer.dbusData['totalErr'] += 1
                        continue

                    effectiveReply = False
                    if mtype == 'RETURN':
                        # get reply-serial #
                        repSerial = \
                            libgioObj.g_dbus_message_get_reply_serial(
                                c_ulong(gdmsg))
                        if repSerial in msgTable:
                            effectiveReply = True

                    # print message #
                    if SysMgr.checkMode('printdbus') or SysMgr.customCmd:
                        if len(jsonData['backtrace']) > 2:
                            backtrace = \
                                'Backtrace: %s\n' % jsonData['backtrace']
                        else:
                            backtrace = ''

                        if SysMgr.checkMode('dbustop') or SysMgr.showAll:
                            addInfo = "\n%s%s" % \
                                (libgioObj.g_dbus_message_print(
                                    c_ulong(gdmsg), c_ulong(0)).decode(),
                                    backtrace)
                        else:
                            path = libgioObj.g_dbus_message_get_path(addr)
                            if not path:
                                path = b''

                            iface = \
                                libgioObj.g_dbus_message_get_interface(addr)
                            if not iface:
                                iface = b''

                            member = libgioObj.g_dbus_message_get_member(addr)
                            if not member:
                                member = b''

                            addInfo = " %s.%s" % \
                                (iface.decode(), member.decode())

                        mtime = jsonData['time']

                        msgStr = \
                            "[%s] %.6f %s(%s) %s->%s %s %g %s%s" % \
                            (DbusMgr.msgColorList[mtype],
                                mtime, jsonData['comm'], tid, srcInfo,
                                desInfo, direction, jsonData['timediff'],
                                UtilMgr.convSize2Unit(hsize), addInfo)

                        if effectiveReply:
                            pass
                        elif SysMgr.customCmd and \
                            not UtilMgr.isValidStr(
                                msgStr, SysMgr.customCmd, ignCap=True):
                            continue

                        if SysMgr.checkMode('printdbus'):
                            SysMgr.printPipe(msgStr, flush=True)
                            continue

                    # set task default dict #
                    DbusMgr.sentData.setdefault(tid, dict())
                    DbusMgr.recvData.setdefault(tid, dict())

                    # return check #
                    if mtype == 'RETURN':
                        if repSerial in msgTable:
                            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'] = long(0)

                        continue

                    # get properties from message #
                    #path = libgioObj.g_dbus_message_get_path(addr)
                    interface = libgioObj.g_dbus_message_get_interface(addr)
                    member = libgioObj.g_dbus_message_get_member(addr)
                    arg0 = libgioObj.g_dbus_message_get_arg0(addr)
                    serial = libgioObj.g_dbus_message_get_serial(addr)

                    # handle error message #
                    if mtype == 'ERROR' or mtype == 'INVALID':
                        ename = libgioObj.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']

                    # save last interface except for signal #
                    if mtype != 'SIGNAL':
                        pass

                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] = dict()
                        TaskAnalyzer.dbusData[tid][name]['cnt'] = \
                            value['count']
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn(
                    "fail 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:
                        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:
                try:
                    if tid:
                        comm = SysMgr.getComm(tid, cache=True)
                except:
                    pass

                if tid:
                    procInfo = ' for %s(%s)' % (comm, tid)
                else:
                    procInfo = ''

                SysMgr.printWarn(
                    'fail to read data from pipe%s' % procInfo, reason=True)

                return

        def _updateServiceProc(bus, tid, addr, serviceList):
            '''
            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.getPids(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:
            onlyDaemon = True
            taskList += _getDefaultTasks('dbus-daemon')
            taskList += _getDefaultTasks('dbus-broker')
        else:
            onlyDaemon = False
            for val in SysMgr.filterGroup:
                if SysMgr.groupProcEnable:
                    taskList += SysMgr.getPids(val, sibling=True)
                else:
                    taskList += _getDefaultTasks(val)
        if not taskList:
            SysMgr.printErr(
                "fail to find task to analyze D-Bus message")
            sys.exit(0)
        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()

        # define common list #
        busList = []
        pipeList = []
        busServiceList = {}
        gBusServiceList = {}
        interfaceList = {}
        threadingList = []
        SysMgr.filterGroup = taskList

        # 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(
                ConfigMgr.sysList.index('sys_recvmsg'))
            SysMgr.syscallList.append(
                ConfigMgr.sysList.index('sys_recvmmsg'))
        SysMgr.syscallList.append(
            ConfigMgr.sysList.index('sys_sendmsg'))
        SysMgr.syscallList.append(
            ConfigMgr.sysList.index('sys_sendmmsg'))

        # set colors for each message types #
        DbusMgr.msgColorList = {
            'INVALID': UtilMgr.convColor('INVALID', 'RED'),
            'ERROR': UtilMgr.convColor('ERROR', 'RED'),
            'METHOD': UtilMgr.convColor('METHOD', 'CYAN'),
            'RETURN': UtilMgr.convColor('RETURN', 'BLUE'),
            'SIGNAL': UtilMgr.convColor('SIGNAL', 'PINK'),
        }

        # 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:
                cmdline = ''

            # get bus type #
            bus = None
            listen = None
            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 = item.lstrip('<listen>')
                                item = item.split('</listen>')[0]
                                item = item.strip()
                                listen = item
                            if item.startswith('<type>'):
                                item = item.lstrip('<type>')
                                item = item.split('</type>')[0]
                                item = item.strip()
                                bus = item
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printWarn(
                        "fail to get D-Bus config", reason=True)
            busList.append(bus)

            # get servce list #
            if bus:
                services = DbusMgr.getBusService(
                    bus, tid=tid, addr=listen)
            else:
                services = None

            # register services #
            busServiceList.setdefault(tid, dict())
            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 False and not service.startswith(':'):
                        # get service tid #
                        if pinfo:
                            ptid = pinfo[pinfo.rfind('(')+1:-1]
                        else:
                            ptid = None

                        interfaceList[service] = \
                            DbusMgr.getStats(
                                bus, 'introspect', service, procStr=pinfo)

                busServiceList[tid].setdefault(bus, busProcList)
            else:
                busServiceList[tid].setdefault(bus, dict())

            # monitor messages #
            if mode == 'monitor':
                ret = DbusMgr.runMonitor(bus)
                continue

            # print signals #
            procStr = '%s(%s)' % (SysMgr.getComm(tid, cache=True), tid)
            if mode == 'signal':
                ret = DbusMgr.getStats(bus, 'allmatch', procStr=procStr)
                if ret:
                    perProc, perSig = ret
                    DbusMgr.printSignalInfo(
                        tid, perProc, perSig, busProcList)
                continue
            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.optStrace = True
                SysMgr.encodeB64Enable = True
                SysMgr.intervalEnable = long(0)
                SysMgr.outPath = SysMgr.printFd = None
                SysMgr.logEnable = False
                SysMgr.filterGroup = [tid]
                SysMgr.jsonEnable = True

                # execute strace mode #
                SysMgr.doTrace('syscall')

                sys.exit(0)

            # error #
            else:
                sys.exit(0)

        # check signal mode #
        if mode == 'signal':
            return

        # 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 type #
    MSGTYPE = \
        ["log", "app_trace", "nw_trace", "control"]
    LOGINFO = \
        ["", "fatal", "error", "warn", "info", "debug", "verb"]
    msgColorList = []

    # 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
    }

    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': long(0)}

    @staticmethod
    def printSummary():
        quitLoop = False
        convertFunc = UtilMgr.convNum

        # update uptime #
        SysMgr.updateUptime()

        # print title #
        SysMgr.addPrint(
            ("[%s] [Time: %7.3f] [Interval: %.1f] [NrMsg: %s]\n") % \
                ('DLT Info', SysMgr.uptime,
                SysMgr.uptimeDiff,
                convertFunc(DltAnalyzer.dltData['cnt'])))

        # 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.printProcUsage()
            DltAnalyzer.procInfo.reinitStats()
        else:
            SysMgr.addPrint('%s\n' % twoLine)

        SysMgr.addPrint(
                "{0:^20} | {1:^19} | {2:^19} |\n{3:1}\n".format(
                "ECU", "AP", "CONTEXT", twoLine), newline=2)

        # traverse DLT table #
        dltCnt = long(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 \
                SysMgr.checkCutCond():
                break

            ecuCnt = ecuItem['cnt']
            ecuPer = ecuCnt / float(DltAnalyzer.dltData['cnt']) * 100
            ecuStr = "{0:4} {1:>8}({2:5.1f}%)\n".format(
                ecuId, convertFunc(ecuCnt), ecuPer)
            SysMgr.addPrint(ecuStr)
            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 \
                    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, convertFunc(apCnt), apPer)
                SysMgr.addPrint(apStr)

                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 \
                        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, convertFunc(ctxCnt), ctxPer)
                    SysMgr.addPrint(ctxStr)

        if dltCnt == 0:
            SysMgr.addPrint('\tNone\n')

        if not quitLoop:
            SysMgr.addPrint('%s\n' % oneLine)

        SysMgr.printTopStats()

        # initialize data #
        DltAnalyzer.dltData = {'cnt': long(0)}



    @staticmethod
    def onAlarm(signum, frame):
        if SysMgr.checkMode('printdlt'):
            SysMgr.progressCnt += 1
            if SysMgr.repeatCount <= SysMgr.progressCnt:
                sys.exit(0)

        if DltAnalyzer.dltData['cnt'] == 0 and \
            not SysMgr.inWaitStatus:
            SysMgr.printWarn(
                "no DLT message received", True)
        else:
            DltAnalyzer.printSummary()

        SysMgr.updateTimer()



    @staticmethod
    def handleMessage(dltObj, msg, buf, mode, verbose, buffered=False):
        DLT_MSIN_MTIN = 0xf0 # message type info #
        DLT_MSIN_MTIN_SHIFT = 4 # shift right offset to get mtin value #

        # save and reset global filter #
        filterGroup = SysMgr.filterGroup

        # pick storage info #
        if msg.storageheader:
            ecuId = msg.storageheader.contents.ecu.decode()
        else:
            return
        if msg.extendedheader:
            apId = msg.extendedheader.contents.apid.decode()
            ctxId = msg.extendedheader.contents.ctid.decode()
        else:
            return

        # summarizing #
        if mode == 'top':
            # check filter #
            if filterGroup:
                skipFlag = True
                for cond in filterGroup:
                    if cond == ecuId or \
                        cond == apId or \
                        cond == ctxId:
                        skipFlag = False
                        break
                if skipFlag:
                    return

            DltAnalyzer.dltData['cnt'] += 1

            # add ecuId #
            if not ecuId in DltAnalyzer.dltData:
                DltAnalyzer.dltData[ecuId] = {'cnt': long(0)}
            DltAnalyzer.dltData[ecuId]['cnt'] += 1

            # add apId #
            if not apId in DltAnalyzer.dltData[ecuId]:
                DltAnalyzer.dltData[ecuId][apId] = {'cnt': long(0)}
            DltAnalyzer.dltData[ecuId][apId]['cnt'] += 1

            # add ctxId #
            if not ctxId in DltAnalyzer.dltData[ecuId][apId]:
                DltAnalyzer.dltData[ecuId][apId][ctxId] = {'cnt': long(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, verbose)
            try:
                #string = buf.value.decode("utf8")
                string = buf.value
                string = string.decode().strip()
            except:
                string = [string]

            # check filter #
            if filterGroup:
                skipFlag = True
                for cond in filterGroup:
                    if cond == ecuId or \
                        cond == apId or \
                        cond == 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))
            subtype = \
                (msg.extendedheader.contents.msin & DLT_MSIN_MTIN) \
                    >> DLT_MSIN_MTIN_SHIFT
            try:
                level = DltAnalyzer.msgColorList[subtype]
            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 buffered:
                SysMgr.addPrint(output, force=True, listBuf=True)
            else:
                SysMgr.printPipe(output, flush=True)



    @staticmethod
    def doLogDlt(
        appid='GUID'.encode(), context='GUID'.encode(), msg=None, level='INFO'):
        # 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(
                "fail 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:
            SysMgr.dltObj = None
            SysMgr.printWarn(
                'fail to find %s to log DLT' % SysMgr.libdltPath, True)
            sys.exit(0)

        # register #
        if not SysMgr.dltCtx:
            ctx = DltContext()
            ret = dltObj.dlt_register_app(appid, 'Guider'.encode())
            if ret < 0:
                SysMgr.printErr(
                    "fail to register app '%s'" % appid)
                sys.exit(0)

            ret = dltObj.dlt_register_context(
                byref(ctx), context, 'Guider'.encode())
            if ret < 0:
                SysMgr.printErr(
                    "fail to register context '%s'" % context)
                sys.exit(0)

            SysMgr.dltCtx = ctx

        # log #
        pos = long(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):
                return ret

            pos = end

        '''
        # unregister #
        dltObj.dlt_unregister_context(byref(ctx))
        dltObj.dlt_unregister_app()
        '''



    @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), verbose) == -1:
                SysMgr.printErr(
                    "fail to initialize the DLTFilter object")
                return -1

            if dltObj.dlt_filter_add(
                byref(dltFilter), apid or b"", ctid or b"", verbose) == -1:
                SysMgr.printErr(
                    "fail to add %s and %s to the DLTFilter object" % \
                        (apid, ctid))
                return -1

            if dltFilter.counter >= DltAnalyzer.DLT_FILTER_MAX:
                SysMgr.printErr((
                    "fail 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), verbose)

        # 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 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 */
                 int32_t buffersize;       /**< size of receiver buffer */
             } 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),
                ("buffersize", c_int32)
            ]

        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;
            '''

            _pack_ = 1
            _fields_ = [
                    ("receiver", DltReceiver),
                    ("sock", c_int),
                    ("servIP", c_char_p),
                    ("port", c_int),
                    ("serialDevice", c_char_p),
                    ("socketPath", c_char_p),
                    ("ecuid", c_char * DLT_ID_SIZE),
                    ("baudrate", c_int),
                    ("mode", 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;
            '''
            _pack_ = 1
            _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;
            '''
            _pack_ = 1
            _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;
            '''
            _pack_ = 1
            _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;
            '''
            _pack_ = 1
            _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;
            '''

            _pack_ = 1
            _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 informations, 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;
            '''

            _pack_ = 1
            _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;          /**< messsage info */
                uint8_t noar;          /**< number of arguments */
                char apid[DLT_ID_SIZE];          /**< application id */
                char ctid[DLT_ID_SIZE];          /**< context id */
            } PACKED DltExtendedHeader;
            '''

            _pack_ = 1
            _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;
            '''

            _pack_ = 1
            _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(
                'fail to find %s to get DLT log' % \
                    SysMgr.libdltPath, always=True, reason=True)
            sys.exit(0)

        # define verbose #
        if SysMgr.warnEnable:
            # set log level to DEBUG #
            if hasattr(dltObj, 'dlt_log_set_level'):
                dltObj.dlt_log_set_level(LogMgr.LOG_DEBUG)

            verbose = 1
        else:
            verbose = long(0)

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

        try:
            from socket import socket, AF_INET, SOCK_DGRAM,\
                SOCK_STREAM, SOL_SOCKET, SO_REUSEADDR, SO_RCVBUF,\
                create_connection, MSG_PEEK, MSG_DONTWAIT
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "fail to import socket", True)
            sys.exit(0)

        # 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():
            flist = SysMgr.getMainArg().split(',')
            flist = UtilMgr.cleanItem(flist)
            if not flist:
                SysMgr.printErr("no path for DLT file")
                sys.exit(0)
        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("no path for DLT file")
                sys.exit(0)

        # check sort option #
        if SysMgr.findOption('S'):
            buffered = True
            SysMgr.printStreamEnable = 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 = None

            DltAnalyzer.msgColorList.append(
                UtilMgr.convColor(item, color, 5, 'left'))

        # messages from file #
        if mode == 'print' and flist:
            for path in flist:
                # convert path string to utf-8 format #
                path = UtilMgr.encodeStr(path)

                # initialize file object #
                ret = dltObj.dlt_file_init(byref(dltFile), verbose)
                if ret < 0:
                    SysMgr.printErr(
                        "fail to initialize a DLTFile object")

                # set filter #
                #_setFilter(dltObj, dltFilter, dltFile, apid=b"", ctid=b"", init=True)

                # open file #
                ret = dltObj.dlt_file_open(byref(dltFile), path, verbose)
                if ret != 0:
                    SysMgr.printErr(
                        "fail to open %s" % path)
                    return
                elif dltFile.file_length == 0:
                    SysMgr.printErr(
                        "fail to read %s because size is 0" % path)
                    return

                # read a file #
                while dltFile.file_position < dltFile.file_length:
                    ret = dltObj.dlt_file_read(byref(dltFile), verbose)
                    # storage header corrupted #
                    if ret < 0:
                        nextHeaderPos = \
                            _findNextHeader(path, dltFile.file_position)
                        if nextHeaderPos is not None:
                            if dltFile.file_position == nextHeaderPos:
                                break
                            else:
                                dltFile.file_position = nextHeaderPos
                        else:
                            break

                # read messages #
                for index in range(0, dltFile.counter_total):
                    ret = dltObj.dlt_file_message(
                        byref(dltFile), index, verbose)
                    if ret < 0:
                        SysMgr.printWarn(
                            "fail to read %s message from %s" %
                                (index, path), True)
                        continue

                    # print message #
                    DltAnalyzer.handleMessage(
                        dltObj, dltFile.msg, buf, mode, verbose, buffered)

                # free file object #
                ret = dltObj.dlt_file_free(byref(dltFile), verbose)
                if ret < 0:
                    SysMgr.printErr(
                        "fail to free a DLTFile object")

            # 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(
                "fail 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.defaultPort:
                    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(
                "fail to get the address of dlt-daemon", True)
            sys.exit(0)

        # connect to server #
        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
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "fail to connect to dlt-daemon with %s:%s" % \
                    (servIp, servPort), True)
            sys.exit(0)

        # initialize client #
        dltClient = DltClient()
        dltObj.dlt_client_init(byref(dltClient), verbose)
        sockno = c_int(connSock.fileno()) # pylint: disable=no-member
        dltClient.sock = sockno
        dltClient.receiver.fd = sockno
        #dltObj.dlt_client_cleanup(byref(dltClient), verbose)

        # change default log level #
        try:
            if SysMgr.customCmd:
                val = SysMgr.customCmd[0].upper()
                level = DltAnalyzer.LOGLEVEL[val]
                dltObj.dlt_client_send_all_log_level(byref(dltClient), level)
        except:
            SysMgr.printErr(
                "fail to set %s to default log level" % val)
            sys.exit(0)

        # 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 range(0, appids):
                    app = resp.log_info_type.app_ids[idx]
                    for num in range(0, 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(
                "fail 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

            ret = dltObj.dlt_receiver_init(
                byref(dltReceiver), c_int(nrConnSock), c_int(RECVBUFSIZE))
            if ret < 0:
                SysMgr.printErr(
                    "fail to initialize DLT receiver")
                sys.exit(0)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "fail to initialize connection", True)
            sys.exit(0)

        # define receiver symbol #
        try:
            if hasattr(dltObj, 'dlt_receiver_receive_socket'):
                dlt_receiver_receive = dltObj.dlt_receiver_receive_socket
            elif hasattr(dltObj, 'dlt_receiver_receive'):
                dlt_receiver_receive = dltObj.dlt_receiver_receive
            else:
                raise Exception('no DLT receiver')
        except:
            SysMgr.printErr(
                "fail to get dlt_receiver_receive symbol")
            sys.exit(0)

        # 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()

        if mode == 'top':
            SysMgr.printInfo(
                "start collecting DLT log... [ STOP(Ctrl+c) ]")
        elif mode == 'print':
            SysMgr.printInfo(
                "start printing DLT log... [ STOP(Ctrl+c) ]\n")

        while 1:
            try:
                # initialize message #
                ret = dltObj.dlt_message_init(byref(msg), verbose)
                if ret < 0:
                    SysMgr.printErr(
                        "fail to initialize DLT message")
                    sys.exit(0)

                # check DLT data to be read #
                try:
                    ret = dlt_receiver_receive(byref(dltReceiver), 0)
                    if ret <= 0:
                        continue
                except:
                    sys.exit(0)

                # check DLT data to be read #
                while 1:
                    ret = dltObj.dlt_message_read(
                        byref(msg), cast(dltReceiver.buf, POINTER(c_char_p)),
                        c_uint(dltReceiver.bytesRcvd), c_int(0), c_int(verbose))
                    if ret != 0:
                        # move receiver buffer pointer to start of the buffer #
                        ret = dltObj.dlt_receiver_move_to_begin(
                            byref(dltReceiver))
                        if ret < 0:
                            SysMgr.printErr(
                                "fail to move the pointer to receiver buffer")
                            sys.exit(0)

                        break

                    # 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(
                            "fail to remove data from buffer")
                        sys.exit(0)

                    # print DLT message #
                    if verbose:
                        dltObj.dlt_message_print_ascii(
                            byref(msg), byref(buf),
                            c_uint32(msg.headersize), c_int(verbose))

                    # 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()))

                    DltAnalyzer.handleMessage(dltObj, msg, buf, mode, verbose)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn(
                    "fail to process DLT message", True, reason=True)
                continue

        # free message #
        dltObj.dlt_message_free(msg, verbose)





class Debugger(object):
    """ Debugger for ptrace """

    globalEvent = None
    gLockObj = None
    gLockPath = None
    dbgInstance = None
    selfInstance = None
    RETSTR = None
    targetNum = -1

    exceptWait = False
    exceptNoSymbol = False
    traceInjection = False
    exceptLD = False
    noMute = False

    def getSigStruct(self):
        class _sifields_sigfault_t(Union):
            _fields_ = (
                ("_addr", c_void_p),
            )

        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))),
                ("_sigchld", _sifields_sigchld_t),
                ("_sigfault", _sifields_sigfault_t),
                #        ("_kill", _sifields_kill_t),
                #        ("_timer", _sifields_timer_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 range(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 range(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),  # FIXME: ppc64 => softe
                    ("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 updateCurrent(self):
        self.current = time.time()
        if self.timeDelay == 0:
            self.timeDelay = time.time() - self.current



    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.sampleStatus = True
        self.attached = attach
        self.execCmd = execCmd
        self.arch = arch = SysMgr.getArch()
        self.skipInst = 5
        self.syscall = ''
        self.bufferedStr = ''
        self.mapFd = None
        self.pmap = None
        self.prevPmap = None
        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.sampleTime = long(0)
        self.targetNum = 0
        self.childNum = 0
        self.startProfTime = False

        # set character for word decoding #
        if ConfigMgr.wordSize == 4:
            self.decodeChar = 'I'
        else:
            self.decodeChar = 'Q'

        # timestamp variables #
        self.current = 0
        self.timeDelay = 0
        self.dstart = 0
        self.vdiff = 0
        self.updateCurrent()

        self.args = []
        self.values = []
        self.fileList = []
        self.addrList = []
        self.callstack = []
        self.overlayfsList = []
        self.totalCall = long(0)
        self.syscallAddr = None
        self.syscallFound = True
        self.callTable = {}
        self.btTable = {}
        self.fileTable = {}
        self.bpList = {}
        self.bpNewList = {}
        self.entryTime = {}
        self.retCmdList = {}
        self.retFilterList = {}
        self.exceptBpList = {}
        self.targetBpList = {}
        self.targetBpFileList = {}
        self.exceptBpFileList = {}
        self.symbolCacheList = dict()
        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.prevBtList = None
        self.prevBtStr = None
        self.startAddr = None
        self.prevSym = None

        self.lockObj = None
        self.tempPage = 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

        self.peekIdx = ConfigMgr.PTRACE_TYPE.index('PTRACE_PEEKTEXT')
        self.pokeIdx = ConfigMgr.PTRACE_TYPE.index('PTRACE_POKEDATA')
        self.tkillIdx = ConfigMgr.sysList.index('sys_tkill')

        plist = ConfigMgr.PTRACE_TYPE
        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')

        self.ignoreItemList = \
            list(map(lambda x: x.encode(), SysMgr.ignoreItemList))

        # 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

        # check ptrace scope #
        if Debugger.checkPtraceScope() < 0:
            raise Exception('no ptrace permission')

        # 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)



        # 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:
                SysMgr.printErr(
                    'fail to find %s(%s)' % (self.comm, pid))
                sys.exit(0)

            # update comm #
            if not self.comm:
                self.comm = SysMgr.getComm(self.pid, cache=True)

            if attach:
                if self.attach(verb=True) < 0:
                    sys.exit(0)
        # execute #
        elif self.execCmd:
            self.execute(self.execCmd)
            if mode == 'signal':
                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
        if 'ELAPSED' in SysMgr.environList:
            self.retTime = float(SysMgr.environList['ELAPSED'][0])

        # set target sequence #
        if Debugger.targetNum == -1 and \
            'TARGETNUM' in SysMgr.environList:
            Debugger.targetNum = long(SysMgr.environList['TARGETNUM'][0])
            SysMgr.printInfo(
                "set the number of target to '%s' for new threads" % \
                    Debugger.targetNum)

        # apply color for return string #
        if not Debugger.RETSTR:
            Debugger.RETSTR = UtilMgr.convColor('[RET]', 'OKBLUE')

        # enable injection trace #
        if not Debugger.traceInjection and \
            'TRACEINJECTION' in SysMgr.environList:
            Debugger.traceInjection = True

        # ignore wait function #
        if not Debugger.exceptWait and \
            'EXCEPTWAIT' in SysMgr.environList:
            Debugger.exceptWait = True

        # ignore non-symbol function #
        if not Debugger.exceptNoSymbol and \
            'EXCEPTNOSYM' in SysMgr.environList:
            Debugger.exceptNoSymbol= True

        # ignore ld function #
        if not Debugger.exceptLD and \
            'EXCEPTLD' in SysMgr.environList:
            Debugger.exceptLD = True

        # ignore mute #
        if not Debugger.noMute and \
            'NOMUTE' in SysMgr.environList:
            Debugger.noMute = 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

        if not self.isAlive():
            return

        # kill childs #
        if hasattr(self, 'childList'):
            SysMgr.killChilds(sig=signal.SIGINT, childs=self.childList)
            del self.childList

        # detach target #
        self.detach()

        # continue target #
        try:
            if stop:
                os.kill(self.pid, signal.SIGSTOP)
            elif self.isStopped():
                os.kill(self.pid, signal.SIGCONT)
        except:
            SysMgr.printSigError(self.pid, 'SIGCONT')
            return



    @staticmethod
    def hookFunc(pid, hookList=[], mode='hook'):
        # attach to target #
        try:
            comm = SysMgr.getComm(pid)
            procInfo = '%s(%s)' % (comm, pid)
            dobj = Debugger(pid=pid, attach=False)
            dobj.initValues()
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("fail to hook for %s" % procInfo, True)
            sys.exit(0)

        # load libraries in advance #
        dobj.loadSymbols()
        if dobj.attach() < 0:
            sys.exit(0)

        # 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("fail to recognize '%s'" % item)
                sys.exit(0)

            # 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("fail to recognize '%s'" % item)
                sys.exit(0)

            # 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 = ''

                dobj.loadSymbols()
                if not fpath in dobj.pmap:
                    SysMgr.printErr(
                        "fail to find '%s' on memory map for %s%s" % \
                            (fpath, procInfo, errMsg))

                    PageAnalyzer.printMemoryArea(
                        pid, comm=comm, lastLine=True)

                    sys.exit(0)

            # get target symbol info #
            oldSet = dobj.getAddrBySymbol(oldSym)
            if not oldSet:
                SysMgr.printWarn(
                    "fail to find '%s' info from %s" % (oldSym, procInfo))
                continue

            # get hook symbol info #
            newSet = dobj.getAddrBySymbol(newSym, fpath)
            if not newSet:
                SysMgr.printErr(
                    "fail 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], verbose=False)

        # print context #
        dobj.printContext(regs=SysMgr.showAll, newline=True)

        # define link list #
        linkList = {}
        convColor = UtilMgr.convColor

        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, list())
                    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 = hook[0]
                hookSym = hook[1]
                hookBin = hook[2]

                # target info #
                target = item[0][0]
                targetAddr = target[0]
                targetSym = target[1]
                targetBin = target[2]

                # 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)

                # check update result #
                if hookAddr == newAddr:
                    SysMgr.printInfo(
                        "updated %s(%s@%s) to %s(%s@%s) for %s" % \
                            (targetSym, hex(targetAddr), fpath, hookSym,
                                hex(hookAddr), hookBin, procInfo),
                                    prefix=False)
                else:
                    SysMgr.printErr(
                        "fail to update %s(%s@%s) to %s(%s@%s) for %s" % \
                            (targetSym, hex(targetAddr), fpath,
                                hookSym, hex(hookAddr), hookBin, procInfo))

        # continue target #
        SysMgr.sendSignalProcs(signal.SIGCONT, [pid], verbose=False)

        if not linkList:
            return

        # set pager #
        if not SysMgr.findOption('Q'):
            SysMgr.printStreamEnable = 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):
        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')

            if size != 0:
                Debugger.gLockObj.truncate(size)

        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "fail to create %s for lock" % Debugger.gLockPath, True)

            if not SysMgr.forceEnable:
                sys.exit(0)

        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.r10, 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('fail 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:
                    pass

        return argList



    def executeCmd(self, cmdList, sym=None, fname=None, args=[]):
        def _flushPrint(newline=True):
            if SysMgr.outPath:
                if SysMgr.showAll:
                    self.callPrint.append(SysMgr.bufferString[1:])

                # print to stdout #
                if SysMgr.printStreamEnable:
                    sys.stdout.write(SysMgr.bufferString)
            else:
                SysMgr.printPipe(
                    SysMgr.bufferString, flush=True, newline=newline)

            SysMgr.clearPrint()

        def _printCmdErr(cmdset, cmd):
            if cmd == 'print':
                cmdformat = "VAR"
            elif cmd == 'exec':
                cmdformat = "COMMAND"
            elif cmd == 'ret':
                cmdformat = "VAL"
            elif cmd == 'check':
                cmdformat = \
                    "VAR|NAME|ADDR|REG:OP(EQ/DF/INC/BT/LT):VAL:SIZE:EVENT"
            elif cmd == 'getret':
                cmdformat = "CMD"
            elif cmd == 'setret':
                cmdformat = "VAL:CMD"
            elif cmd == 'getarg':
                cmdformat = "REG:REG"
            elif cmd == 'setarg':
                cmdformat = "REG#VAL:REG#VAL"
            elif cmd == 'wrmem':
                cmdformat = "VAR|ADDR|REG:VAL:SIZE"
            elif cmd == 'rdmem':
                cmdformat = "VAR|ADDR|REG:SIZE"
            elif cmd == 'jump':
                cmdformat = "SYMBOL|ADDR#ARG0#ARG1"
            elif cmd == 'usercall':
                cmdformat = "FUNC#ARG0#ARG1"
            elif cmd == 'syscall':
                cmdformat = "SYSCALL#ARG0#ARG1"
            elif cmd == 'load':
                cmdformat = "PATH"
            elif cmd == 'save':
                cmdformat = "VAR:VAL:TYPE"
            elif cmd == 'acc':
                cmdformat = "NAME:VAR|NAME|REG|VAL"
            elif cmd == 'dist':
                cmdformat = "NAME:VAR|NAME|REG|VAL"
            elif cmd == 'dump':
                cmdformat = "NAME|ADDR:FILE"
            elif cmd == 'start':
                cmdformat = ""
            elif cmd == 'exit':
                cmdformat = ""
            elif cmd == 'condexit':
                cmdformat = ""
            elif cmd == 'map':
                cmdformat = ""
            elif cmd == 'stop':
                cmdformat = ""
            elif cmd == 'setenv':
                cmdformat = "VAR#VAR|VAL"
            elif cmd == 'getenv':
                cmdformat = "VAR"
            elif cmd == 'repeat':
                cmdformat = "CNT"
            elif cmd == 'thread':
                cmdformat = ""
            elif cmd == 'pystr':
                cmdformat = "CODE:SYNC"
            elif cmd == 'pyfile':
                cmdformat = "PATH:SYNC"
            elif cmd == 'log':
                cmdformat = "MESSAGE"
            else:
                cmdformat = ""

            if cmdformat:
                cmdformat = ":%s" % cmdformat
            SysMgr.printErr(
                "wrong command '%s', input in the format {%s%s}" % \
                    (cmdset, cmd, cmdformat))
            sys.exit(0)

        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, 'BOLD', 8)

            if cmd == 'print':
                if SysMgr.showAll:
                    pass
                elif len(cmdset) == 1:
                    self.printContext(newline=True)
                else:
                    var = cmdset[1]
                    try:
                        data = self.retList[var]
                    except:
                        data = 'N/A'

                    SysMgr.addPrint(
                        "\n[%s] %s = %s" % (cmdstr, var, data))

            elif cmd == 'map':
                PageAnalyzer.printMemoryArea(
                    self.pid, comm=self.comm, lastLine=True)

            elif cmd == 'exec':
                if len(cmdset) == 1:
                    _printCmdErr(cmdval, cmd)

                SysMgr.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()

                    self.execBgCmd(execCmd=param, mute=False, wait=wait)

            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
                SysMgr.addPrint("\n[%s] %s" % (cmdstr, 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((
                        "fail 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

                # inject the new breakpoint for return #
                ret = self.setRetBp(sym, fname, cmd)
                if not ret:
                    SysMgr.printErr((
                        "fail to set breakpoint to "
                        "return address for %s") % sym)
                    return repeat

                # register a return value #
                newSym = '%s%s' % (sym, Debugger.RETSTR)
                val = memset[0]
                try:
                    num = long(val, 16)
                except:
                    num = long(val)
                self.setRetList[newSym] = num

                # print return value #
                SysMgr.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]

                SysMgr.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(',')]

                SysMgr.addPrint("\n[%s] %s" % (cmdstr, res))

            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

                SysMgr.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(
                        "fail to write '%s' to %s" % \
                            (val.decode(), hex(addr).rstrip('L')))
                    return repeat

            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:
                    SysMgr.addPrint(
                        "\n[%s] %s(%s)" % (cmdstr, self.comm, self.pid))

            elif cmd == 'pystr' or cmd == '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()

                SysMgr.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'

                SysMgr.addPrint(
                    "\n[%s] %s(%s)->%s (%s)" % \
                        (cmdstr, meminfo,
                            UtilMgr.convSize2Unit(size), output, res))

            elif cmd == 'check':
                cmds = ':'.join(cmdset)
                ret = self.checkFilterCond(cmds, args, sym, fname)

                # broadcast event #
                if ret:
                    params = cmdset[1].split(':')
                    if len(params) > 4:
                        SysMgr.broadcastEvent(params[4])

                # change color for False #
                if ret:
                    ret = convColor(ret, 'GREEN')
                else:
                    ret = convColor(ret, 'RED')

                SysMgr.addPrint(
                    "\n[%s] %s = %s" % (cmdstr, cmdset[1], ret))

            elif cmd == 'acc' or cmd == '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 type(data) is 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': long(0), 'total': long(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(val))
                    except:
                        import math
                        idx = long(math.sqrt(val))

                    self.accList[name].setdefault('dist', dict())
                    self.accList[name]['dist'].setdefault(idx, 0)
                    self.accList[name]['dist'][idx] += 1
                    dist = self.accList[name]['dist']
                else:
                    dist = ''

                SysMgr.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 == '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(
                        "fail 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:
                    ret = ret.split("\x00")[0]
                    size = len(ret)

                # 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 = ''

                SysMgr.addPrint(
                    "\n[%s] %s: %s(%sbyte)%s" % \
                        (cmdstr, hex(addr).rstrip('L'), \
                            repr(ret), size, binstr))

            elif cmd == 'start':
                SysMgr.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 == '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((
                            "fail to set breakpoint to "
                            "return address for %s") % sym)

                output = "\n[%s] %s%s" % (cmdstr, sym, rstr)
                SysMgr.addPrint(output)

            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)
                SysMgr.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 = 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)
                SysMgr.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)
                SysMgr.addPrint(output)
                _flushPrint(newline=False)

                # remove a breakpoint for syscall #
                self.removeBp(self.getSyscallAddr(), lock=True)

                # call function #
                ret = self.remoteSyscall(val, argList)
                if ret is None:
                    ret = 0

                # update return #
                self.retList[val] = str(ret)
                self.prevReturn = str(ret)

                SysMgr.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 berakpoints #
                if not skip:
                    self.removeAllBp(verb=False)

                SysMgr.addPrint(output)
                _flushPrint(newline=False)

                if not skip:
                    # call function #
                    ret = self.remoteUsercall(addr, argList)
                    if ret is None:
                        ret = 0

                    # update return #
                    self.retList[val] = str(ret)
                    self.prevReturn = str(ret)

                    SysMgr.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

                SysMgr.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])

                SysMgr.addPrint("\n[%s] %g sec" % (cmdstr, val))
                _flushPrint(newline=False)

                time.sleep(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 berakpoints #
                self.removeAllBp(verb=False)

                SysMgr.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)

                SysMgr.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 berakpoints #
                self.removeAllBp(verb=False)

                SysMgr.addPrint(output)
                _flushPrint(newline=False)

                # call function #
                ret = self.getenv(val)

                # update return #
                self.retList[val] = str(ret)
                self.prevReturn = str(ret)

                SysMgr.addPrint(' = %s' % ret)
                _flushPrint(newline=False)

                # inject all breakpoints again #
                self.updateBpList(verb=False)

            elif cmd == 'stop':
                SysMgr.addPrint("\n[%s]\n" % (cmdstr))
                _flushPrint(newline=False)

                SysMgr.blockSignal(act='unblock')
                SysMgr.waitEvent(exit=True)

            elif cmd == 'kill':
                SysMgr.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]

                SysMgr.addPrint("\n[%s] %s" % (cmdstr, val))

            elif cmd == 'condexit':
                if self.startProfTime:
                    diff = self.vdiff - self.startProfTime
                    diff = convColor('%.6f' % diff, 'RED')
                    SysMgr.addPrint("\n[%s] %s\n" % (cmdstr, diff))
                    sys.exit(0)

            elif cmd == 'exit':
                SysMgr.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 = list()

        convNum = UtilMgr.convNum

        # disable stream #
        origin = SysMgr.printStreamEnable
        if origin and SysMgr.outPath:
            SysMgr.printStreamEnable = False

        for cmdval in cmdList:
            # parse cmd set #
            cmdset = cmdval.split(':', 1)
            cmd = cmdset[0]

            # execute a command #
            try:
                repeat = _handleCmd(cmdset, cmd)
            except SystemExit:
                _flushPrint()
                sys.exit(0)
            except:
                _flushPrint()
                SysMgr.printErr(
                    "fail to handle '%s' command" % cmd, True)
                sys.exit(0)

            # re-register command #
            if repeat:
                newCmdList.append(cmdval)

        # recovery stream #
        SysMgr.printStreamEnable = origin

        _flushPrint(False)

        return newCmdList



    def setTraceme(self):
        cmd = ConfigMgr.PTRACE_TYPE.index('PTRACE_TRACEME')
        return self.ptrace(cmd)



    def execBgCmd(self, execCmd, mute=True, wait=True):
        pid = SysMgr.createProcess()
        if pid < 0:
            return pid
        elif pid > 0:
            if wait:
                os.waitpid(pid, 0)
            return

        # execute #
        SysMgr.executeProcess(cmd=execCmd, mute=mute)

        # execute fail #
        os._exit(0)



    def execute(self, execCmd, mute=True):
        # check mute flag #
        if Debugger.noMute:
            mute = False

        pid = SysMgr.createProcess()
        if pid == 0:
            self.pid = os.getpid()

            # set tracee flag #
            self.setTraceme()

            # execute #
            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):
        # ignore breakpoints for command #
        if self.execCmd:
            return

        if not tgid:
            tgid = self.pid

        # check fault flag from shared memory #
        if self.getFaultFlag():
            return

        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.keys())):
            if verb:
                UtilMgr.printProgress(idx, len(self.bpList))
            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.traceInjection:
            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 convertFilterValue(self, origCmdSet):
        cmdSet = list()
        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(
                            "fail to recognize %s as a number" % val, True)
                        sys.exit(0)

            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.keys()):
            # 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.keys()):
                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 = list()
            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)
        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.convertFilterValue(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 cnt in range(0, 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:
                found = False
                for binary in binlist:
                    if binary in self.pmap:
                        found = True
                        break
                if not found:
                    SysMgr.printErr(
                        "fail to find '%s' on memory map" % \
                            ', '.join(binlist))

                    PageAnalyzer.printMemoryArea(
                        self.pid, comm=self.comm, lastLine=True)

                    sys.exit(0)

            # no symbol #
            SysMgr.printErr(
                "fail to find address for symbol '%s'" % value)
            sys.exit(0)

        return addrList, cmdList



    def injectBpList(self, symList, binList=None, verb=True):
        exceptList = list()
        if symList:
            newList = list()
            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 #
            ret = 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]

        for cmd in filterCmd:
            cmdset = cmd.split(':', 1)
            if len(cmdset) == 1:
                _printErr(cmd)
                return False

            # get argument info #
            memset = cmdset[1].split(':')
            if len(memset) < 3:
                _printErr(cmd)
                return False

            # handle return filter #
            if memset[0] == 'RET':
                self.retFilterList[sym] = [memset, None]
                ret = self.setRetBp(sym, fname, cmd)
                if not ret:
                    SysMgr.printErr((
                        "fail to set breakpoint to "
                        "return address for %s") % sym)
                return False

            # 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(
                    "fail to convert %s to number in filter" % addr)
                continue

            if len(memset) == 4:
                size = long(memset[3])
            else:
                size = -1

            # 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(
                        "fail to read from %s" % addr)
                    return False

                ret = ret.decode()
            # get value from register #
            else:
                ret = addr

            # check value #
            # == #
            if op.upper() == 'EQ':
                if ref:
                    if ret[:size] != val:
                        return False
                else:
                    val = str(val)[:size]
                    ret = str(ret)[:size]

                    if ret != val:
                        return False
            # != #
            elif op.upper() == 'DF':
                if ref:
                    if ret[:size] == val:
                        return False
                else:
                    val = str(val)[:size]
                    ret = str(ret)[:size]

                    if ret == val:
                        return False

            # in #
            elif op.upper() == 'INC':
                if ref:
                    if not val in ret[:size]:
                        return False

            # <= or >= #
            elif op.upper() == 'BT' or op.upper() == 'LT':
                if not UtilMgr.isNumber(val):
                    _printErr(cmd)
                    return False

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

                if op.upper() == 'BT' and ret <= val:
                    return False
                elif op.upper() == 'LT' and ret >= val:
                    return False

            else:
                SysMgr.printErr(
                    "fail to recognize operator '%s' for filter" % op)
                return False

        return True



    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(
                "fail to read original data from %s" % \
                    fname, reason=True)
            sys.exit(0)



    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 Debugger.exceptNoSymbol and sym 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'] and Debugger.traceInjection:
                if not sym:
                    sym = self.bpList[addr]['symbol']
                SysMgr.printWarn((
                    'fail 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

            origWord = self.bpList[addr]['data']
            if self.bpList[addr]['reins'] != reins:
                self.bpList[addr]['reins'] = reins
            self.bpList[addr]['set'] = True
        # 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((
                    'fail 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((
                        'fail to inject a breakpoint to %s(%s) for %s' % \
                            (hex(addr).rstrip('L'), sym, procInfo)),
                                reason=True)
                    return

                # load orignal 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((
                    'fail 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(
                'fail to inject a breakpoint to %s(%s) for %s %s' % \
                    (hex(addr).rstrip('L'), sym, procInfo, reason))

            return False
        elif ret == 0 and Debugger.traceInjection:
            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)

        if self.checkPid(pid) < 0:
            SysMgr.printWarn(
                'fail 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')

        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)
                else:
                    reason = ''

                SysMgr.printWarn('fail to attach %s(%s) to guider(%s)%s' % \
                    (self.comm, pid, SysMgr.pid, reason), verb)

                # check return #
                if not cont:
                    return -1
                elif self.isAlive():
                    time.sleep(SysMgr.waitDelay)
                    continue
                else:
                    sys.exit(0)
            else:
                SysMgr.printWarn(
                    'attached %s(%s) to guider(%s)' % \
                        (self.comm, pid, SysMgr.pid))
                self.attached = True
                return 0



    def stop(self, pid=None, thread=True, check=False):
        if not pid:
            pid = self.pid

        if self.checkPid(pid) < 0:
            SysMgr.printWarn(
                'fail to stop %s(%s) because of wrong pid' % \
                    (self.comm, pid))
            return -1

        # send signal to a thread #
        try:
            if thread:
                ret = SysMgr.syscall(self.tkillIdx, pid, signal.SIGSTOP)
                if check:
                    while 1:
                        if self.isStopped():
                            break
                return ret
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn(
                "fail to stop %s(%s)" % (self.comm, pid), reason=True)
            return -1

        # send signal to a process #
        try:
            os.kill(pid, signal.SIGSTOP)
            return 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(
                "fail 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:
                    addr = self.calloc(string=item, temp=False)
                    if not addr:
                        sys.exit(0)

                    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(
                    "fail to alloc memory for %s(%s) because no size" % \
                        (self.comm, self.pid))
                return None

        # use a temporary page #
        addr = None
        if temp:
            addr = self.getTempPage()

        # 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(
                    "fail 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(
                    "fail 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.keys()):
            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.abspath('.')
                path = '%s/%s' % (current, path)

            # check file #
            if not os.path.exists(path):
                SysMgr.printErr(
                    "fail 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("fail 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("fail to call PyFile_FromString")
                    return
                fp = self.remoteUsercall("PyFile_AsFile", [po])
                if not fp:
                    SysMgr.printErr("fail 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("fail 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(
            "fail 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(
                "fail 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(
                    "fail to find attr field 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("fail 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(
                    "fail to write '%s' to %s" % (fname, hex(addr)))
                return None
            '''

        # RTLD_LAZY | RTLD_GLOABL #
        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 type(usercall) is 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(
                "fail 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(
                "fail to set trap for return because %s is not supported" % \
                    self.arch)
            sys.exit(0)

        # 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 type(syscall) is 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 = ConfigMgr.sysList.index(syscall)
                except:
                    SysMgr.printErr("fail to find %s" % syscall, True)
                    return -1
        else:
            SysMgr.printErr(
                "fail 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(
                    "fail 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(
                "fail 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(
                "fail 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(
                'fail to kill %s(%s)' % (self.comm, self.pid))
            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 self.attached:
            return 0

        if not pid:
            pid = self.pid

        if self.checkPid(pid) < 0:
            SysMgr.printWarn(
                'fail to continue %s(%s) because of wrong pid' % \
                    (self.comm, pid))
            return -1

        # check target is running #
        try:
            os.kill(pid, 0)
        except SystemExit:
            sys.exit(0)
        except:
            if not self.isAlive():
                errMsg = \
                    'fail 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
                time.sleep(0.001)

                if cnt < 0:
                    break
                elif not self.isAlive():
                    errMsg = \
                        'fail to continue %s(%s) because it is terminated' % \
                            (self.comm, pid)
                    SysMgr.printErr(errMsg)
                    return -1

        # continue target thread #
        ret = self.ptrace(self.contCmd, 0, sig)
        if ret != 0:
            SysMgr.printWarn(
                'fail to continue %s(%s)' % (self.comm, pid))
            return -1

        return 0



    def doDetach(self, pid, cont=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(
                    'fail to detach %s(%s) from guider(%s)' % \
                        (self.comm, pid, SysMgr.pid))

                # check return #
                if not cont:
                    return -1
                elif self.isAlive():
                    time.sleep(SysMgr.waitDelay)
                    continue
                else:
                    sys.exit(0)
            else:
                SysMgr.printWarn(
                    'detached %s(%s) from guider(%s)' % \
                        (self.comm, pid, SysMgr.pid))
                return 0



    def detach(self, only=False, pid=None, cont=False):
        if only:
            return self.doDetach(pid, cont=cont)

        if not self.attached:
            return

        if hasattr(self, 'pid'):
            pid = self.pid
        else:
            return

        # 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, cont=cont)



    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((
                "fail 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((
                "fail 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 = long(0)
        wordSize = ConfigMgr.wordSize

        if addr < wordSize:
            SysMgr.printWarn((
                "fail 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)
                return ret
            except SystemExit:
                sys.exit(0)
            except:
                self.supportProcessVmWr = False

        # check address alignment #
        offset = addr % wordSize

        # handle interger-type data #
        if not skipCheck:
            if UtilMgr.isNumber(data):
                if offset == 0:
                    if size == 0:
                        size = 1
                    for idx in range(0, 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((
                    "fail 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 range(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.keys())



    def updateBpList(self, verb=True):
        if self.mode != 'break':
            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((
                "fail 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 size == 0:
            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)
                if ret == 0:
                    return None

                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:
                if verb:
                    SysMgr.printErr(
                        "fail 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 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 range(0, 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 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 SysMgr.optStrace or namelen == 0:
            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 range(0, iovlen):
                offset = idx * sizeof(self.iovec)

                # get iov object #
                iovobj = self.readMem(
                    iovaddr+offset, sizeof(self.iovec))
                iovobjOrig = iovobj
                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 SysMgr.encodeB64Enable:
                    iovobjdata = UtilMgr.encodeBase64(iovobjdata)
                    if sys.version_info >= (3, 0):
                        iovobjdata = iovobjdata.decode('latin-1')

                # 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 #
        return msginfo

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

        # 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):
            control = self.readMem(header.contents.msg_control, controllen)
            controlobj = cast(control, self.cmsghdr_ptr)

            cmsglen = long(controlobj.contents.cmsg_len)
            cmsglevel = controlobj.contents.cmsg_level
            cmsgtype = controlobj.contents.cmsg_type

            msginfo['msg_control']['cmsglen'] = cmsglen
            if socket and cmsglevel == socket.SOL_SOCKET:
                msginfo['msg_control']['cmsglevel'] = 'SOL_SOCKET'
            else:
                msginfo['msg_control']['cmsglevel'] = cmsglevel
            try:
                msginfo['msg_control']['cmsgtype'] = \
                    ConfigMgr.CMSG_TYPE[cmsgtype]
            except:
                msginfo['msg_control']['cmsgtype'] = cmsgtype

        return msginfo



    def convSyscallParam(
        self, argtype, argname, value, seq=0, ref=True, argset={}, buf=False):

        syscall = self.syscall

        # toDo: convert a integer or mask values #

        # handle process_vm_readv #
        pass

        # handle sendmsg / recvmsg #
        if syscall == "sendmsg" or syscall == "recvmsg":
            if ref and argname == "msg":
                try:
                    return self.readMsgHdr(value)
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printWarn(
                        "fail to get msghdr for %s" % \
                            syscall, True, reason=True)

        # handle sendmmsg / recvmmsg #
        if 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(
                        "fail to get mmsghdr for %s" % \
                            syscall, True, reason=True)

        # convert fd to name #
        if argname == "fd" and ref:
            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 value

        # handle special syscalls #
        if syscall == "execve":
            if argname in ("argv", "envp"):
                # toDo: handle double pointer values #
                return value

        if syscall == "ptrace" and argname == "request":
            try:
                return ConfigMgr.PTRACE_TYPE[value]
            except:
                return value

        if ref and argtype == "const char *" and \
            (argname.endswith("name") or argname.endswith("path")):
            addr = self.values[seq]
            # redundant call after execve #
            if addr == 0:
                return value
            else:
                return self.readString(addr)

        if syscall == "socketcall":
            if argname == "call":
                try:
                    return ConfigMgr.SOCKETCALL[value]
                except:
                    return value
            elif argname == "args":
                # toDo: handle socket call args #
                return value

        if 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)

        if syscall.startswith('fcntl'):
            if argname == 'cmd':
                return ConfigMgr.FCNTL_TYPE[value]

        if syscall.startswith('futex'):
            if argname == 'op':
                if value < len(ConfigMgr.FUTEX_TYPE):
                    return ConfigMgr.FUTEX_TYPE[value]

                # check _PRIVATE FLAG #
                value = value & 0x16
                if value < len(ConfigMgr.FUTEX_TYPE):
                    return ConfigMgr.FUTEX_TYPE[value] + '_PRIVATE'

        if syscall == 'open':
            if argname == 'flags':
                return UtilMgr.getFlagString(
                    value, ConfigMgr.OPEN_TYPE, num='oct')

        if argname == 'whence':
            return ConfigMgr.SEEK_TYPE[int(value)]

        if syscall == 'access':
            if argname == 'mode':
                return UtilMgr.getFlagString(
                    value, ConfigMgr.PERM_TYPE)

        if syscall == 'clone':
            if argname == 'flags':
                return UtilMgr.getFlagString(
                    value, ConfigMgr.CLONE_TYPE)

        if syscall == 'prctl':
            if argname == 'option':
                try:
                    return ConfigMgr.PRCTL_TYPE[value]
                except:
                    return value

        if argname == 'behavior' and \
            syscall.startswith('madvise'):
            try:
                return ConfigMgr.MADV_TYPE[int(value)]
            except:
                return value

        if buf and argname == "buf" and \
            (syscall == "write" or syscall == "read"):
            if self.values[2] > self.pbufsize:
                length = self.pbufsize
            else:
                length = self.values[2]

            # read string from address #
            ret = self.readMem(value, length)
            if ret:
                value = ret

            try:
                return repr(value)[1:-1]
            except SystemExit:
                sys.exit(0)
            except:
                return repr(value)

        if argname == "flags" and value:
            if syscall.startswith('send') or \
                syscall.startswith('recv'):
                return UtilMgr.getFlagString(
                    value, ConfigMgr.MSG_TYPE)

        if argname == "signum" or argname == "sig":
            return ConfigMgr.SIG_LIST[int(value)]

        # remove const prefix #
        if argtype.startswith("const "):
            argtype = argtype[6:]

        # toDo: handle file path #
        pass

        # 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):
            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 childs #
                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, 15, 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 = list()
        _iterNode(tagList, callTree, callCnt)
        return '\n'.join(tagList)



    @staticmethod
    def drawFlame(inputFile):
        # set output path #
        outputPath = UtilMgr.getDrawOutputPath(inputFile, 'flamegraph')

        # get list for call samples #
        try:
            callList, title = Debugger.getCallStatsFile(inputFile)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "fail to get call samples from '%s'" % inputFile, True)
            sys.exit(0)

        # convert list to tree for call samples #
        try:
            callTree, callCnt = Debugger.convCallList2Tree(callList)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "fail to convert call samples from '%s'" % inputFile, True)
            sys.exit(0)

        # make svg string #
        try:
            svgStr = Debugger.makeSvgString(callTree, callCnt)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "fail to make flamegraph from '%s'" % inputFile, True)
            sys.exit(0)

        # write svg code to the file #
        try:
            UtilMgr.writeFlamegraph(outputPath, svgStr, title)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "fail to save flamegraph from '%s' to '%s'" % \
                    (inputFile, SysMgr.outPath), True)
            sys.exit(0)



    @staticmethod
    def convCallList2Tree(callList):
        def _getObj():
            return dict(cnt=0, child=dict())

        tree = {}
        totals = {}
        pos = None

        # 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

        return tree, totals



    @staticmethod
    def getCallStatsFile(logFile):
        # get file handle #
        try:
            fd = UtilMgr.getTextLines(logFile, retfd=True)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("fail to read %s\n" % logFile)
            sys.exit(0)

        stack = ''
        main = ''
        mainCnt = 0
        context = None
        samples = {}
        title = None

        for line in fd:
            # get start keyword #
            if line.startswith('[Top '):
                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 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 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 == True:
            value = 1
        else:
            value = 0

        if sys.version_info < (3, 0, 0):
            value = bytes(value)

        Debugger.globalEvent[0] = value # pylint: disable=unsupported-assignment-operation



    @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 == True:
            value = 1
        else:
            value = 0

        if sys.version_info < (3, 0, 0):
            value = bytes(value)

        Debugger.globalEvent[1] = value # pylint: disable=unsupported-assignment-operation



    @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():
            # initialize syscall timetable #
            self.syscallStat = dict()
            self.brkcallStat = dict()

            # reset data #
            self.totalCall = long(0)
            self.callTable = dict()
            SysMgr.clearPrint()

        def _checkInterval():
            if SysMgr.repeatCount == 0:
                return

            SysMgr.progressCnt += 1
            if SysMgr.repeatCount <= SysMgr.progressCnt:
                sys.exit(0)

        def _finishPrint():
            # print stats #
            SysMgr.printTopStats()

            # check and update repeat count #
            _checkInterval()

            _resetStats()

        # check samples #
        if not self.callTable:
            if not self.sampleStatus:
                SysMgr.printWarn(
                    "no sample data for %s(%s)" % \
                        (self.comm, self.pid), True)
            _resetStats()
            return

        # update status for sample collection #
        self.sampleStatus = True

        # check user input #
        SysMgr.waitUserInput(
            wait=0.000001, msg="press enter key...")

        # define stop flag #
        needStop = False

        # set time #
        SysMgr.updateUptime()
        current = time.time()
        diff = current - self.last
        self.last = current

        # update comm #
        origComm = self.comm
        self.comm = SysMgr.getComm(self.pid)
        if not self.comm:
            self.comm = origComm

        # check comm filter for child #
        if (self.execCmd and SysMgr.filterGroup) or Debugger.targetNum > -1:
            if UtilMgr.isValidStr(self.comm, inc=True):
                pass
            elif Debugger.targetNum == self.targetNum:
                pass
            else:
                # skip on break mode #
                if self.mode == 'break':
                    _resetStats()
                    return

                # print status #
                SysMgr.printWarn(
                    'stopped tracing for %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()

                _resetStats()
                return

        # print summary table #
        if self.mode == 'syscall':
            ctype = 'Syscall'
            addInfo = '<Elapsed>'
            sampleStr = ''
        elif self.mode == 'break':
            ctype = 'Breakcall'
            addInfo = '[PATH] <Interval>'
            sampleStr = ''
        else:
            if self.mode == 'pycall':
                ctype = 'Pycall'
            else:
                ctype = 'Usercall'
            addInfo = '[PATH] <Sample>'
            sampleStr = ' [SampleRate: %g]' % self.sampleTime

            # continue target to prevent too long freezing #
            if self.traceStatus and self.isAlive():
                if self.cont(check=True) == 0:
                    needStop = True

        nrTotal = float(self.totalCall)
        convert = UtilMgr.convNum

        # get CPU Usage for target #
        cpuUsage = self.getCpuUsage()
        ttime = cpuUsage[0] / diff
        utime = cpuUsage[1] / diff
        stime = cpuUsage[2] / diff
        cpuStr = '%d%%(Usr/%d%%+Sys/%d%%)' % (ttime, utime, stime)

        # get CPU Usage for myself #
        cpuUsage = Debugger.selfInstance.getCpuUsage()
        mttime = cpuUsage[0] / diff
        mcpuStr = '%d%%' % mttime

        # add CPU time info #
        self.cpuUsageList.append([ttime, utime, stime])

        # 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

        if self.comm:
            comm = self.comm
        else:
            comm = '??'

        # print top stat #
        ret = SysMgr.addPrint((
            '[Top %s Info] [Time: %.3f] [Interval: %.3f] [NrSamples: %s] '
            '[%s(%s): %s] [%s(%s): %s]%s \n%s\n') % \
                (ctype, SysMgr.uptime, diff,
                convert(self.totalCall), comm, self.pid,
                cpuStr, Debugger.selfInstance.comm,
                Debugger.selfInstance.pid,
                mcpuStr, sampleStr, twoLine), newline=2)
        if not ret:
            _finishPrint()

        # print menu #
        ret = SysMgr.addPrint(
            '{0:^7} | {1:<144}\n{2:<1}\n'.format(
                'Usage', 'Function %s' % addInfo, twoLine), newline=2)
        if not ret:
            _finishPrint()

        totalCnt = long(0)
        isBtPrinted = False
        for sym, value in sorted(self.callTable.items(),
            key=lambda x:x[1]['cnt'], reverse=True):
            if sym[0] == '/':
                sym = '??'

            # check per #
            try:
                per = value['cnt'] / nrTotal * 100 * floatTotalUsage
                if per < 1 and not SysMgr.showAll:
                    break
            except:
                break

            # get stat #
            if self.mode == 'syscall':
                try:
                    total, tmax = self.syscallStat[sym]
                    average = total / value['cnt']
                except:
                    total = average = tmax = long(0)

                addVal = \
                    "<Cnt: %s, Tot: %.6f, Avg: %.6f, Max: %.6f, Err: %s>" % \
                        (convert(value['cnt']),
                            total, average, tmax, convert(value['err']))
            elif self.mode == 'break':
                try:
                    prev, total, tmin, tmax = self.brkcallStat[sym]
                    avg = total / value['cnt']
                except:
                    prev = total = tmin = tmax = avg = long(0)

                addVal = \
                    '[%s] <Cnt: %s, Avg: %.6f, Min: %.6f, Max: %.6f]' % \
                        (value['path'], convert(value['cnt']), avg, tmin, tmax)
            else:
                addVal = '[%s] <Cnt: %s>' % \
                    (value['path'], convert(value['cnt']))

            # check cut condition #
            if SysMgr.checkCutCond():
                break

            ret = SysMgr.addPrint(
                '{0:>7} | {1:<144}\n'.format(
                    '%.1f%%' % per, '%s %s' % (sym, addVal)))
            if not ret:
                break

            totalCnt += 1

            # backtrace #
            if value['backtrace']:
                # backup backtraces #
                if SysMgr.outPath:
                    self.btTable.setdefault(sym, dict())
                    for bt, cnt in value['backtrace'].items():
                        self.btTable[sym].setdefault(bt, 0)
                        self.btTable[sym][bt] += cnt

                for bt, cnt in sorted(value['backtrace'].items(),
                    key=lambda x:x[1], reverse=True):

                    bper = cnt / float(value['cnt']) * 100
                    if bper < 1 and not SysMgr.showAll:
                        break

                    nline = bt.count('\n') + 1
                    if SysMgr.checkCutCond(nline):
                        _finishPrint()

                        # stop target to return original status #
                        if needStop:
                            self.stop(check=True)

                        return

                    ret = SysMgr.addPrint(
                        '{0:>17} | {1:<1} <Cnt: {2:1}>\n'.format(
                            '%.1f%%' % bper, bt, convert(cnt)), newline=nline)
                    if not ret:
                        break

            if SysMgr.funcDepth > 0:
                isBtPrinted = True
                ret = SysMgr.addPrint('%s\n' % oneLine)
                if not ret:
                    break

        if totalCnt == 0:
            SysMgr.addPrint('\tNone\n')

        if not isBtPrinted:
            SysMgr.addPrint('%s\n' % oneLine)

        # print stats #
        _finishPrint()

        # print progress #
        if SysMgr.repeatCount > 0:
            UtilMgr.printProgress(
                SysMgr.progressCnt, SysMgr.repeatCount)

        # stop target to return original status #
        if needStop:
            self.stop(check=True)



    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 list of process mapped files #
        self.pmap = FileAnalyzer.getProcMapInfo(
            self.pid, self.mapFd, onlyExec=onlyExec)
        if not self.pmap or \
            self.prevPmap == self.pmap:
            return False
        else:
            self.prevPmap = self.pmap

        return True



    def loadSymbols(self, onlyFunc=True, onlyExec=True):
        ret = self.updateProcMap(onlyExec=onlyExec)
        if not ret:
            return False

        # update overlayfs info #
        if not self.overlayfsList:
            self.overlayfsList = SysMgr.getOverlayfsInfo(self.pid)

        # check STOP condition #
        if 'STOPTARGET' in SysMgr.environList:
            needStop = True
            self.stop()
        else:
            needStop = False

        # register default libraries #
        for fpath in list(self.pmap.keys()):
            # 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 file-mapped objects #
        printLog = True
        for mfile in list(self.pmap.keys()):
            try:
                eobj = ElfAnalyzer.getObject(
                    mfile, overlay=self.overlayfsList, log=printLog)
                if eobj:
                    eobj.mergeSymTable(onlyFunc=onlyFunc)
                    if printLog:
                        printLog = False
            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(
                'fail to get file list on memory map')

        # continue target #
        if needStop:
            self.cont()

        return True



    @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("fail to get PID to get symbol")
            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 #
            SysMgr.printWarn(
                'fail to get symbol via %s for %s(%s)' % \
                    (hex(vaddr).rstrip('L'), self.comm, self.pid))

            return None

        # get real offset for memory hole #
        totalDiff = 0
        magicstr = SysMgr.magicStr
        if 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:
            # set variable to rescan process map #
            self.needMapScan = True

            # print error message and return #
            SysMgr.printWarn(
                'fail to get symbol via %s for %s(%s)' % \
                    (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 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(
                'fail 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):

        # 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))

            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)
                            rvalue = rvalue.encode()
                        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 = ''

                SysMgr.addPrint(
                    '%13s: 0x%x%s\n' % (reg, val, rvalue))

            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 = ConfigMgr.sysList.index(syscall)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("fail to get syscall number", reason=True)
            sys.exit(0)

        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 addSample(
        self, sym, filename, realtime=False, bt=None, err=None, elapsed=None):
        if not self.runStatus and Debugger.exceptWait:
            return

        if err:
            # increase err count #
            try:
                self.callTable[sym]['err'] += 1
            except:
                pass

            return

        if not realtime:
            self.callList.append([sym, self.current, filename])
            return

        self.totalCall += 1

        if not SysMgr.showAll and bt:
            # 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:
                    break
                elif sym == bt[0][1] and filename == bt[0][2]:
                    bt.pop(0)
                    continue
                break

        # check wait status #
        if not self.runStatus and \
            (self.mode == 'sample' or self.mode == 'pycall'):
            sym = 'WAIT(%s)' % sym

        # add backtrace #
        if bt:
            btStr = self.getBacktraceStr(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': long(0),
                'backtrace': dict(),
                'elapsed': float(0),
                'min': float(0),
                'max': float(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] = dict()
            self.fileTable[filename]['cnt'] = 1

        if not SysMgr.outPath:
            return

        self.callList.append([sym, self.current, filename])



    def checkSymbol(self, sym, newline=False):
        if not SysMgr.customCmd or SysMgr.outPath:
            return

        isPaused = False
        for cmd in SysMgr.customCmd:
            item = cmd.split('|', 1)
            if item[0] and item[0] != '*' and item[0] != sym:
                continue

            if len(item) == 1:
                isPaused = True
                break
            elif len(item) > 1:
                args = self.readArgs()
                self.executeCmd([item[1]], sym, None, args)

        if not isPaused:
            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="%s() is detected! press enter to continue..." % sym)

        # enable timer #
        SysMgr.updateTimer()



    def getBacktraceStr(self, bt, default=20, 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
        pos = default

        # set maximum depth #
        if maximum == 0:
            if len(oneLine) < SysMgr.ttyCols:
                maximum = len(oneLine)
            else:
                maximum = SysMgr.ttyCols

        # set default indentation #
        if default == 0:
            indentStr = ''
        else:
            indentStr = ' ' * default

        for item in bt:
            if item[1] == item[2] == '??':
                sym = hex(item[0]).rstrip('L')
            else:
                sym = item[1]
            fname = item[2]

            # 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 = ''

            # 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 = '%s%s' % (btStr, newStr)

        if btStr == '':
            self.btStr = '??'
        else:
            self.btStr = btStr

        return self.btStr



    def checkInterval(self):
        # continue target thread #
        if self.cont(check=True) < 0:
            sys.exit(0)

        self.traceStatus = False

        # wait for sampling time #
        if self.runStatus:
            time.sleep(self.sampleTime)
        else:
            time.sleep(self.sampleTime*2)

        # check run status #
        self.runStatus = self.isInRun()

        # stop target thread #
        if self.stop() < 0:
            sys.exit(0)

        self.traceStatus = True



    def getBacktrace(self, limit=32, cur=False, force=False):
        try:
            # use backtrace cache #
            if not force and self.btList:
                self.btList

            restored = True

            # unwind stack using DWARF #
            if SysMgr.dwarfEnable:
                # backup registers #
                self.backupRegs(bt=True)
                restored = False

                # 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)
                    if not raddr:
                        break
                    # check max length #
                    elif len(btList) >= limit:
                        break

                    btList.append(raddr)
                    ip = raddr

                # 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:
                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(
                'fail to get backtrace%s' % addr, reason=True)

            if SysMgr.dwarfEnable and not restored:
                # restore registers #
                self.restoreRegs(bt=True)

            return []



    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 addresss #
        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):
        # get file name #
        fname = self.getFileFastFromMap(vaddr)
        if not fname:
            return None

        # get file offset #
        ret = self.getSymbolInfo(vaddr)
        if not ret or ret[2] == '??':
            return
        sym = ret[0]
        foffset = long(ret[2], 16)

        # get ELF object #
        fobj = ElfAnalyzer.getObject(fname)

        # check DWARF info #
        if 'dwarf' not in fobj.attr or not fobj.attr['dwarf']['CFAIndex']:
            SysMgr.printWarn(
                'fail to find DWARF info for %s(%s) in %s' % \
                    (sym, hex(foffset), fname))
            SysMgr.dwarfEnable = False
            return None

        # get function address from CFA index table #
        idx = UtilMgr.bisect_left(\
            fobj.attr['dwarf']['CFAIndex'], foffset) - 1
        faddr = fobj.attr['dwarf']['CFAIndex'][idx]
        # toDo: check function scope from faddr #
        if not faddr in fobj.attr['dwarf']['CFATable']:
            SysMgr.printWarn(
                'fail 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 fobj.attr['dwarf']['CFATable'][faddr]:
            if foffset < line['pc']:
                break
            rule = line
        if not rule or not 'cfa' in rule:
            SysMgr.printWarn(
                'fail 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

        # 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
        # just use FP #
        else:
            raddr = self.fp + ConfigMgr.wordSize

        # 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=32, 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 = []
        for addr in btList:
            res = self.getSymbolInfo(addr)
            if res:
                clist.append([addr, res[0], res[1]])
            else:
                clist.append([addr, '??', '??'])

        return clist



    def addStat(self, sym):
        # apply stat #
        try:
            prev, ttotal, tmin, tmax = self.brkcallStat[sym]

            tdiff = self.current - prev

            ttotal += tdiff

            if tmax < tdiff:
                tmax = tdiff

            if tmin == 0 or \
                tmin > tdiff:
                tmin = tdiff

            self.brkcallStat[sym] = \
                [self.current, ttotal, tmin, tmax]
        except SystemExit:
            sys.exit(0)
        except:
            self.brkcallStat[sym] = [self.current, 0, 0, 0]



    def getBacktraceTree(
        self, diffstr, tinfo, cont=True, cur=False, addBt=[]):

        def _getCommonPos(backtrace, cur):
            # check contiguous tree presentation #
            try:
                commonPos = -1
                if not cont:
                    raise Exception()

                for item in reversed(self.prevStack):
                    if item == backtrace[commonPos]:
                        commonPos -= 1
                        continue
                    break
            except SystemExit:
                sys.exit(0)
            except:
                pass

            return commonPos

        # get 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, cur)
        if commonPos == -1:
            commonPos = 0
            stack = backtrace
        else:
            stack = backtrace[:commonPos]

        self.prevStack = backtrace

        btStr = ''
        for sidx, item in enumerate(reversed(stack)):
            btStr += '\n%s %s%s%s/%s [%s]' % \
                (diffindent, tinfoindent,
                    (sidx-(commonPos)) * '  ',
                    item[1], 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(0)

        # 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)



    def printBpContext(self, sym, addr, fname, checkArg, origPC):
        # skip ld functions #
        if Debugger.exceptLD and fname and \
            os.path.basename(fname).startswith('ld-'):
            SysMgr.printWarn(
                'skip printing %s in %s' % (sym, fname))
            return False

        # read args #
        args = self.readArgs()

        # strip syscall args #
        if sym in ConfigMgr.SYSCALL_PROTOTYPES and \
            len(ConfigMgr.SYSCALL_PROTOTYPES[sym][1]) < len(args):
            args = args[:len(ConfigMgr.SYSCALL_PROTOTYPES[sym][1])]

        # check filter #
        filterCmd = self.bpList[addr]['filter']
        if not self.checkFilterCond(filterCmd, args, sym, fname):
            return

        # build arguments string #
        argstr = '(%s)' % \
            ','.join(list(map(lambda x: hex(x).rstrip('L'), args)))

        # top mode #
        if self.isRealtime:
            if SysMgr.funcDepth > 0:
                backtrace = self.getBacktrace()
            else:
                backtrace = None

            self.addSample(
                sym, fname, realtime=True, bt=backtrace)

            self.addStat(sym)

            return

        # trace mode #
        if self.multi:
            tinfo = '%s(%s) ' % (self.comm, self.pid)
        else:
            tinfo = ''

        # get diff time #
        diffstr = '%3.6f' % self.vdiff

        # check return type #
        if sym.endswith(Debugger.RETSTR):
            isRetBp = True
        else:
            isRetBp = False

        # build backtrace #
        if SysMgr.funcDepth > 0:
            if SysMgr.showAll:
                cont = False
            else:
                cont = True

            # add return address to backtrace #
            if isRetBp:
                addBt = [addr]
            else:
                addBt = []

            # get backtrace tree #
            btstr, depth = \
                self.getBacktraceTree(diffstr, tinfo, cont, addBt=addBt)

            indent = '  ' * depth
        else:
            btstr = indent = ''

        # print return value #
        retstr = ''
        hasRetFilter = False
        elapsed = ''
        callString = ''
        etime = None
        cmds = None
        skip = False

        # handle breakpoint for return #
        if isRetBp:
            try:
                etime, elapsed, hasRetFilter, skip = \
                    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 prevSymInfo:
                        prevSym = prevSymInfo[0]
                        prevFname = prevSymInfo[1]
                        prevAddr = prevSymInfo[3]
                        addStr = ' -> %s/%s [%s]' % \
                            (prevSym, hex(prevAddr).rstrip('L'), prevFname)
                    else:
                        addStr = ''

                    # convert elapsed color #
                    if etime > self.retTime:
                        elapsed = UtilMgr.convColor(elapsed, 'RED')
                    else:
                        elapsed = UtilMgr.convColor(elapsed, 'CYAN')

                    # build context string #
                    callString = '\n%s %s%s%s%s%s%s' % \
                        (diffstr, tinfo, indent, sym, retstr, elapsed, addStr)
            except SystemExit:
                sys.exit(0)
            except:
                elapsed = ''
                isRetBp = False

            # check command #
            origSym = sym[:-len(Debugger.RETSTR)]
            if origSym in self.retCmdList:
                cmds = self.retCmdList[origSym]
        else:
            # build current symbol string #
            callString = '\n%s %s%s%s%s/%s%s [%s]' % \
                (diffstr, tinfo, indent, sym, elapsed,
                    hex(addr).rstrip('L'), argstr, fname)

        if callString:
            # emphasize string #
            if hasRetFilter and not skip:
                callString = UtilMgr.convColor(callString, 'CYAN')

            # add backtrace #
            if btstr:
                callString = '%s%s' % (btstr, callString)

            # add entry log to return filter #
            if sym in self.retFilterList:
                self.retFilterList[sym][1] = callString

            # file output #
            if SysMgr.outPath:
                self.addSample(
                    sym, fname, realtime=True, elapsed=etime)

                # print history #
                if SysMgr.showAll:
                    self.callPrint.append(callString.rstrip())

                # print to stdout #
                if SysMgr.printStreamEnable:
                    sys.stdout.write(callString)
            # console output #
            else:
                SysMgr.printPipe(callString, newline=False, flush=True)

            # handle repeat command #
            if isRetBp and origPC != self.pc:
                self.handleBp(True, checkArg)
                return

            # check command #
            cmd = self.bpList[addr]['cmd']
            if cmd:
                self.bpList[addr]['cmd'] = \
                    self.executeCmd(
                        cmd, sym=sym, fname=fname, args=args)

        # execute commands #
        if cmds:
            self.executeCmd(cmds, sym, fname, args)

        return isRetBp



    def handleBp(self, printStat=False, checkArg=None):
        # read registers for target #
        if not self.updateRegs():
            sys.exit(0)

        # 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(
                    "fail 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(0)
            else:
                offset = long(ret[2], 16)

            # load orignal data from storage #
            origWord = self.loadInst(fname, offset)

            # register this lost breakpoint #
            ret = self.injectBp(
                addr, sym, fname=fname, origWord=origWord)

            # check memory map again #
            if addr not in self.bpList:
                SysMgr.printErr((
                    "fail 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(0)

        # 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'))):
            if self.loadSymbols():
                self.updateBpList(verb=False)
            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)
            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()

        # 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 ret is None:
            self.unlock(nrLock)
            return

        # check reinstall option #
        reins = ret[2]
        if isRetBp or not reins:
            self.unlock(nrLock)
            return

        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)

            # check process #
            ret = self.waitpid()
            self.checkStat(ret, reason="injection is failed")

        # register this breakpoint again #
        ret = self.injectBp(
            addr, sym, fname=fname, reins=reins)
        if not ret:
            self.unlock(nrLock)
            sys.exit(0)

        # unlock between processes #
        self.unlock(nrLock)



    def handleTrapEvent(self, stat):
        previous = self.status
        self.status = self.mode

        # interprete user function call #
        if self.mode == 'inst' or self.mode =='sample':
            self.handleUsercall()
        elif self.mode == 'break':
            # block signal #
            SysMgr.blockSignal(act='block')

            while 1:
                try:
                    self.handleBp(printStat=SysMgr.printEnable)
                    break
                except SystemExit:
                    sys.exit(0)
                except IOError:
                    SysMgr.printWarn(
                        "fail to handle breakpoint for %s(%s)" % \
                            (self.comm, self.pid), True, reason=True)
                    sys.exit(0)
                except:
                    SysMgr.printWarn(
                        "fail to handle breakpoint for %s(%s)" % \
                            (self.comm, self.pid), True, reason=True)

            if self.cont(check=True) < 0:
                sys.exit(0)

            # unblock signal #
            SysMgr.blockSignal(act='unblock')
        elif self.mode == 'pycall':
            self.handlePycall()

        self.status = previous



    def handleSignal(self, sig):
        if not SysMgr.printEnable:
            return

        # check signal filter #
        if SysMgr.customCmd:
            found = False
            for signame in SysMgr.customCmd:
                if signame.upper() == ConfigMgr.SIG_LIST[sig]:
                    found = True
                    break
            if not found:
                return

        # get diff time #
        diff = self.vdiff

        if self.multi:
            tinfo = '%s(%s) ' % (self.comm, self.pid)
        else:
            tinfo = ''

        try:
            signame = ConfigMgr.SIG_LIST[sig]
        except:
            signame = 'UNKNOWN(%s)' % sig

        callString = '\n%3.6f %s[%s]' % \
            (diff, tinfo, signame)

        SysMgr.printPipe(callString)

        # print backtrace #
        if not self.isRealtime and SysMgr.funcDepth > 0:
            # read registers for target #
            if not self.updateRegs():
                sys.exit(0)

            self.printContext(regs=False, sig=False)



    def initPyEnv(self):
        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(
                    "fail to find python binary for %s" % procInfo)
                sys.exit(0)

        # 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 symbol for interpreter #
        pySym = ['_PyThreadState_Current', '_PyRuntime']
        symbolInfo = SysMgr.getProcAddrBySymbol(
            self.pid, pySym, fileFilter=[pyPath])
        if not symbolInfo:
            SysMgr.printErr(
                "fail to find '%s' symbol for %s" % (pySym, procInfo))
            sys.exit(0)
        elif len(symbolInfo) > 1:
            SysMgr.printErr(
                "found multiple symbols [ %s ] for %s" % \
                 (', '.join(list(symbolInfo.keys())), procInfo))
            sys.exit(0)

        # get address for interpreter #
        pySymbol = list(symbolInfo.values())[0]
        self.pyAddr = long(pySymbol[2], 16)

        # version >= 3.7 #
        if pySymbol[3] == '_PyRuntime':
            # get offset for PyInterpreterState head #
            if ConfigMgr.wordSize == 4:
                SysMgr.printErr(
                    'not supported yet for PyThreadState on 32-bit')
                sys.exit(0)
            else:
                self.pyAddr += 32

        # 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))
            sys.exit(0)



    def readPyState32(self, addr):
        SysMgr.printErr("not implemented yet")
        sys.exit(0)



    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]
                PyThreadState = self.readMem(PyThreadState, 216)
                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)
                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)
                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(0)



    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, 7):
            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(0)



    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 handlePycall(self):
        if not self.pyAddr:
            self.initPyEnv()

        # read address for PyThreadState #
        pyThreadStateP = self.readMem(self.pyAddr)
        pyThreadStateP = struct.unpack('Q', pyThreadStateP)[0]

        # read native call info #
        if sys.version_info >= (3, 7):
            self.updateRegs()
            curSym = self.getSymbolInfo(self.pc)[0]
            if not curSym.startswith('_Py') and not curSym.startswith('Py'):
                self.handleUsercall(update=False)
                return
        elif 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:
            return
        else:
            framep = frameList[self.pthreadid]

        # read frames #
        bt = []
        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]

            if not lastName:
                lastName = name
                lastFile = filename
            else:
                bt.append([f_lineno, name, filename])

            # check last frame #
            if SysMgr.funcDepth == 0 or f_back == 0:
                break

            framep = f_back

        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(0)
            else:
                return

        # check previous function boundary #
        if not self.prevCallInfo:
            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')

            if self.isRealtime:
                self.addSample(sym, fname, realtime=True, bt=backtrace)
            elif SysMgr.outPath:
                self.addSample(sym, fname, 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

        # 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 = long(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 == 'PLT':
                direction = '(--)'
                self.addCall(sym)
            elif self.sp > self.prevSp:
                direction = '(<-)'
            else:
                direction = '(->)'
                self.addCall(sym)

            symstr = '%s%s' % (' ' * 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

            if SysMgr.outPath:
                self.addSample(sym, fname)

                if SysMgr.showAll:
                    self.callPrint.append(callString)
            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):
        proto = ConfigMgr.SYSCALL_PROTOTYPES

        # get argument values from register #
        regstr = self.readArgs()

        # get data types #
        self.rettype, formats = proto[self.syscall]

        # get values #
        self.values = \
            [value for value, format in zip(regstr, formats)]

        seq = long(0)
        argset = {}
        for value, format in zip(regstr, formats):
            # get type and name of a argument #
            argtype, argname = format
            argset[argname] = value

            # convert argument value #
            value = self.convSyscallParam(
                argtype, argname, value, seq, ref, argset, SysMgr.showAll)
            if value is not None:
                self.addArg(argtype, argname, value)

            seq += 1



    def convSyscallArgs(self):
        args = []

        if self.isRealtime and not SysMgr.showAll:
            ref = False
        else:
            ref = True

        # converting arguments #
        self.updateSyscallArgs(ref)

        # 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[:-1]
                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 isDeferrableCall(self, name):
        if name == 'read' or \
            name == 'recvmsg' or \
            name == 'recvmmsg' or \
            name == 'recv' or \
            name == 'readv' or \
            name == 'readlink' or \
            name == 'recvfrom' or \
            name == 'clock_gettime' or \
            name == 'getgroups' or \
            name == 'getgroups16' or \
            name == 'gethostname' or \
            name == 'getitimer' or \
            name == 'getpeername' or \
            name == 'gettimeofday' or \
            name == 'getsockname' or \
            name == 'clone' or \
            name == 'process_vm_readv':
            return True
        else:
            return False



    def handleSyscallOutput(self, args, deferrable=False):
        # get diff time #
        diff = self.vdiff

        # get backtrace #
        if SysMgr.funcDepth > 0:
            backtrace = self.getBacktrace(limit=SysMgr.funcDepth, cur=True)
            bts = self.getBacktraceStr(backtrace)
            if bts:
                bts = '\n%s%s ' % (' ' * 20, bts)
        else:
            backtrace = None
            bts = ''

        # print context in JSON format #
        if SysMgr.jsonEnable:
            jsonData = {
                "type": "enter",
                "time": self.current,
                "timediff": diff,
                "name": self.syscall,
                "tid": self.pid,
                "comm": self.comm,
                "backtrace": bts,
                "args": dict(),
            }

            # marshaling args #
            for idx, arg in enumerate(self.args):
                if len(args) > 0:
                    jsonData['args'][arg[1]] = args[idx]
                else:
                    jsonData['args'][arg[1]] = arg[2]

            try:
                SysMgr.printPipe(
                    str(UtilMgr.convDict2Str(jsonData, pretty=False)))
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "fail to convert %s to JSON for marshalling" % \
                        [jsonData], True)
            return

        if not self.isRealtime or SysMgr.showAll:
            # convert args to string ##
            if len(args) > 0:
                argText = ', '.join(\
                    hex(arg).rstrip('L') if type(arg) is long else str(arg) \
                        for arg in args)
            else:
                argText = ', '.join(str(arg[2]) for arg in self.args)

            # build call string #
            if deferrable:
                callString = '%s)%s' % (argText, bts)
            else:
                callString = '%3.6f %s(%s) %s(%s)%s' % \
                    (diff, self.comm, self.pid, self.syscall, argText, bts)

        # print call info #
        if self.isRealtime:
            self.addSample(
                self.syscall, '??', realtime=True, bt=backtrace)
        elif SysMgr.outPath:
            self.addSample(self.syscall, '??', bt=backtrace)
        else:
            ttyColsOrig = SysMgr.ttyCols

            if SysMgr.showAll or SysMgr.funcDepth > 0:
                SysMgr.ttyCols = long(0)
            else:
                callString = '%s ' % callString[:self.pbufsize]

            if deferrable:
                prefix = ''
            else:
                prefix = '\n'

            SysMgr.printPipe(
                '%s%s' % (prefix, callString), newline=False, flush=True)

            SysMgr.ttyCols = ttyColsOrig

        # print call history #
        if SysMgr.showAll and SysMgr.outPath:
            if deferrable:
                callString = '%s%s' % (self.bufferedStr, callString)
            self.callPrint.append(callString)

        # check symbol #
        if SysMgr.customCmd:
            self.checkSymbol(self.syscall, newline=True)



    def handleDefSyscall(self):
        self.status = 'exit'

        if self.getRegs(temp=True) != 0:
            sys.exit(0)

        # 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:
            self.clearArgs()
            args = self.convSyscallArgs()

        self.handleSyscallOutput(args, deferrable=True)



    def handleSyscall(self):
        # skip useless return processing #
        if self.status == 'skip':
            self.status = 'enter'
            return

        # check deferrable #
        if self.status == 'deferrable':
            self.handleDefSyscall()

        # ignore return #
        if SysMgr.optStrace and self.status == 'exit':
            self.status = 'enter'
            self.clearArgs()
            return

        # read registers #
        if not self.updateRegs():
            sys.exit(0)

        # 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

        # get syscall name #
        try:
            proto = ConfigMgr.SYSCALL_PROTOTYPES
            self.syscall = name = ConfigMgr.sysList[nrSyscall][4:]
        except SystemExit:
            sys.exit(0)
        except:
            return

        # get diff time #
        diff = self.vdiff

        # enter #
        if self.status == 'enter':
            # set next status #
            self.status = 'exit'

            # check wait condition #
            if self.wait:
                return

            # check prototype #
            if name not in proto:
                SysMgr.printWarn(
                    "fail to get args info of %s" % name, True)
                return

            args = []

            self.syscallTime[name] = self.vdiff

            # convert args except for top mode #
            if not self.isRealtime:
                if self.isDeferrableCall(name):
                    self.status = 'deferrable'

                    if SysMgr.jsonEnable:
                        return

                    # build call string #
                    callString = '%3.6f %s(%s) %s(' % \
                        (diff, self.comm, self.pid, name)

                    if SysMgr.outPath:
                        self.bufferedStr = callString
                    else:
                        SysMgr.printPipe(
                            '\n%s' % callString, newline=False, flush=True)

                    return

                args = self.convSyscallArgs()

            self.handleSyscallOutput(args)

            # check syscall condition #
            if SysMgr.syscallList:
                self.clearArgs()

            return

        # exit #
        elif self.status == 'exit':
            # set next status #
            self.status = 'enter'

            # get diff #
            try:
                diff = self.vdiff - self.syscallTime[name]
            except SystemExit:
                sys.exit(0)
            except:
                diff = long(0)

            # get diff time #
            if self.isRealtime:
                # apply diff and update maximum diff #
                try:
                    ttotal, tmax = self.syscallStat[name]
                    ttotal += diff

                    if tmax < diff:
                        tmax = diff

                    self.syscallStat[name] = [ttotal, tmax]
                except SystemExit:
                    sys.exit(0)
                except:
                    self.syscallStat[name] = [diff, diff]

            # set 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:
                try:
                    err = '%s (%s)' % \
                        (ConfigMgr.ERR_TYPE[abs(retval+1)],
                            os.strerror(abs(retval)))

                    self.addSample(name, '??', err=retval)
                except SystemExit:
                    sys.exit(0)
                except:
                    err = ''
            else:
                err = ''

            # convert type #
            try:
                rtype = proto[name][0]
                if '*' in rtype:
                    retval = '0x%s' % long(str(retval), 16)
            except SystemExit:
                sys.exit(0)
            except:
                pass

            # print context in JSON format #
            if SysMgr.jsonEnable:
                jsonData = {
                    "type": "exit",
                    "time": self.current,
                    "timediff": diff,
                    "name": name,
                    "tid": self.pid,
                    "comm": self.comm,
                    "backtrace": self.prevBtStr,
                    "ret": str(retval),
                    "err": err,
                }

                SysMgr.printPipe(
                    str(UtilMgr.convDict2Str(jsonData, pretty=False)))

                self.clearArgs()

                return

            # convert return format #
            if type(retval) is long:
                retval = hex(retval).rstrip('L')

            # convert error color #
            if err:
                err = ' ' + UtilMgr.convColor(err, 'RED')

            # convert elapsed color #
            diffStr = ' [%.6f]' % diff
            if diff > self.retTime:
                diffStr = UtilMgr.convColor(diffStr, 'RED')
            else:
                diffStr = UtilMgr.convColor(diffStr, 'CYAN')

            # build call string #
            callString = '= %s%s%s' % (retval, err, diffStr)

            if SysMgr.outPath:
                if SysMgr.showAll and len(self.callPrint) > 0:
                    self.callPrint[-1] = '%s%s' % \
                        (self.callPrint[-1], callString)
            elif self.isRealtime:
                pass
            else:
                SysMgr.printPipe(callString, newline=False, flush=True)

            self.clearArgs()

        else:
            SysMgr.printErr(
                'fail to recognize syscall status')



    def getKernelStack(self, retstr=False):
        try:
            self.kernelFd.seek(0)
            stat = self.kernelFd.readlines()
        except SystemExit:
            sys.exit(0)
        except:
            try:
                kernelPath = "%s/%s/task/%s/stack" % \
                    (SysMgr.procPath, self.pid, self.pid)
                self.kernelFd = open(kernelPath, 'r')
                stat = self.kernelFd.readlines()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenWarn(kernelPath)
                return None

        # return full data #
        if retstr:
            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:
                SysMgr.printOpenWarn(statPath)
                return None

        # return full data #
        if retstr:
            return stat

        try:
            if status:
                return stat.split(') ', 1)[1][0]
            else:
                return stat.split(')')[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 == 'T' or stat == 't':
            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 getCpuUsage(self):
        stat = self.getStatList(retstr=True)
        if not stat:
            SysMgr.printWarn(
                "fail to get CPU usage for %s(%s)" % \
                    (self.comm, self.pid))
            return [0, 0, 0]

        # check stat change #
        if self.prevStat == stat:
            return [0, 0, 0]

        self.prevStat = stat

        # convert string to list #
        statList = stat.split(')')[1].split()
        if not statList:
            return [0, 0, 0]

        # get total CPU time #
        utime = long(statList[self.utimeIdx-2])
        stime = long(statList[self.stimeIdx-2])
        ttime = utime + stime

        # get CPU diff #
        prevUsage = self.prevCpuStat
        if prevUsage == None:
            ret = [0, 0, 0]
        else:
            ret = [ttime - prevUsage[0],
                utime - prevUsage[1],
                stime - prevUsage[2]]

        # save CPU usage #
        self.prevCpuStat = [ttime, utime, stime]

        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 = {}

        for mfile in list(self.pmap.keys()):
            if binary and not mfile in binary:
                continue

            # get ELF object #
            fcache = ElfAnalyzer.getObject(mfile)
            if not fcache:
                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

        # return address #
        if not addrList:
            if verb:
                SysMgr.printErr(
                    "fail 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()

        # stop tracees #
        self.stop()
        self.stop(pid=tid)

        # check lock #
        if self.mode == 'break' 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 #
        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, cont=True)

            # attach to the parent task again #
            if self.attach(verb=True) < 0:
                sys.exit(0)

            # increase the number of childs #
            self.childNum += 1

            # wait for tracer of child task #
            try:
                os.close(wr)
                os.fdopen(rd, 'r').read()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "fail 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

                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()
            self.forked = True
            signal.alarm(SysMgr.intervalEnable)

            # increase the number of childs #
            self.targetNum = self.childNum + 1
            self.childNum += 1

            # change status to leave clone context #
            if self.mode == 'syscall':
                self.status = 'enter'
            else:
                self.status = 'skip'

            # notify to tracer of parent task #
            try:
                os.close(rd)
                os.fdopen(wr, 'w').write('0')
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "fail to notify initialization to %s(%s)" % \
                        (self.comm, origPid), reason=True)
        else:
            return

        # set trace event #
        self.ptraceEvent(self.traceEventList)

        # set attributes for multiprocess #
        self.multi = True
        if not SysMgr.outPath:
            SysMgr.setStream()

        # continue tasks #
        self.cont()

        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 #
        try:
            SysMgr.printFd.close()
        except SystemExit:
            sys.exit(0)
        except:
            pass
        finally:
            SysMgr.printFd = None

        # 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

        # load symbols and inject breakpoints #
        if (dobj.mode != 'syscall' and dobj.mode != 'signal') or \
            SysMgr.funcDepth > 0:
            if dobj.loadSymbols():
                dobj.updateBpList()

        # continue target #
        if dobj.mode != 'syscall' and dobj.isStopped():
            if dobj.cont(check=True):
                sys.exit(0)

        # start new tracing #
        dobj.trace(mode=self.mode, multi=self.multi)



    def initValues(self):
        # default info #
        self.traceEventList = [\
            'PTRACE_O_TRACEEXEC',
            'PTRACE_O_TRACESYSGOOD',
            'PTRACE_O_TRACECLONE',
            'PTRACE_O_TRACEFORK',
            'PTRACE_O_TRACEVFORK',
        ]

        # 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.sampleStatus = True
        self.statFd = None
        self.kernelFd = None
        self.prevStat = None
        self.prevCpuStat = None
        self.pyLibPath = None
        self.pyInit = False
        self.prevSym = None
        self.arch = SysMgr.getArch()
        self.sysreg = ConfigMgr.SYSREG_LIST[self.arch]
        self.retreg = ConfigMgr.RET_LIST[self.arch]
        self.commIdx = ConfigMgr.STAT_ATTR.index("COMM")
        self.utimeIdx = ConfigMgr.STAT_ATTR.index("UTIME")
        self.stimeIdx = ConfigMgr.STAT_ATTR.index("STIME")

        # 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 = list()
        self.prevStack = list()
        self.childList = list()
        self.callList = list()
        self.callPrint = list()
        self.cpuUsageList = list()
        self.syscallTime = dict()
        self.syscallStat = dict()
        self.brkcallStat = dict()
        self.retList = dict()
        self.accList = dict()
        self.setRetList = dict()
        self.regList = dict()
        self.repeatCntList = dict()
        self.symbolCacheList = dict()
        self.prevReturn = -1
        self.startAddr = None

        # timestamp variables #
        self.updateCurrent()

        # python variables #
        self.pyAddr = None
        self.pyFrameCache = {}

        # python functinos #
        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

        # index variables #
        self.sigExecFlag = signal.SIGTRAP | \
            ConfigMgr.PTRACE_EVENT_TYPE.index('PTRACE_EVENT_EXEC') << 8
        self.sigCloneFlag = signal.SIGTRAP | \
            ConfigMgr.PTRACE_EVENT_TYPE.index('PTRACE_EVENT_CLONE') << 8
        self.sigForkFlag = signal.SIGTRAP | \
            ConfigMgr.PTRACE_EVENT_TYPE.index('PTRACE_EVENT_FORK') << 8
        self.sigVforkFlag = signal.SIGTRAP | \
            ConfigMgr.PTRACE_EVENT_TYPE.index('PTRACE_EVENT_VFORK') << 8

        # make object for myself #
        if not Debugger.selfInstance or \
            Debugger.selfInstance.pid != SysMgr.pid:
            Debugger.selfInstance = Debugger(SysMgr.pid, attach=False)
            Debugger.selfInstance.initValues()



    def handleRetBpFilter(self, sym):
        # get original symbol #
        try:
            origSym = sym[:-len(Debugger.RETSTR)]
        except:
            origSym = sym

        if origSym not in self.entryTime:
            SysMgr.printWarn(
                "no entry time of %s(%s) for %s(%s)" % \
                    (origSym, sym, self.comm, self.pid))
            raise Exception('no entry time')

        # calculate elapsed time #
        skip = False
        hasRetFilter = False
        entry = self.entryTime[origSym]
        etime = self.vdiff - entry
        elapsed = '/%.6f' % etime

        # remove entry timestamp from list #
        self.entryTime.pop(origSym, None)

        # check return filter #
        if not origSym in self.retFilterList:
            return etime, elapsed, hasRetFilter, skip

        # check condition #
        try:
            filters = self.retFilterList[origSym][0]
            op = filters[1].upper()
            cond = float(filters[2])

            # compare values #
            if op == 'EQ':
                if etime != cond:
                    skip = True
            elif op == 'DF':
                if etime == cond:
                    skip = True
            elif op == 'BT':
                if etime <= cond:
                    skip = True
            elif op == 'LT':
                if etime >= cond:
                    skip = True
            else:
                SysMgr.printErr((
                    "fail to recognize '%s' in return filter "
                    "for %s for %s(%s)") % \
                        (op, origSym, self.comm, self.pid))
                sys.exit(0)

            hasRetFilter = True
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "fail to check return filter for %s for %s(%s)" % \
                    (origSym, self.comm, self.pid))

        # remove return filter #
        self.retFilterList.pop(origSym, None)

        return etime, elapsed, hasRetFilter, skip



    def handleRetBp(self, sym, fname, addr):
        try:
            # change return value #
            if sym in self.setRetList:
                newval = 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

            if origSym in self.regList:
                newObj = self.regList.pop(origSym, None)
                self.setRegs(newObj=newObj)
                self.updateRegs()

            # save return vaue #
            self.retList[origSym] = long(retval)
            self.prevReturn = str(retval)

            # remove breakpoint #
            ret = self.removeBp(addr, lock=True)

            return "=%s(%s)" % (hex(retval).rstrip('L'), retval)
        except SystemExit:
            sys.exit(0)
        except:
            errMsg = "fail 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)
            return True

        # add the new breakpoint for return #
        newSym = '%s%s' % (sym, Debugger.RETSTR)
        ret = self.injectBp(
            pos, newSym, fname, reins=True, cmd=None)
        if not ret:
            # ignore error message #
            pass

        # 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 #
        self.entryTime[sym] = 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.isCloned(ostat) or self.isForked(ostat):
                pid = self.handoverNewTarget()
                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:
            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):
        # timestamp variables #
        self.updateCurrent()

        # initialize dynamic time for tracing #
        self.dstart = time.time()

        # set update flag for time #
        if SysMgr.isTraceMode():
            updateTime = True
        else:
            updateTime = 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 == 'ready' or self.status == 'wait':
                pass
            else:
                # wait for sample calls #
                if self.mode == 'sample' or self.mode == 'pycall':
                    self.checkInterval()
                elif self.mode == 'break' or self.mode == 'signal':
                    pass
                # skip instructions for performance #
                elif self.mode == 'inst' and self.skipInst > 0:
                    for i in range(0, self.skipInst):
                        self.ptrace(self.cmd)
                # setup trap #
                else:
                    self.ptrace(self.cmd)

            try:
                # add tracing overhead to start time #
                if updateTime:
                    overhead = time.time() - self.current + self.timeDelay
                    self.dstart += overhead

                # wait for target to be stopped #
                rid, ostat = self.waitpid()

                # update time #
                self.updateCurrent()
                if updateTime:
                    self.vdiff = self.current - self.dstart

                # handle clone event #
                if not SysMgr.optStrace and SysMgr.cloneEnable:
                    if self.isCloned(ostat):
                        self.handoverNewTarget()
                        continue
                    elif self.isForked(ostat):
                        self.handoverNewTarget(fork=True)
                        continue

                # handle exec event #
                if self.isExeced(ostat):
                    if self.execEnable:
                        self.restartTrace()
                    else:
                        SysMgr.printErr(
                            'terminated tracing for %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:
                    # after execve() #
                    if 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.mode == 'break':
                            # remove all breakpoins for new child process #
                            if self.forked:
                                self.removeAllBp()

                            # load symbols again #
                            if self.loadSymbols():
                                self.updateBpList()

                            # continue target #
                            if self.cont(check=True) < 0:
                                sys.exit(0)

                        # change status #
                        self.status = 'enter'

                    # usercall / breakcall #
                    elif self.mode == 'break' or self.mode == 'inst':
                        self.handleTrapEvent(ostat)

                    # wrong status for syscall #
                    elif self.mode == 'syscall' and self.status == 'enter':
                        self.status = 'skip'
                        self.ptraceEvent(self.traceEventList)
                        self.ptrace(self.cmd)
                        continue

                # breakpoint for ARM #
                elif stat == signal.SIGILL and self.mode == 'break':
                    self.handleTrapEvent(ostat)

                # syscall #
                elif stat == syscallTrapFlag:
                    # interprete syscall context #
                    if self.mode == 'syscall':
                        self.handleSyscall()

                # STOP signal #
                elif stat == signal.SIGSTOP:
                    if self.mode == 'sample' or self.mode == 'pycall':
                        self.handleTrapEvent(ostat)
                        continue

                    self.status = 'stop'
                    SysMgr.printWarn(
                        'blocked %s(%s) because of %s' % \
                        (self.comm, self.pid, ConfigMgr.SIG_LIST[stat]))

                    # continue #
                    if self.mode == 'break' or self.mode == 'signal':
                        if self.cont(check=True) < 0:
                            sys.exit(0)
                    # set up trap again #
                    elif self.mode == 'syscall':
                        self.ptraceEvent(self.traceEventList)
                        self.ptrace(self.cmd)

                # KILL / SEGV / ABRT signal #
                elif SysMgr.isTermSignal(stat):
                    # print status #
                    SysMgr.printErr(
                        'detected %s for %s(%s)' % \
                            (ConfigMgr.SIG_LIST[stat], self.comm, self.pid))

                    # print context info #
                    if SysMgr.showAll:
                        self.printContext(newline=True)

                    # deliver signal #
                    if self.cont(check=True, sig=stat) < 0:
                        sys.exit(0)

                    # set fault flag to shared memory #
                    self.setFaultFlag()

                # exit #
                elif stat == -1:
                    if self.status == 'exit':
                        SysMgr.printPipe(' ')

                    # print status #
                    SysMgr.printErr(
                        'terminated %s(%s)' % (self.comm, self.pid))

                    if SysMgr.isTopMode() and self.totalCall:
                        SysMgr.waitEvent()

                    sys.exit(0)

                # signal #
                elif self.mode == 'signal':
                    self.handleSignal(stat)

                    self.cont(sig=stat)
                    if self.cont(check=True, sig=stat) < 0:
                        sys.exit(0)

                # other #
                else:
                    SysMgr.printWarn(
                        'detected %s(%s) with %s' % \
                        (self.comm, self.pid, ConfigMgr.SIG_LIST[stat]))

                    if self.mode == 'sample':
                        self.handleTrapEvent(ostat)

                    # continue target from signal stop #
                    if self.mode != 'syscall':
                        if self.cont(check=True, sig=stat) < 0:
                            sys.exit(0)
            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.mode == 'break':
                    if self.cont(check=True) < 0:
                        sys.exit(0)



    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
        self.pbufsize = SysMgr.ttyCols >> 1

        # 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:
            # get first CPU usage #
            self.getCpuUsage()
            Debugger.selfInstance.getCpuUsage()

            # set alarm handler #
            signal.signal(signal.SIGALRM, Debugger.onAlarm)

            if self.mode == 'sample' or self.mode == 'pycall':
                # set sampling rate to 100 us #
                sampleTime = SysMgr.getOption('T')
                if sampleTime:
                    try:
                        self.sampleTime = \
                            long(sampleTime) / float(1000000)
                    except:
                        SysMgr.printErr(
                            "fail to set sampling time", True)
                        sys.exit(0)
                else:
                    self.sampleTime = 0.001

                if not self.multi:
                    SysMgr.printInfo(
                        'do sampling every %g second' % self.sampleTime)

            # set default interval #
            if not SysMgr.findOption('R') and \
                SysMgr.intervalEnable == 0:
                SysMgr.intervalEnable = 1
        else:
            # set timer handler #
            if SysMgr.intervalEnable:
                signal.signal(signal.SIGALRM, SysMgr.exitHandler)

            # 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))

        # 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(
                        'fail to trace %s(%s) because %s' % \
                            (self.comm, self.pid, ereason))
                sys.exit(0)

            # initialize environment for python #
            if mode == 'pycall':
                self.initPyEnv()
            # load user symbols #
            elif (mode != 'syscall' and mode != 'signal') or \
                SysMgr.funcDepth > 0:
                try:
                    self.loadSymbols()
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr(
                        "fail to load symbols", True)
                    sys.exit(0)

            # 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(0)

            ret = self.ptraceEvent(self.traceEventList)

            # handle current user symbol #
            if (self.mode == 'inst' or self.mode == '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(0)
        elif self.mode == 'sample' or self.mode == 'pycall':
            self.cmd = None
        elif self.mode == 'break':
            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 == 'signal':
            if self.isStopped():
                if self.cont(check=True):
                    sys.exit(0)
        elif self.mode == 'remote':
            for i in range(0, SysMgr.intervalEnable+1):
                self.runExecMode()
            SysMgr.printPipe()
            sys.exit(0)
        else:
            SysMgr.printErr(
                "fail to recognize trace mode '%s'" % self.mode)
            sys.exit(0)

        # register summary callback #
        SysMgr.addExitFunc(Debugger.printSummary, [self])

        # wait for task creation #
        if SysMgr.waitEnable and \
            self.mode != 'break':
            SysMgr.waitEnable = False
            self.waitForClone()

        # set timer #
        if SysMgr.masterPid == 0 or SysMgr.printEnable:
            signal.alarm(SysMgr.intervalEnable)

        # run loop #
        self.runEventLoop()



    @staticmethod
    def destroyDebugger(instance):
        Debugger.dbgInstance = None

        # check condition for breakpoint mode #
        if not instance.pid or \
            SysMgr.inputParam or \
            not instance.bpList or \
            not instance.isAlive():
            instance.__del__()
            return

        # stop target #
        if not instance.isStopped():
            instance.stop()
            instance.waitpid()

        # notify termination to master process #
        tgid = long(SysMgr.getTgid(instance.pid))
        if tgid == instance.pid:
            os.kill(SysMgr.masterPid, signal.SIGINT)

        # make my priority lower #
        SysMgr.setPriority(SysMgr.pid, 'C', 19, verb=False)

        # update register set #
        cnt = 5
        try:
            while 1:
                ret = instance.updateRegs()
                if ret:
                    break
                elif not instance.isAlive():
                    return

                # check count #
                cnt -= 1
                if cnt <= 0:
                    instance.__del__(stop=True)
                    return

                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:
            if addr % ConfigMgr.wordSize == 0:
                origWord = instance.accessMem(instance.peekIdx, addr)
                origWord = UtilMgr.convWord2Str(origWord)
            else:
                origWord = instance.readMem(addr)

            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
            instance.removeAllBp(tgid)
            SysMgr.printEnable = origPrintFlag

        # remove new breakpoins after fork for childs #
        for addr in list(instance.bpNewList.keys()):
            instance.removeBp(addr)

        instance.__del__(stop=True)

        # 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):
        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 History] [%s] [Time: %f] [Line: %s]\n%s\n%s\n%s' %
                (procInfo, elapsed, nrLine, twoLine, callStr, oneLine))



    @staticmethod
    def printSummary(instance):
        def _printSystemStat():
            SysMgr()
            SysMgr.sysInstance.saveSysStat()
            SysMgr.printInfoBuffer()

        # check realtime mode #
        if not SysMgr.outPath:
            return

        # summarize samples after last tick #
        if SysMgr.repeatCount == 0 or \
            SysMgr.progressCnt < SysMgr.repeatCount:
            instance.printIntervalSummary()
        else:
            instance.last = time.time()

        callTable = dict()
        fileTable = dict()
        elapsedTable = list()

        # define stop flag #
        needStop = False

        # check mode and define type variables #
        if instance.mode == 'syscall':
            ctype = 'Syscall'
            addInfo = '<Elapsed>'
        elif instance.mode == 'break':
            ctype = 'Breakcall'
            addInfo = '[PATH] <Elapsed>'
        else:
            if instance.mode == 'pycall':
                ctype = 'Pycall'
            else:
                ctype = 'Usercall'
            addInfo = '[Path]'

            # continue target to prevent too long freezing #
            if instance.traceStatus and instance.isAlive():
                if instance.cont(check=True) == 0:
                    needStop = True

        if instance.isRealtime:
            mtype = 'Top'
            suffix = '\n'
        else:
            mtype = 'Trace'
            suffix = ''

        # print System Info #
        _printSystemStat()

        SysMgr.printInfo(
            "start analyzing calls...")

        nrTotal = float(len(instance.callList))

        # iterate the list of call samples #
        for idx, item in enumerate(instance.callList):
            try:
                symbol, timestamp, filename = item

                # skip breakpoints for return #
                if instance.mode == 'break' 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] = dict()
                    callTable[symbol]['cnt'] = 1
                    callTable[symbol]['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] = dict()
                    fileTable[filename]['cnt'] = 1
            except SystemExit:
                UtilMgr.deleteProgress()

                # stop target to return original status #
                if needStop:
                    instance.stop(check=True)

                return
            except:
                pass

        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'

        if instance.sampleTime > 0:
            samplingStr = ' [SampleRate: %g] ' % instance.sampleTime
            sampleRateStr = '(%s%%)' % perSample
        else:
            samplingStr = ''
            sampleRateStr = ''

        # set task info #
        procInfo = '%s(%s)' % (instance.comm, instance.pid)

        nrCpuUsageSample = len(instance.cpuUsageList)
        if nrCpuUsageSample > 0:
            # calculate average CPU usage #
            ttime = utime = stime = 0
            for cpustat in instance.cpuUsageList:
                ttime += cpustat[0]
                utime += cpustat[1]
                stime += cpustat[2]
            ttime /= float(nrCpuUsageSample)
            utime /= float(nrCpuUsageSample)
            stime /= float(nrCpuUsageSample)
            cpuStr = '%d%%(Usr/%d%%+Sys/%d%%)' % (ttime, utime, stime)
            cpuStr = '[%s: %s]' % (procInfo, cpuStr)
        else:
            cpuStr = ' [%s]' % procInfo

        # print top stat #
        SysMgr.printPipe((
            '\n[%s %s Summary] [Elapsed: %.3f]%s%s '
            '[NrSamples: %s%s] [NrSymbols: %s] %s') % \
                (mtype, ctype, elapsed, samplingStr, cpuStr,
                convert(long(nrTotal)), sampleRateStr,
                convert(len(callTable)), suffix))

        SysMgr.printPipe('%s%s' % (twoLine, suffix))
        SysMgr.printPipe(
            '{0:^7} | {1:<144}{2:1}'.format(
                'Usage', 'Function %s' % addInfo, suffix))
        SysMgr.printPipe('%s%s' % (twoLine, suffix))

        cnt = long(0)
        for sym, value in sorted(callTable.items(),
            key=lambda x:x[1]['cnt'], reverse=True):
            if sym[0] == '/':
                sym = '??'

            # get percentage #
            try:
                per = value['cnt'] / nrTotal * 100
            except:
                break

            # add stats #
            if instance.mode == 'syscall':
                addVal = '<Cnt: %s>' % convert(value['cnt'])
            elif instance.mode == 'break':
                addVal = '[%s] <Cnt: %s' % (
                    value['path'], convert(value['cnt']))

                # add return stats #
                rsym = sym + Debugger.RETSTR
                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 = '%s>' % addVal
            else:
                addVal = '[%s] <Cnt: %s>' % \
                    (value['path'], convert(value['cnt']))

            SysMgr.printPipe(
                '{0:>7} | {1:<144}{2:1}'.format(
                    '%.1f%%' % per, '%s %s' % (sym, 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):

                    bper = btcnt / float(value['cnt']) * 100
                    ret = SysMgr.printPipe(
                        '{0:>17} | {1:<1} <Cnt: {2:1}>'.format(
                            '%.1f%%' % bper, bt, convert(btcnt)))

            cnt += 1

        if cnt == 0:
            SysMgr.printPipe('\tNone%s' % suffix)

        SysMgr.printPipe('%s%s' % (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 '
                '[NrSamples: %s(%s%%)] [NrFiles: %s] %s') % \
                    (mtype, elapsed, samplingStr, cpuStr,
                    convert(long(nrTotal)), perSample,
                    convert(len(fileTable)), suffix))
            SysMgr.printPipe('%s%s' % (twoLine, suffix))
            SysMgr.printPipe(
                '{0:^7} | {1:<144}{2:1}'.format('Usage', 'Path', suffix))
            SysMgr.printPipe('%s%s' % (twoLine, suffix))

            cnt = long(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))

                cnt += 1

            if cnt == 0:
                SysMgr.printPipe('\tNone%s' % suffix)

            SysMgr.printPipe('%s%s' % (oneLine, suffix))

        instance.printCallHistory(instance)

        # stop target to return original status #
        if needStop:
            instance.stop(check=True)

        # check realtime mode #
        if SysMgr.procBuffer == []:
            return

        # print detailed statistics #
        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("\n\tNone%s" % suffix)
        else:
            SysMgr.printPipe(SysMgr.procBuffer)



    @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((
                        'fail 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(
                'fail to dump memory for %s(%s)' % \
                    (SysMgr.getComm(pid), pid), reason=True)



    @staticmethod
    def pauseThreads(tlist):
        def _updateTargets(taskList):
            dlist = []
            tlist = list(taskList.keys())

            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 = long(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('fail to create a process')
                    sys.exit(0)

            # 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(
                'fail to pause thread %s' % lastTid, True)



    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 isForked(self, status):
        stat = status >> 8
        return (stat == self.sigForkFlag or \
            stat == self.sigVforkFlag)



    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('no regset')
        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(
            "fail to write remote registers for %s(%s)" % \
                (self.comm, self.pid))

        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(
                "fail to get fp register set of %s(%s)" % \
                    (self.comm, self.pid))

        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('no regset')
        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 = "fail to read registers for %s(%s)" % \
                (self.comm, self.pid)

            # check state #
            if self.isStopped():
                SysMgr.printWarn(errMsg)
                return self.getRegs()
            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 == 'heap' or meminfo == '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(
                    "fail to search %s on memory map for %s(%s)" % \
                        (meminfo, self.comm, self.pid))
                return 0

        # convert range #
        start = UtilMgr.convStr2Num(ret[0])
        if not start:
            return 0
        end = UtilMgr.convStr2Num(ret[1])
        if not end:
            return 0
        size = end - start

        if verb:
            SysMgr.printInfo(
                "start dumping memory %s [%s-%s] from %s(%s)" % \
                    (UtilMgr.convSize2Unit(size),
                        hex(start).rstrip('L'), hex(start+size).rstrip('L'),
                        self.comm, self.pid))

        # open output file #
        try:
            fd = open(output, 'wb')
        except:
            SysMgr.printOpenErr(output)
            return 0

        # 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 syncing %s data to %s" % \
                    (UtilMgr.convSize2Unit(total), output))

        fd.close()

        return total



    def ptraceEvent(self, reqList):
        # define architect-independant 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_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_TRACEEXEC':
                option |= 1 << plist.index('PTRACE_EVENT_EXEC')
            elif req == 'PTRACE_O_TRACEVFORKDONE':
                option |= 1 << plist.index('PTRACE_EVENT_VFORK_DONE')
            elif req == 'PTRACE_O_TRACEEXIT':
                option |= 1 << plist.index('PTRACE_EVENT_EXIT')
            elif req == 'PTRACE_O_TRACESECCOMP':
                option |= 1 << plist.index('PTRACE_EVENT_SECCOMP')

        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

        # set default option #
        options = __WALL

        ret = 0

        if pid is None:
            pid = self.pid

        try:
            # type converting #
            if not self.initWaitpid:
                SysMgr.libcObj.waitpid.argtypes = \
                    (c_int, POINTER(None), c_int)
                SysMgr.libcObj.waitpid.restype = c_int
                self.initWaitpid = True

            status = c_uint(0)

            while 1:
                try:
                    ret = SysMgr.libcObj.waitpid(
                        pid, pointer(status), options)
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

                if ret == -1:
                    if not self.isAlive():
                        sys.exit(0)
                    continue

                break

            return ret, status.value
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn(
                'fail to call waitpid', reason=True)
            return 0, 0



    def ptrace(self, req, addr=0, data=0, pid=None):
        if not pid:
            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

            ret = SysMgr.libcObj.ptrace(req, pid, addr, data)
            if c_long(ret).value == -1:
                return -1
            else:
                return ret
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn(
                'fail 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 len(eventData) > 0:
            SysMgr.printPipe(
                "\n[%s] [ Total: %d ]" % ('Event Info', len(eventData)))
            SysMgr.printPipe(twoLine)
            try:
                EventAnalyzer.printEvent()
            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 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')

        self.mem = bytearray(size)
        ptr = (c_char * size).from_buffer(self.mem)

        ret = memmove(ptr, self.addr, size)
        if ret < 0:
            SysMgr.printErr(
                "fail to copy memory from %s" % self.addr)
        else:
            self.size = size

        return ret



    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):]



    def tell(self):
        return self.pos



    def seek(self, pos):
        self.pos = pos





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_CONSTANTS = {
        "DW_INL_not_inlined":0,
        "DW_INL_inlined":1,
        "DW_INL_declared_not_inlined":2,
        "DW_INL_declared_inlined":3,

        "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_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_ACCESS_public":1,
        "DW_ACCESS_protected":2,
        "DW_ACCESS_private":3,

        "DW_VIS_local":1,
        "DW_VIS_exported":2,
        "DW_VIS_qualified":3,

        "DW_VIRTUALITY_none":0,
        "DW_VIRTUALITY_virtual":1,
        "DW_VIRTUALITY_pure_virtual":2,

        "DW_ID_case_sensitive":0,
        "DW_ID_up_case":1,
        "DW_ID_down_case":2,
        "DW_ID_case_insensitive":3,

        "DW_CC_normal":0x1,
        "DW_CC_program":0x2,
        "DW_CC_nocall":0x3,

        "DW_ORD_row_major":0,
        "DW_ORD_col_major":1,

        "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_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_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_FORM = {
        "DW_FORM_null":0x00,
        "DW_FORM_addr":0x01,
        "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_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_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_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 range(0, 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 = dict()
            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):
            """ 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(', ')
                        for reg in regs:
                            if reg == 'lr':
                                self.cfa_table[lrIdx] = ('OFFSET', self.offset)
                            elif reg == 'fp':
                                self.cfa_table[fpIdx] = ('OFFSET', self.offset)
                            elif reg == 'sp':
                                self.cfa_table[spIdx] = ('OFFSET', self.offset)
                            elif reg == 'ip':
                                self.cfa_table[ipIdx] = ('OFFSET', self.offset)
                            elif reg == 'pc':
                                self.cfa_table[pcIdx] = ('OFFSET', self.offset)
                            else:
                                reg = long(reg[1:])
                                self.cfa_table[reg] = ('OFFSET', 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_range(self, start, count):
            return ((1 << (count + 1)) - 1) << start

        def _printGPR(self, gpr_mask):
            hits = [self.gpr_register_names[i] for i in range(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 range(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_range(4, opcode & 0x07))

        def _decode_10101nnn(self):
            opcode = self._bytecode_array[self._index]
            self._index += 1
            return 'pop %s' % self._printGPR(
                self._calculate_range(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_range(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_range(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_range(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_range(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_range(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 = {}
    strippedFiles = {}
    failedFiles = {}
    relocTypes = {}
    cachedDemangleTable = {}
    overlayTable = {}



    @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(
                    'fail to make %s directory' % \
                        SysMgr.cacheDirPath, reason=True)

        # build cache path #
        cpath = '%s/%s' % \
            (SysMgr.cacheDirPath, path.replace('/', '_'))

        return UtilMgr.saveObjectToFile(obj, cpath)



    @staticmethod
    def getCachedFilename(path):
        return '%s/%s' % \
            (SysMgr.cacheDirPath, path.replace('/', '_'))



    @staticmethod
    def loadObject(path):
        # build cache path #
        cpath = ElfAnalyzer.getCachedFilename(path)

        # check modified time #
        try:
            otime = os.stat(path).st_ctime
            ctime = os.stat(cpath).st_ctime

            if otime > ctime:
                SysMgr.printWarn(
                    "'%s' is more recent than the cache '%s'" % \
                        (path, cpath), True)
        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 isLoadableFile(path):
        if path == 'vsyscall' or \
            path == 'vvar' or \
            path == 'stack':
            return False
        else:
            return True



    @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(
                "fail to load %s because it is already deleted" % path)
            return None

        # 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

            # print start message #
            if log:
                SysMgr.printInfo('start loading binaries...')

            if path == 'vdso':
                fobj = SysMgr.getVDSO()

            # print load message #
            SysMgr.printInfo(
                "load %s... " % path, suffix=False, prefix=False)

            # return a exceptional file object #
            if fobj:
                SysMgr.printInfo("[done]", prefix=False, notitle=True)
                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
                    SysMgr.printInfo("[cached]", prefix=False, notitle=True)
                    return fobj

            # create a new object #
            try:
                raiseExcept = False

                elfObj = ElfAnalyzer(path)
                if not elfObj or not elfObj.ret:
                    raiseExcept = True
                    raise Exception('not an ELF file')

                ElfAnalyzer.cachedFiles[path] = elfObj
                SysMgr.printInfo("[done]", prefix=False, notitle=True)
            except SystemExit:
                sys.exit(0)
            except:
                ElfAnalyzer.failedFiles[path] = True

                failLog = UtilMgr.convColor("[fail]", 'RED')
                SysMgr.printInfo(failLog, prefix=False, notitle=True)

                SysMgr.printWarn(
                    "fail 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 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 #
        origSym = symbol
        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):
        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]

        # strip llvm info #
        if '.llvm.' in symbol:
            symbol = symbol[:symbol.find('.llvm.')]

        # check version #
        if '@' in symbol:
            symbol, version = symbol.split('@')
            version = '@%s' % version
        else:
            version = ''

        # get ctypes object #
        if not SysMgr.importPkgItems('ctypes', False):
            SysMgr.printWarn((
                "fail 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 #
            SysMgr.loadLibcObj()

            # load demangle library #
            if not SysMgr.libdemangleObj:
                SysMgr.libdemangleObj = SysMgr.loadLib(SysMgr.libdemanglePath)

            # declare free() args #
            SysMgr.libcObj.free.argtypes = [c_void_p]

            # declare __cxa_demangle() function pointer #
            funcp = getattr(SysMgr.libdemangleObj, '__cxa_demangle')
            funcp.restype = c_void_p

            status = c_int()
            mSymbol = c_char_p(UtilMgr.encodeStr(symbol))

            # call to demangle symbol #
            ret = funcp(mSymbol, None, None, pointer(status))

            retc = cast(ret, c_char_p)

            # check return status and convert type from bytes to string #
            if status.value == 0:
                try:
                    dmSymbol = str(retc.value.decode())
                except:
                    dmSymbol = str(retc.value)
            elif status.value == -1:
                SysMgr.printWarn(
                    "fail to allocate memory to demangle symbol %s" % symbol)
                dmSymbol = symbol
            elif status.value == -2:
                SysMgr.printWarn(
                    "fail to demangle %s because of invalid name" % symbol)
                dmSymbol = symbol
            elif status.value == -3:
                SysMgr.printWarn(
                    "fail to demangle %s because of invalid args" % symbol)
                dmSymbol = symbol
            else:
                SysMgr.printWarn(
                    "fail to demangle %s because of unknown status %d" % \
                        (symbol, status.value))
                dmSymbol = symbol

            # 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 #
            dmSymbol = ElfAnalyzer.demangleRustSym(dmSymbol)

            # demangle symbols for java #
            '''
            toDo: implement demangleJavaSym()
            dmSymbol = ElfAnalyzer.demangleJavaSym(dmSymbol)
            '''

            demangledSym = '%s%s' % (dmSymbol, version)
            ElfAnalyzer.cachedDemangleTable[origSym] = demangledSym
            return demangledSym
        except SystemExit:
            sys.exit(0)
        except:
            err = SysMgr.getErrMsg()
            SysMgr.printWarn((
                "fail 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:
                if ElfAnalyzer.isLoadableFile(binPath):
                    SysMgr.printWarn(
                        'fail 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:
            SysMgr.printErr(
                "fail to execute %s to get address from binary" % objdumpPath)
            sys.exit(0)

        while 1:
            try:
                # read a line from objdump process #
                line = proc.stdout.readline()
            except:
                SysMgr.printErr(
                    "fail to read output from objdump", True)

            # handle error #
            if not line:
                err = proc.stderr.read()
                if len(err) > 0:
                    try:
                        proc.terminate()
                    except:
                        pass
                    SysMgr.printErr(err[err.find(':') + 2:])
                    sys.exit(0)
                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(
                "fail to check relocatable format", reason=True)
            return False

        # check file name #
        if '.so' in path or \
            '.ttf' in path or \
            '.pak' in path:
            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 = deepcopy(self.attr['symTable'])
        tempSymTable.update(self.attr['dynsymTable'])
        tempSymTable.update(self.attr['dwarfTable'])
        self.mergedSymTable = tempSymTable

        # add PLT symbol #
        if not ElfAnalyzer.isRelocFile(self.path):
            pltinfo = self.getSectionHeader('.plt')
            if pltinfo:
                tempSymTable['PLT'] = {
                        'vis': 'DEFAULT', 'bind': 'GLOBAL',
                        'value': pltinfo['addr'], 'ndx': 17,
                        'type': 'OBJECT', 'size': pltinfo['size']}

        mainSym = '?'
        prevAddr = None
        prevSize = 0
        prevLen = 0

        # 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 #
            curLen = idx.find('@')
            if curLen < 0:
                curLen = len(idx)

            # update main symbol caused by same address #
            if prevAddr == item['value']:
                if idx.startswith('_') and \
                    not mainSym.startswith('_'):
                    pass
                elif not idx.startswith('_') and \
                    mainSym.startswith('_'):
                    mainSym = idx
                elif '@' in idx and \
                    not '@' in mainSym:
                    mainSym = idx
                elif curLen < prevLen:
                    mainSym = idx
                prevLen = curLen
                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 #
        try:
            if not prevAddr:
                raise Exception()

            self.sortedAddrTable.append(prevAddr)
            self.sortedSymTable.append([mainSym, prevSize])
        except:
            pass

        # 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 = long(0)

            if addrTable[idx] > offset:
                if idx > 0:
                    start = addrTable[idx-1] + symTable[idx-1][1] + 1
                    end = addrTable[idx] - 1
                else:
                    start = long(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 = long(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 = list()

        # 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 idx in range(0, 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:].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:].decode('latin-1')
                arg1, nsize = UtilMgr.decodeULEB128(data)
                pos += nsize
                data = table[pos:].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:].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:].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:].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:].decode('latin-1')
                arg1, nsize = UtilMgr.decodeULEB128(data)
                pos += nsize
                data = table[pos:].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:].decode('latin-1')
                arg1, nsize = UtilMgr.decodeULEB128(data)
                pos += nsize
                data = table[pos:].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:].decode('latin-1')
                arg, nsize = UtilMgr.decodeULEB128(data)
                pos += nsize
                args = [arg]
            else:
                inst = None
                SysMgr.printErr(
                    'fail to recognize CFI opcode %s for %s' % \
                        (hex(opcode), self.path))
                break

            cfi.append([inst, opcode, args])

        return cfi



    def unzip(self, 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 True:
            chunk = fd.read(SysMgr.pageSize)
            if not chunk:
                break
            uncompBytes += decompressor.decompress(chunk)

        uncompBytes += decompressor.flush()

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

        return uncompBytes, len(uncompBytes)



    def getString(self, strtable, start=0):
        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:
                symbol = strtable[start:idx]

        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('fail 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 __init__(
        self, path=None, debug=False, onlyHeader=False,
        fd=None, size=sys.maxsize, incArg=False):

        # 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:
            # check debug file #
            filename = os.path.basename(path)
            dirname = os.path.dirname(path)
            debugPath = '%s/.debug/%s' % (dirname, filename)
            if not os.path.isfile(debugPath):
                debugPath = '/usr/lib/debug%s' % path
                if not os.path.isfile(debugPath):
                    debugPath = None

            # merge a debug file #
            if debugPath:
                SysMgr.printInfo(
                    "merge %s's debug symbols" % debugPath)

                dobj = ElfAnalyzer(debugPath, debug=debug)
                if dobj:
                    dobj.mergeSymTable()
                    self.addrTable.update(dobj.addrTable)
                    dobj.addrTable.clear()
                self.attr['symTable'] = deepcopy(dobj.attr['symTable'])
                self.attr['dynsymTable'] = deepcopy(dobj.attr['dynsymTable'])

            # 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.abspath(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 = "fail 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 invaild 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', dict())
        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:
            SysMgr.printPipe('''\

[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 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_shstrndx)

        # parse string section #
        fd.seek(sh_offset)
        str_section = fd.read(sh_size)

        # define program info #
        self.attr['progHeader'] = list()

        # print program header title #
        if debug:
            SysMgr.printPipe((
                "[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 range(0, 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

            if not debug:
                continue

            # print program header #
            SysMgr.printPipe(
                "%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:
            SysMgr.printPipe(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_shehframe = -1
        e_shdbgframe = -1
        e_shehframehdr = -1
        e_sharmidx = -1
        e_shframe = -1

        # define section info #
        self.attr.setdefault('sectionHeader', dict())

        # print section header title #
        if debug:
            SysMgr.printPipe(
                ("\n[Section Headers]\n%s\n"
                "[NR] %50s%15s%12s%12s%20s%8s%5s%5s%7s%6s\n%s") % \
                (twoLine, "Name", "Type", "Address", "Offset", "Size(%)",
                "EntSize", "Flag", "Link", "Info", "Align", twoLine))

        # parse section header #
        for i in range(0, 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 += "W"
            if sh_flags & ElfAnalyzer.SHF_ALLOC:
                f += "A"
            if sh_flags & ElfAnalyzer.SHF_EXECINSTR:
                f += "X"
            if sh_flags & ElfAnalyzer.SHF_MASKPROC:
                f += "M"

            # 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(%2.1f%%)' % (UtilMgr.convNum(sh_size), size_per)
                SysMgr.printPipe(
                    "[%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 == '.eh_frame_hdr':
                e_shehframehdr = 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:
            SysMgr.printPipe(oneLine)

        # define versym info #
        self.attr['versymList'] = list()

        # 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 range(0, 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', dict())
        self.attr.setdefault('dynsymList', ['']) # STN_UNDEF == 0
        self.attr.setdefault('versionTable', dict())

        # 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 = long(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 = long(0)
                entsize = 20
                sentsize = 8
                for idx in range(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 range(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 = long(0)
                entsize = 16
                for idx in range(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 range(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:
                SysMgr.printPipe((
                    "\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:
                SysMgr.printPipe('\tNone')

            printCnt = 0

            for i in range(0, 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, inc=True):
                            continue

                    SysMgr.printPipe(
                        "%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:
                    SysMgr.printPipe('\tNone')
                SysMgr.printPipe(oneLine)

        # define .sym info #
        self.attr.setdefault('symTable', dict())

        # 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:
                SysMgr.printPipe((
                    "\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:
                SysMgr.printPipe('\tNone')

            printCnt = 0

            for i in range(0, 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, inc=True):
                            continue

                    SysMgr.printPipe(
                        "%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:
                    SysMgr.printPipe('\tNone')
                SysMgr.printPipe(oneLine)
        else:
            ElfAnalyzer.strippedFiles[path] = True
            SysMgr.printWarn(
                "fail 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:
                SysMgr.printPipe((
                    '\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:
                SysMgr.printPipe('\tNone')

            printCnt = 0
            for i in range(0, 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 = long(0)

                if debug:
                    # apply filter #
                    if SysMgr.filterGroup:
                        if not UtilMgr.isValidStr(symbol, inc=True):
                            continue

                    SysMgr.printPipe(
                        '%016x %016x %32s %016x %s' % \
                        (sh_offset, sh_info, RTYPE, saddr, symbol))

                    printCnt += 1

            if debug:
                if printCnt == 0:
                    SysMgr.printPipe('\tNone')
                SysMgr.printPipe(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:
                SysMgr.printPipe((
                    '\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:
                SysMgr.printPipe('\tNone')

            printCnt = 0

            for i in range(0, 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, inc=True):
                            continue

                    SysMgr.printPipe(
                        '%016x %016x %32s %s %s' % \
                            (sh_offset, sh_info, RTYPE, val,
                            '%s%x' % (symbol, sh_addend)))

                    printCnt += 1

            if debug:
                if printCnt == 0:
                    SysMgr.printPipe('\tNone')
                SysMgr.printPipe(oneLine)

        # set DWARF Flag #
        if SysMgr.dwarfEnable:
            self.attr['dwarfEnabled'] = True
        else:
            self.attr['dwarfEnabled'] = False

        # check frame section #
        if '.eh_frame' in self.attr['sectionHeader'] and \
            self.attr['sectionHeader']['.eh_frame']['type'] != 'NOBITS':
            frameSectName = 'eh_frame'
            e_shframe = e_shehframe
        elif '.debug_frame' in self.attr['sectionHeader'] and \
            self.attr['sectionHeader']['.debug_frame']['type'] != 'NOBITS':
            # toDo: need to implement more for DWARF v4 #
            frameSectName = 'debug_frame'
            e_shframe = e_shdbgframe
        elif '.zdebug_frame' in self.attr['sectionHeader'] and \
            self.attr['sectionHeader']['.zdebug_frame']['type'] != 'NOBITS':
            frameSectName = 'debug_frame'
            e_shframe = e_shdbgframe
        else:
            frameSectName = ''

        # check frame section #
        self.attr['dwarfTable'] = dict()
        if SysMgr.dwarfEnable and e_shframe >= 0 and frameSectName:
            def _getEncType(encoding):
                if encoding == ENC_FLAGS['DW_EH_PE_omit']:
                    SysMgr.printErr(
                        'fail 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(
                        'fail to recognize modifier %x' % encoding)
                    sys.exit(0)
                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(
                        'fail to recognize basic encoding %s' % encFormat)
                    sys.exit(0)

                return val

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

            def _getAugData(string, table, pos, size):
                if size == 0:
                    return dict(), '', ''

                augdata = table[pos:pos+size]

                # parse data #
                augpos = 0
                augdict = dict()
                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(
                                'fail to recognize encoding format %x' % \
                                    basicEnc)
                            sys.exit(0)

                        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(
                            'fail to recognize augmentation "%s"' % char)
                        sys.exit(0)

                adstr = _getAugStr(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

                copy = SysMgr.getPkg('copy', False)

                # CIE #
                if entry == 'CIE':
                    myObj = cie
                    curLine = dict(pc=0, cfa=CFARule(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=CFARule(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'] = CFARule(reg=args[0], offset=args[1])
                    elif name == 'DW_CFA_def_cfa_sf':
                        curLine['cfa'] = CFARule(reg=args[0],
                            offset=args[1] * cie['daf'])
                    elif name == 'DW_CFA_def_cfa_register':
                        curLine['cfa'] = CFARule(reg=args[0],
                            offset=curLine['cfa'][offsetIdx])
                    elif name == 'DW_CFA_def_cfa_offset':
                        curLine['cfa'] = CFARule(
                            reg=curLine['cfa'][regIdx], offset=args[0])
                    elif name == 'DW_CFA_def_cfa_offset_sf':
                        curLine['cfa'] = CFARule(
                            reg=curLine['cfa'][regIdx],
                            offset=args[0] * cie['daf'])
                    elif name == 'DW_CFA_def_cfa_expression':
                        curLine['cfa'] = CFARule(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(copy.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:
                    SysMgr.printPipe(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

                SysMgr.printPipe(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', dict())
            self.attr['dwarf']['CIE'] = dict()
            self.attr['dwarf']['FDE'] = dict()
            self.attr['dwarf'].setdefault('general', dict())
            self.attr['dwarf'].setdefault('CFAIndex', list())
            self.attr['dwarf'].setdefault('CFATable', dict())
            ENC_FLAGS = ElfAnalyzer.DW_EH_encoding_flags
            nrCIE = nrFDE = 0

            # get symbol string #
            shname = self.getString(str_section, sh_name)

            if debug:
                SysMgr.printPipe(
                    '\n[%s Section]\n%s' % (shname, twoLine))

            # set position #
            fd.seek(sh_offset)

            # decompress section #
            if shname.startswith('.z'):
                decompSect, decompSize = self.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)
            else:
                isCompressed = False

            # 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:].decode('latin-1')
                    caf, nsize = UtilMgr.decodeULEB128(data)
                    pos += nsize

                    # Data Alignment Factor #
                    data = table[pos:].decode('latin-1')
                    daf, nsize = UtilMgr.decodeSLEB128(data)
                    pos += nsize

                    # Return Address Register #
                    data = table[pos:].decode('latin-1')
                    rar, nsize = UtilMgr.decodeULEB128(data)
                    pos += nsize

                    # Augmentation Size #
                    if 'z' in augstr:
                        data = table[pos:].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': list(),
                    }

                    # 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)
                        SysMgr.printPipe(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(
                            'fail 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(
                                "fail to find FDE encoding data from CIE %x" % \
                                    cie['id'])
                            sys.exit(0)
                    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 = _getAugStr(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': list(),
                    }

                    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, inc=True):
                                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 #
                        SysMgr.printPipe(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'].keys()):
                if not name in ('CFAIndex', 'CFATable'):
                    del self.attr['dwarf'][name]

            if debug:
                SysMgr.printPipe(
                    '\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', dict())
            self.attr['dwarf']['hdr'] = dict()
            ENC_FLAGS = ElfAnalyzer.DW_EH_encoding_flags

            # get symbol string #
            shname = self.getString(str_section, sh_name)

            if debug:
                SysMgr.printPipe(
                    '\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:
                SysMgr.printPipe((\
                    'eh_frame pointer: %016x, FDE count: %s\n%s' %
                        (ehframePtr, UtilMgr.convNum(fdeCnt), oneLine)))

                # print menu #
                SysMgr.printPipe(
                    '{0:^5} {1:^16} {2:^16}'.format(
                            'IDX', 'FUNC ADDR', 'FDE ADDR'))

            # table #
            printCnt = 0
            for idx in range(0, 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, inc=True):
                            continue

                    SysMgr.printPipe(output)

                    printCnt += 1

            if debug:
                if printCnt == 0:
                    SysMgr.printPipe('%s\n\tNone' % oneLine)
                SysMgr.printPipe(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:
                    SysMgr.printPipe('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:
                    SysMgr.printPipe(
                        ' Function offset %s: %s' % (\
                            hex(foffset).rstrip('L'), toffset))

                if personality == -1:
                    if debug:
                        SysMgr.printPipe('\n')
                    return

                if debug:
                    SysMgr.printPipe(
                        ' Compact model index: %s' % personality)

                    # print op code #
                    for line in dobj.mnemonic_array:
                        SysMgr.printPipe(' %s' % line)

                    SysMgr.printPipe('\n')

            self.attr.setdefault('dwarf', dict())
            self.attr['dwarf'].setdefault('general', dict())
            self.attr['dwarf'].setdefault('CFAIndex', list())
            self.attr['dwarf'].setdefault('CFATable', dict())

            # 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:
                SysMgr.printPipe(
                    '\n[%s Section]\n%s\n' % (shname, twoLine))

            for idx in range(0, 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 range(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:
                SysMgr.printPipe(oneLine)

        # 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:
            SysMgr.printPipe((
                '\n[.dynamic Section]\n%s\n'
                '%16s %20s %32s\n%s') % \
                (twoLine, "Tag", "Type", "Name/Value", twoLine))

        nrItems = long(sh_size / sh_entsize)
        if nrItems == 0:
            SysMgr.printPipe('\tNone')

        for i in range(0, 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':
                    SysMgr.printPipe(
                        '%016x %20s %32s' % \
                        (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':
                    SysMgr.printPipe(
                        '%016x %20s %32s' % \
                        (d_tag, ElfAnalyzer.DT_TYPE[d_tag], d_un))
                else:
                    SysMgr.printPipe(
                        '%016x %20s %32s' % \
                        (d_tag, ElfAnalyzer.DT_TYPE[d_tag], hex(d_un)))
            else:
                SysMgr.printPipe(
                    '%016x %20s %32s' % (d_tag, d_tag, hex(d_un)))

        if debug:
            SysMgr.printPipe('%s\n\n\n' % oneLine)





class TaskAnalyzer(object):
    """ Analyzer for thread profiling """

    reportData = {}
    eventCommandList = {}
    lifeIntData = {}
    lifecycleData = {}
    procTotData = {}
    procIntData = []
    procEventData = []
    dbusData = {'totalCnt': long(0), 'totalErr': long(0)}
    dbgObj = None

    # request type #
    requestType = [
        'LOG',
        'EVENT',
        'PRINT',
        'REPORT_ALWAYS',
        'REPORT_BOUND',
    ]

    init_procTotData = \
        {'comm': '', 'ppid': long(0), 'nrThreads': long(0), 'pri': '',
        'startIdx': long(0), 'cpu': long(0), 'cpuMax': long(0),
        'cpuMin': long(-1), 'cpuAvg': long(0), 'dly': long(0),
        'initMem': long(0), 'lastMem': long(0), 'memDiff': long(0),
        'minMem': long(0), 'maxMem': long(0), 'minVss': long(0),
        'maxVss': long(0), 'blk': long(0), 'blkrd': long(0), 'blkwr': long(0)}

    init_procIntData = \
        {'cpu': long(0), 'cpuMax': long(0), 'cpuMin': long(-1),
        'cpuAvg': long(0), 'dly': long(0), 'mem': long(0), 'memDiff': long(0),
        'blk': long(0), 'blkrd': long(0), 'blkwr': long(0), 'die': False}



    @staticmethod
    def checkFilter(comm, pid):
        found = False

        for idx in list(SysMgr.filterGroup):
            # check exclusion condition #
            if idx.startswith('^'):
                cond = idx[1:]
                if cond in comm or pid == cond:
                    found=False
                    break
                else:
                    found=True
                    continue

            # check inclusion condition #
            if idx in comm or pid == idx:
                found = True
                break

        return found



    @staticmethod
    def doSumReport(fname):
        if not fname:
            SysMgr.printErr("no input file")
            sys.exit(0)

        # 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(
                "fail to recognize %s" % fname)
            sys.exit(0)

        # check data #
        SysMgr.procBuffer = SysMgr.procBuffer[start:end]

        # reverse sequence #
        if reverse:
            SysMgr.procBuffer = list(reversed(SysMgr.procBuffer))

        # print summary #
        try:
            TaskAnalyzer.printIntervalUsage()
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "fail to print interval summary", reason=True)



    @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)
        if len(flist) < 2:
            SysMgr.printErr(
                "input at least more than one effective path")
            sys.exit(0)

        # define variable and table #
        nrFiles = len(flist)
        unionCpuList = dict()
        unionGpuList = dict()
        unionRssList = dict()
        statFileList = dict()

        # 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:
                sys.exit(0)

            # 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.keys()):
                if pinfo.startswith('*'):
                    cpuProcUsage[pinfo[1:]] = cpuProcUsage.pop(pinfo)
                else:
                    break

            # merge tasks having same name #
            prevTask = None
            for pinfo in sorted(cpuProcUsage.keys()):
                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 = dict()
                    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 lastest one #
            if idx == len(flist)-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.keys()):
                if pinfo.startswith('*'):
                    gpuProcUsage[pinfo[1:]] = gpuProcUsage.pop(pinfo)
                else:
                    break

            # merge tasks having same name #
            prevTask = None
            for pinfo in sorted(gpuProcUsage.keys()):
                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 = dict()
                    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 lastest one #
                if idx == len(flist)-1:
                    unionGpuList[pname] = value['diff']

            # remove * characters #
            for pinfo in sorted(memProcUsage.keys()):
                if pinfo.startswith('*'):
                    memProcUsage[pinfo[1:]] = memProcUsage.pop(pinfo)
                else:
                    break

            # merge tasks having same name #
            prevTask = None
            for pinfo in sorted(memProcUsage.keys()):
                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 = dict()
                    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 lastest one #
            if idx == len(flist)-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])

        # print CPU diff #
        SysMgr.printPipe('\n[Diff CPU Info]\n%s' % 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}' % len(emptyCpuStat)).format(printBuf, fname)
            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):
            printBuf = "%16s | " % pname
            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 = -(prevCpuProcList[pname][item])
                        if SysMgr.cpuAvgEnable:
                            diff = '%6.1f' %  diff

                        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' % UtilMgr.convNum(cpuProcStat['diff'])))
                elif cpuProcStat['diff'] < 0:
                    diff = '{0:>6}%'.format(
                        '%6s' % ('-%s' % \
                            UtilMgr.convNum(abs(cpuProcStat['diff']))))
                else:
                    diff = '0'

                total = UtilMgr.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)

        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]\n%s' % 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)).format(printBuf, fname)
            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
            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 = -(prevGpuProcList[pname][item])
                        if SysMgr.cpuAvgEnable:
                            diff = '%6.1f' %  diff

                        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' % UtilMgr.convNum(gpuProcStat['diff'])))
                elif gpuProcStat['diff'] < 0:
                    diff = '{0:>6}%'.format(
                        '%6s' % ('-%s' % \
                            UtilMgr.convNum(abs(gpuProcStat['diff']))))
                else:
                    diff = '0'

                total = UtilMgr.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]\n%s' % (mtype, 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)).format(printBuf, fname)
            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):
            printBuf = "%16s | " % pname
            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:
                        printBuf = '%s %6dM%s' % \
                            (printBuf, -(prevRssProcList[pname]['maxRss']),
                                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' % rssProcStat['diff'])
                elif rssProcStat['diff'] < 0:
                    diff = '{0:>6}M'.format('-%s' % abs(rssProcStat['diff']))
                else:
                    diff = '0'

                newStat = "%7s(%2d)(%6dM/%6dM/%6dM)" % \
                    (diff, rssProcStat['cnt'],
                        rssProcStat['minRss'], rssProcStat['avgRss'],
                        rssProcStat['maxRss'])

                printBuf = '%s %s' % (printBuf, newStat)

            if pname == 'FREE':
                totalBuf = printBuf
            else:
                SysMgr.addPrint(printBuf + '\n', force=True)

        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=None):

        # thread mode #
        if fpath:
            self.initThreadData()

            self.init_threadData = \
                {'comm': '', 'usage': float(0), 'cpuRank': long(0),
                'yield': long(0), 'cpuWait': float(0), 'pri': '?',
                'reqRdBlock': long(0), 'readBlock': long(0),
                'ioRank': long(0), 'irq': float(0), 'reclaimWait': float(0),
                'reclaimCnt': long(0), 'ptid': '-'*5, 'new': ' ',
                'die': ' ', 'preempted': long(0), 'preemption': long(0),
                'start': float(0), 'stop': float(0), 'ioRdWait': float(0),
                'readQueueCnt': long(0), 'readStart': float(0),
                'maxRuntime': float(0), 'coreSchedCnt': long(0),
                'longRunCore': long(-1), 'dReclaimWait': float(0),
                'dReclaimStart': float(0), 'migrate': long(0),
                'dReclaimCnt': long(0), 'ftxMax': float(0),
                'ftxLockCnt': long(0), 'ftxEnter': float(0),
                'ftxLock': float(0), 'ftxTotal': float(0),
                'ftxWaitCnt': long(0), 'ftxProcess': float(0),
                'ftxLockMax': float(0), 'ftxStat': '?',
                'ftxLSwitch': long(0), 'ftxBlockTotal': float(0),
                'ftxLBlockTotal': float(0), 'ftxBlock': float(0),
                'ftxLBlock': float(0), 'ftxBlockCnt': long(0),
                'ftxEnt': None, 'lastStatus': 'N', 'offCnt': long(0),
                'offTime': float(0), 'waitStartAsParent': float(0),
                'nrAllocPages': long(0), 'nrPages': long(0),
                'reclaimedPages': long(0), 'waitPid': long(0),
                'remainKmem': long(0), 'wasteKmem': long(0),
                'childList': None, 'kernelPages': long(0),
                'readBlockCnt': long(0), 'writeBlock': long(0),
                'writeBlockCnt': long(0), 'tgid': '-'*5,
                'cachePages': long(0), 'userPages': long(0),
                'lastOff': float(0), 'maxPreempted': float(0),
                'anonReclaimedPages': long(0), 'lastIdleStatus': long(0),
                'createdTime': float(0), 'waitChild': float(0),
                'waitParent': float(0), 'customEvent': None,
                'userEvent': None, 'kernelEvent': None, 'blkCore': long(0),
                'lockWait': float(0), 'lockTime': float(0),
                'lockCnt': long(0), 'tryLockCnt': long(0),
                'lastLockTime': float(0), 'lastLockWait': float(0),
                'reqWrBlock': long(0), 'writeQueueCnt': long(0),
                'writeBlockCnt': long(0), 'writeStart': float(0),
                'ioWrWait': float(0), 'awriteBlock': long(0),
                'awriteBlockCnt': long(0), 'schedLatency': float(0),
                'schedReady': float(0), 'lastNrSyscall': long(-1),
                'nrSyscall': long(0), 'lastCore': long(0)}

            self.init_irqData = \
                {'name': None, 'usage': float(0), 'start': float(0),
                'max': float(0), 'min': float(0), 'maxPeriod': float(0),
                'minPeriod': float(0), 'count': long(0)}

            self.init_intData = \
                {'time': float(0), 'firstLogTime': float(0),
                'cpuPer': float(0), 'totalUsage': float(0),
                'totalMemUsage': long(0), 'brUsage': long(0),
                'totalBrUsage': long(0), 'irqUsage': float(0),
                'kmemUsage': long(0), 'totalKmemUsage': long(0),
                'coreSchedCnt': long(0), 'totalCoreSchedCnt': long(0),
                'preempted': float(0), 'totalBwUsage': long(0),
                'totalPreempted': float(0), 'new': ' ', 'die': ' ',
                'bwUsage': long(0), 'cpuUsage': float(0), 'memUsage': long(0)}

            self.init_eventData = \
                {'count': long(0), 'start': float(0), 'usage': float(0),
                'max': float(0), 'min': float(0), 'maxPeriod': float(0),
                'minPeriod': float(0)}

            self.init_kmallocData = \
                {'tid': '0', 'caller': '0', 'ptr': '0', 'req': long(0),
                'alloc': long(0), 'time': '0', 'waste': long(0),
                'core': long(0)}

            self.wakeupData = \
                {'tid': '0', 'nr': '0', 'ret': '0', 'time': '0',
                'args': '0', 'valid': long(0), 'from': '0', 'to': '0',
                'corrupt': '0'}

            self.allocPageData = {}

            self.init_syscallInfo = \
                {'usage': float(0), 'last': float(0), 'count': long(0),
                'max': float(0), 'min': float(0), 'err': long(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': float(0), 'count': long(0), 'max': float(0)}

            self.init_wqData = \
                {'name': None, 'usage': float(0), 'start': float(0),
                'max': float(-1), 'min': float(-1), 'maxPeriod': float(-1),
                'minPeriod': float(-1), 'avgPeriod': float(0),
                'scount': long(0), 'rcount': long(0), 'avg': float(0),
                'task': None}

            self.finishTime = '0'
            self.lastTidPerCore = {}
            self.lastCore = '0'
            self.lastEvent = '0'
            self.timelineData = {"time_unit": "ns", "segments": list()}

        # top mode #
        else:
            self.init_procData = \
                {'isMain': False, 'tids': None, 'stat': None, 'io': None,
                'alive': False, 'runtime': float(0), 'changed': True,
                'created': False, 'new': False, 'majflt': long(0),
                'ttime': long(0), 'cttime': long(0), 'utime': long(0),
                'stime': long(0), 'taskPath': None, 'statm': None,
                'mainID': '', 'btime': long(0), 'maps': None, 'status': None}

            self.init_cpuData = \
                {'user': long(0), 'system': long(0), 'nice': long(0),
                'idle': long(0), 'wait': long(0), 'irq': long(0),
                'softirq': long(0)}

            self.nrThread = long(0)
            self.nrPrevThread = long(0)
            self.nrProcess = long(0)
            self.nrPrevProcess = long(0)
            self.nrFd = long(0)
            self.maxPid = SysMgr.pid
            self.procData = {}
            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.memData = {}
            self.prevMemData = {}
            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.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")

            # initialize netlink socket #
            try:
                SysMgr.initNetlink()
            except:
                SysMgr.printWarn(
                    "fail to initialize netlink", reason=True)

            # check to return just instance #
            if onlyInstance:
                return

            if SysMgr.graphEnable:
                # draw images based on statistics #
                if SysMgr.inputParam:
                    # FLAME GRAPH MODE #
                    if SysMgr.checkMode('drawflame', True):
                        for fpath in list(SysMgr.inputParam):
                            Debugger.drawFlame(fpath)
                    # OTHER DRAW MODE #
                    else:
                        self.drawStats(SysMgr.inputParam)
                # no path for statistics #
                else:
                    SysMgr.printErr((
                        "wrong option used, "
                        "use also -I option to load statistics data"))
                sys.exit(0)

            # set system maximum fd number #
            SysMgr.setMaxFd()

            # set default interval #
            if SysMgr.intervalEnable == 0:
                SysMgr.intervalEnable = 1

            # 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:
                    if SysMgr.processEnable:
                        SysMgr.printInfo((
                            "only specific processes that are involved "
                            "in the process group [ %s ] are shown") % \
                                taskList)
                    else:
                        SysMgr.printInfo((
                            "only specific threads that are involved "
                            "in the process group [ %s ] are shown") % \
                                taskList)
                elif SysMgr.processEnable:
                    SysMgr.printInfo(
                        "only specific processes [ %s ] are shown" % \
                            taskList)
                else:
                    SysMgr.printInfo(
                        "only specific threads [ %s ] are shown" % \
                            taskList)

            # set network config #
            if not SysMgr.findOption('x'):
                NetworkMgr.setServerNetwork(None, None, reuse=False)

            # set threshold config #
            SysMgr.applyThreshold()

            # set log buffer size #
            if SysMgr.bufferSize == -1:
                # default unlimited #
                SysMgr.bufferSize = long(0)
            else:
                # change unit from KB to Byte #
                SysMgr.bufferSize = long(SysMgr.bufferSize) << 10

            if SysMgr.outPath:
                SysMgr.printStat(
                    r"start profiling... [ STOP(Ctrl+c), SAVE(Ctrl+\) ]")

            # wait for input #
            if SysMgr.waitEnable:
                SysMgr.waitUserInput(
                    0, msg="\npress enter key...", force=True)

            # exec variable #
            if SysMgr.execEnable is None:
                self.execEnable = False
            else:
                self.execEnable = True

            # file mode #
            if SysMgr.fileTopEnable:
                try:
                    self.runFileTop()
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr("fail to monitor files", reason=True)
            # DLT mode #
            elif SysMgr.dltTopEnable:
                DltAnalyzer.runDltReceiver(mode='top')
            # D-Bus mode #
            elif SysMgr.dbusTopEnable:
                DbusMgr.runDbusSnooper(mode='top')
            # cgroup  mode #
            elif SysMgr.cgTopEnable:
                try:
                    self.runCgTop()
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printErr("fail to monitor cgroup", reason=True)

            # print system general info in advance #
            if SysMgr.outPath and SysMgr.pipeEnable and SysMgr.exitFlag:
                SysMgr.printLogo(big=True)
                SysMgr.sysInstance.saveSysStat()
                SysMgr.printInfoBuffer()
                SysMgr.printPipe('\n')

            # request service to remote server #
            self.requestService()

            # task top mode #
            try:
                self.runTaskTop()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr("fail 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(0)
            elif SysMgr.findOption('g'):
                SysMgr.printErr(
                    "-g option is already used")
                sys.exit(0)

            for index in SysMgr.preemptGroup:
                '''
                preempted state
                [preemptBit, threadList, startTime, core, totalUsage] #
                '''
                self.preemptData.append([False, {}, float(0), 0, float(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)

        # get indexes for trim #
        if 'TRIM' in SysMgr.environList:
            start, end = SysMgr.environList['TRIM'][0].split(':')
            if start.strip():
                self.trimStart = float(start.strip())
            if end.strip():
                self.trimStop = float(end.strip())

        for idx, log in enumerate(lines):
            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 self.stopFlag:
                break

        # update finish time #
        if self.finishTime == '0':
            self.finishTime = time

        UtilMgr.deleteProgress()

        # update anonymous comm #
        for idx, val in self.threadData.items():
            if val['comm'] == '<...>':
                val['comm'] = '?'

        # add comsumed 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 = long(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'] = long(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'] = long(0)
                else:
                    break
                '''

            # warn uncompleted block request #
            if len(self.ioData) > 0:
                SysMgr.printWarn(
                    "fail to handle %s block requests" % 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(0)

        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():
                    for item in SysMgr.filterGroup:
                        if item in value['comm']:
                            plist[value['tgid']] = long(0)

            for key in list(self.threadData.keys()):
                # except for core #
                if key.startswith('0['):
                    continue

                if not SysMgr.isExceptTarget(
                    key, self.threadData, plist=plist):
                    continue

                # remove thread #
                try:
                    self.threadData.pop(key, None)
                except:
                    continue



    def __del__(self):
        pass



    def runCgTop(self):
        cgroupPath = SysMgr.sysInstance.getCgroupPath()
        if not os.path.isdir(cgroupPath):
            SysMgr.printErr("fail to access cgroup filesystem")
            sys.exit(0)

        # apply for filter from 1st argument #
        if not SysMgr.filterGroup and SysMgr.hasMainArg():
            value = SysMgr.getMainArg()
            value = UtilMgr.splitString(value)
            SysMgr.filterGroup = UtilMgr.cleanItem(value)

        # 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.writeTraceCmd('AFTER')

            # get delayed time #
            delayTime = time.time() - prevTime
            if delayTime > SysMgr.intervalEnable:
                waitTime = 0.000001
            else:
                waitTime = SysMgr.intervalEnable - delayTime

            # wait for next interval #
            if not SysMgr.waitUserInput(waitTime):
                time.sleep(waitTime)



    def runFileTop(self):
        def _getFilter(init=False):
            procFilter = []
            fileFilter = []

            if SysMgr.filterGroup == []:
                return [procFilter, fileFilter]

            newFilter = ','.join(SysMgr.filterGroup)
            newFilter = newFilter.split(':')

            for pval in newFilter[0].split(','):
                if pval != '':
                    procFilter.append(pval)
            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]

        SysMgr.checkRootPerm()

        if not os.path.isdir(SysMgr.procPath):
            SysMgr.printErr("fail to access to proc filesystem")
            sys.exit(0)

        # apply for filter from 1st argument #
        if not SysMgr.filterGroup and SysMgr.hasMainArg():
            value = SysMgr.getMainArg()
            value = UtilMgr.splitString(value)
            SysMgr.filterGroup = UtilMgr.cleanItem(value)

        # import select package in the foreground #
        if not SysMgr.outPath:
            SysMgr.getPkg('select', False)

        prevFilter = []

        # initialize task stat #
        TaskAnalyzer.dbgObj = Debugger(SysMgr.pid, attach=False)
        TaskAnalyzer.dbgObj.initValues()
        TaskAnalyzer.dbgObj.getCpuUsage()

        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 #
            self.saveFileStat(nowFilter)

            # print system status #
            self.printFileStat(nowFilter)

            # flush socket cache #
            SysMgr.udpListCache = \
                SysMgr.tcpListCache = None

            # check repeat count #
            SysMgr.checkProgress()

            # reset and save proc instance #
            self.saveProcInstance()

            # reset system status #
            self.reinitStats()

            # write user command #
            SysMgr.writeTraceCmd('AFTER')

            # get delayed time #
            delayTime = time.time() - prevTime
            if delayTime > SysMgr.intervalEnable:
                waitTime = 0.000001
            else:
                waitTime = SysMgr.intervalEnable - delayTime

            # wait for next interval #
            if not SysMgr.waitUserInput(
                waitTime, msg="press enter key..."):
                time.sleep(waitTime)



    def runTaskTop(self):
        if not os.path.isdir(SysMgr.procPath):
            SysMgr.printErr("fail to access proc filesystem")
            sys.exit(0)

        # initialize perf events #
        SysMgr.initSystemPerfEvents()

        # apply for filter from 1st argument #
        if not SysMgr.filterGroup and SysMgr.hasMainArg():
            value = SysMgr.getMainArg()
            value = UtilMgr.splitString(value)
            SysMgr.filterGroup = UtilMgr.cleanItem(value)

        # import select package in the foreground #
        if not SysMgr.outPath:
            SysMgr.getPkg('select', 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 #
            self.saveSystemStat()

            # save timestamp #
            prevTime = time.time()

            if self.prevCpuData:
                # print system status #
                self.printSystemStat(idIndex=True)

                if SysMgr.elasticEnable:
                    # report system status for elastic stack
                    self.reportSystemStatElastic()
                elif SysMgr.reportEnable:
                    # report system status #
                    self.reportSystemStat()

            # check repeat count #
            SysMgr.checkProgress()

            # reset system status #
            self.reinitStats()

            # write user command #
            SysMgr.writeTraceCmd('AFTER')

            # get delayed time #
            delayTime = time.time() - prevTime
            if delayTime > SysMgr.intervalEnable:
                waitTime = 0.000001
            else:
                waitTime = SysMgr.intervalEnable - delayTime

            if SysMgr.stackEnable and self.stackTable:
                # get stack of threads #
                self.sampleStack(waitTime)
                SysMgr.waitUserInput(0.000001)
            else:
                # wait for next interval #
                if 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):
        del self.prevProcData
        self.prevProcData = self.procData
        self.procData = {}
        SysMgr.topInstance = self
        SysMgr.procInstance = self.procData



    def reinitStats(self):
        del self.prevCpuData
        self.prevCpuData = self.cpuData
        self.nsData = {}
        self.cpuData = {}
        self.fileData = {}
        self.abnormalTasks = {}
        self.nrPrevThread = self.nrThread
        self.nrPrevProcess = self.nrProcess
        self.nrThread = long(0)
        self.nrProcess = long(0)
        self.nrFd = long(0)
        SysMgr.jsonData = {}



    @staticmethod
    def getStatsFile(logFile, applyOpt=True):
        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:
            fd = UtilMgr.getTextLines(logFile, retfd=True)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr("fail to read %s\n" % logFile)
            sys.exit(0)

        SysMgr.printStat(
            r"start processing %s..." % logFile)

        # context varaible #
        finalLine = long(0)
        context = None
        totalRam = None

        # get total size #
        try:
            totalSize = os.stat(logFile).st_size
        except:
            totalSize = long(0)

        curSize = long(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 = long(0)
                average = long(0)
                maxVss = long(0)
                maxRss = long(0)
                maxUsage = long(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 = UtilMgr.convUnit2Size(sline[1][:-1])
                    except:
                        pass

                    try:
                        totalSwap = UtilMgr.convUnit2Size(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:
                    timeline.append(long(float(sline[1].split('-')[1])))
                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

            # 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 ]"] = dict()

                            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 range(0, 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'] = long(0)
                        cpuProcUsage[pname]['average'] = long(0)
                        cpuProcUsage[pname]['maximum'] = long(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 ]"] = dict()

                            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 range(0, 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'] = long(0)
                        cpuProcDelay[pname]['average'] = long(0)
                        cpuProcDelay[pname]['maximum'] = long(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'] = long(0)
                        gpuUsage[gname]['average'] = long(0)
                        gpuUsage[gname]['maximum'] = long(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 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 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 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, dict())
                    busyList = list()
                    readList = list()
                    writeList = list()
                    freeList = list()

                    # convert previous stats #
                    for item in intervalList.split():
                        busy, read, write, free = item.split('/')
                        busyList.append(busy)
                        readList.append(
                            UtilMgr.convUnit2Size(read) >> 10)
                        writeList.append(
                            UtilMgr.convUnit2Size(write) >> 10)
                        freeList.append(
                            UtilMgr.convUnit2Size(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, dict())
                    recvList = list()
                    tranList = list()

                    # convert previous stats e
                    for item in intervalList.split():
                        recv, tran = item.split('/')
                        recvList.append(
                            UtilMgr.convUnit2Size(recv) >> 10)
                        tranList.append(
                            UtilMgr.convUnit2Size(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'] = long(0)
                        cpuProcUsage[pname]['average'] = long(0)
                        cpuProcUsage[pname]['maximum'] = long(0)
                    else:
                        cpuProcUsage[pname]['minimum'] = min(cpuList)
                        cpuProcUsage[pname]['average'] = \
                            sum(cpuList) / len(cpuList)
                        cpuProcUsage[pname]['maximum'] = max(cpuList)

        UtilMgr.deleteProgress()

        # check output data #
        if not totalRam:
            SysMgr.printErr(
                "fail to find statistics data in %s" % logFile)
            sys.exit(0)
        elif not timeline:
            SysMgr.printErr(
                "fail to find interval data in %s" % logFile)
            sys.exit(0)

        # get indexes for trim #
        if 'TRIM' in SysMgr.environList:
            trim = SysMgr.environList['TRIM'][0].split(':')
            try:
                if len(trim) == 1:
                    condMin = long(trim[0])
                    condMax = sys.maxsize
                elif len(trim) >= 2:
                    condMin = long(trim[0])
                    condMax = long(trim[1])
            except:
                SysMgr.printErr(
                    "fail to recognize %s as START:END time" % \
                        ':'.join(trim))
                sys.exit(0)

            # 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)

            # 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',
        }

        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(
                    "fail to get file name from '%s" % name, True)
                sys.exit(0)

            if sname.endswith('List'):
                continue
            elif sname.endswith('ProcUsage'):
                avgList.setdefault(sname, dict())

                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 type(value[0]) is 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, dict())

                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 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)
        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:
            yrange = SysMgr.environList['YRANGE'][0].split(':')
            yminval, ymaxval = UtilMgr.cleanItem(yrange, False)

            # set ymin #
            if yminval:
                ax.set_ylim(bottom=long(yminval))
                ymin = long(yminval)
            else:
                ymin = long(min(ax.get_yticks().tolist()))
                if ymin < 0:
                    ymin = long(0)
                    ax.set_ylim(bottom=0)

            # set ymax #
            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(range(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:
                ymaxval = 1
            if ymaxval > 0:
                ylim([0, ymaxval])

            # get final yticks #
            ylist = ax.get_yticks().tolist()
            ymin = long(min(ylist))
            if ymin < 0:
                ymin = long(0)
                ax.set_ylim(bottom=0)

            # adjust yticks #
            if adjust:
                inc = long(ymax / 10)
                if inc == 0:
                    inc = 1
                yticks(range(ymin, long(ymax + inc), inc), fontsize=fontsize)
            else:
                yticks(fontsize=fontsize)



    @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():
        # get matplotlib object #
        matplotlib = SysMgr.getPkg('matplotlib', False)
        if not matplotlib:
            SysMgr.printPipWarn('matplotlib', 'matplotlib')
            sys.exit(0)

        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):
        # convert str to list #
        if type(flist) is str:
            flist = [flist]

        # get stats from 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 = dict()
            chartStats = dict()

            # parse stats from multiple files #
            for lfile in flist:
                try:
                    gstats, cstats = TaskAnalyzer.getStatsFile(lfile)
                except SystemExit:
                    sys.exit(0)
                except:
                    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

        # 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(
                    "fail to draw history graph", True)
            return

        # draw graphs #
        try:
            if not onlyChart:
                self.drawGraph(graphStats, logFile, outFile=outFile)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "fail 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(
                "fail 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...")

        seq = long(0)
        height = \
            long(len(data) / 2) \
            if len(data) % 2 == 0 else long(len(data) / 2 + 1)
        colors = \
            ['pink', 'lightgreen', 'skyblue',
            'lightcoral', 'gold', 'yellowgreen']
        propList = \
            ['count', 'vmem', 'rss', 'pss', 'swap',
            'huge', 'locked', 'pdirty', 'sdirty']
        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 = long(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 = UtilMgr.convSize2Unit(
                    value[propList.index('pdirty')] << 10, True)

                # set shared dirty size #
                sdrt = UtilMgr.convSize2Unit(
                    value[propList.index('sdirty')] << 10, True)

                # set rss size #
                rss = UtilMgr.convSize2Unit(
                    value[propList.index('rss')] << 20, True)

                # set swap size #
                swap = UtilMgr.convSize2Unit(
                    value[propList.index('swap')] << 20, True)

                # set locked size #
                locked = UtilMgr.convSize2Unit(
                    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 = UtilMgr.convSize2Unit((rss+swap) << 20)

            rss = UtilMgr.convSize2Unit(rss << 20)
            swap = UtilMgr.convSize2Unit(swap << 20)

            vmem = UtilMgr.convSize2Unit(
                item['[TOTAL]'][propList.index('vmem')] << 20)

            pss = UtilMgr.convSize2Unit(
                item['[TOTAL]'][propList.index('pss')] << 20)

            lock = UtilMgr.convSize2Unit(
                item['[TOTAL]'][propList.index('locked')] << 10)

            dirty = item['[TOTAL]'][propList.index('pdirty')] + \
                item['[TOTAL]'][propList.index('sdirty')]
            dirty = UtilMgr.convSize2Unit(dirty << 10)

            totalList =\
                [('\n%s\n%s\n\n- TOTAL: %s \n- RSS: %s \n- SWAP: %s \n%s\n\n'
                '- VIRT: %s \n- PSS: %s \n- LOCK: %s \n- DIRTY: %s') % \
                ('[%s] %s' % (str(seq+1), idx), line, total,
                rss, swap, line, vmem, pss, lock, 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.7)
            else:
                patches, texts, autotexts = \
                    pie(sizes, explode=explode, labels=labels, colors=colors,
                    autopct=_make_autopct(sizes), shadow=True, pctdistance=0.7)

            # set font size #
            for idx, val in enumerate(texts):
                val.set_fontsize(5)
                autotexts[idx].set_fontsize(3.5)
            axis('equal')

            # print total size in legend #
            if SysMgr.matplotlibVersion >= 1.2:
                legend(patches, totalList, loc="lower right", shadow=True,
                    fontsize=4.5, 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 = long(0)
        total = long(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(
                        "fail to draw graph "
                        "because %s graph is duplicated" % target)
                    sys.exit(0)
                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(
                    "fail to draw graph "
                    "because graph format [TYPE:SIZE] is wrong")
                sys.exit(0)

        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(
                        "fail to draw graph "
                        "because '%s' is not recognized" % target)
                    sys.exit(0)

                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):
        if xtype == 1:
            # convert tick type to integer #
            try:
                xtickLabel = ax.get_xticks().tolist()
                xtickLabel = list(map(long, xtickLabel))
                if len(str(xtickLabel[0])) > 5:
                    for idx, item in enumerate(list(xtickLabel)):
                        if idx % 2 > 0:
                            xtickLabel[idx] = '\n%s' % item
                    ax.set_xticklabels(xtickLabel)
                if xtickLabel[0] != xtickLabel[-1]:
                    xlim([xtickLabel[0], xtickLabel[-1]])
                    xtickLabel[-1] = '   TIME(Sec)'
                    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] = \
                                effectProcList[timeline.index(long(cnt))]
                        except SystemExit:
                            sys.exit(0)
                        except:
                            xtickLabel[seq] = ' '
                xtickLabel[-1] = '   RUN(NR)'
                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:
                        xtickLabel[seq] = nrTask[timeline.index(long(cnt))]
                    except SystemExit:
                        sys.exit(0)
                    except:
                        xtickLabel[seq] = ' '
                xtickLabel[-1] = '   TASK(NR)'
                ax.set_xticklabels(xtickLabel)
            except SystemExit:
                sys.exit(0)
            except:
                pass



    def drawUserEvent(self, mode=None):
        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((
                        'fail to recognize %s in '
                        'X:Y:NAME:[CPU|MEM|IO]:[BOX|CIRCLE|LARROW|RARROW]'
                        'format') % item)
                    sys.exit(0)

                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'

                if mode and mode.upper() != resource.upper():
                    continue

                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'

                text(long(x), long(y), name, style='italic',
                    fontsize=5, color='green', fontweight='bold',
                    bbox=dict(boxstyle=feature, facecolor='gold',
                    alpha=0.7))

            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    'fail to draw events', reason=True)
                sys.exit(0)



    def drawBoundary(self, gtype, labelList):
        if not SysMgr.boundaryLine:
            return

        try:
            boundaryList = \
                list(map(UtilMgr.convUnit2Size, SysMgr.boundaryLine))
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "fail to set boundary line", True)
            sys.exit(0)

        # 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)

            # 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

                    evtbox = '%s%s' % (prefix, '\n'.join(evts))

                    try:
                        text(timeline[tm], ylim()[-1], evtbox,
                            fontsize=3, verticalalignment='top', style='italic',
                            bbox={'facecolor':'green', 'alpha': 1, 'pad': 1},
                            ha=_getTextAlign(tm, timeline))

                        axvline(x=timeline[tm], linewidth=1,
                            linestyle='--', color='green')
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass

        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 = long(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 #
            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 len(prefix) > 0:
                            gcolor = None
                        else:
                            gcolor = 'olive'

                        # draw total gpu graph #
                        plot(timeline, stat, '-', c=gcolor, linestyle='--',
                            linewidth=1, marker='d', markersize=1,
                            solid_capstyle='round')

                        totalUsage = sum(stat)

                        try:
                            avgUsage = round(totalUsage / len(stat), 1)
                        except:
                            avgUsage = long(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=4, color='olive', fontweight='bold',
                                bbox=dict(boxstyle='round', facecolor='wheat',
                                alpha=0.3),
                                ha=_getTextAlign(idx, timeline))
                            break

                    #------------------ Total CPU usage ------------------#
                    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]

                        # set color #
                        if len(prefix) > 0:
                            icolor = None
                        else:
                            icolor = 'pink'

                        # draw total CPU + iowait graph #
                        plot(timeline, blkWait, '-', c=icolor, linestyle='--',
                            linewidth=1, marker='d', markersize=1,
                            solid_capstyle='round')

                        totalUsage = sum(blkWait)

                        try:
                            avgUsage = round(totalUsage / len(blkWait), 1)
                        except:
                            avgUsage = long(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=4, color='pink', fontweight='bold',
                                bbox=dict(boxstyle='round', facecolor='wheat',
                                alpha=0.3),
                                ha=_getTextAlign(idx, timeline))
                            break

                    # set color #
                    if len(prefix) > 0:
                        ccolor = None
                    else:
                        ccolor = 'red'

                    # draw total CPU graph #
                    plot(timeline, cpuUsage, '-', c=ccolor, linestyle='--',
                        linewidth=1, marker='d', markersize=1,
                        solid_capstyle='round')

                    totalUsage = sum(cpuUsage)

                    try:
                        avgUsage = round(totalUsage / len(cpuUsage), 1)
                    except:
                        avgUsage = long(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=4, 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 \
                    "[ TOTAL ]" in cpuProcUsage and \
                    cpuProcUsage["[ TOTAL ]"]['count'] > 1:
                    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,
                        solid_capstyle='round')

                    totalSumUsage = sum(totalUsage)

                    try:
                        avgUsage = round(totalSumUsage / len(totalUsage), 1)
                    except:
                        avgUsage = long(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

                        text(timeline[idx], totalUsage[maxIdx],
                            '%s Max_%d%%|Avg_%.1f%%|Total_%s%%' % \
                            (prefix, maxUsage, avgUsage, conv(totalSumUsage)),
                            fontsize=4, 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 #
                if SysMgr.nrTop:
                    tcnt = long(0)

                # check delay option #
                if delay:
                    targetList = cpuProcDelay
                else:
                    targetList = cpuProcUsage

                # Process CPU usage #
                for idx, item in sorted(targetList.items(),
                    key=lambda e: e[1]['average'], reverse=True):

                    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

                    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 = long(0)

                    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

                    maxIdx = usage.index(maxusage)
                    color = plot(
                        timeline, usage, '-', linewidth=0.7)[0].get_color()

                    margin = self.getMargin()

                    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)
                    text(timeline[maxIdx], usage[maxIdx] + margin, ilabel,
                        fontsize=2, 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=4)
            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):
                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' % \
                    (prefix, convSize2Unit(usage[minIdx] << 10))
                maxsize = convSize2Unit(usage[maxIdx] << 10)
                totalsize = convSize2Unit(long(sum(usage)) << 10)
                maxval = '%s%s' % (prefix, maxsize)
                lastval = '%s%s' % \
                    (prefix, convSize2Unit(usage[-1] << 10))

                # set color #
                if len(prefix) > 0:
                    rcolor = None
                else:
                    rcolor = color

                if usage[minIdx] == usage[maxIdx] == 0:
                    line = plot(timeline, statList, '-', c=rcolor,
                        linewidth=0.1, alpha=0.1)
                else:
                    line = plot(timeline, statList, '--', c=rcolor,
                        linewidth=0.7, marker='d', markersize=1)

                color = line[0].get_color()

                if usage[minIdx] > 0:
                    text(timeline[minIdx], usage[minIdx], minval,
                        fontsize=3, 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=3, color=color, fontweight='bold',
                        ha=_getTextAlign(maxIdx, timeline), rotation=35)
                if usage[-1] > 0:
                    text(timeline[-1], usage[-1], lastval, rotation=35,
                        fontsize=3, color=color, fontweight='bold',
                        ha='right')

                return totalsize, ymax

            # define common label list #
            ymax = long(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)

            # 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

            # 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)
                    labelList.append(
                        '%sBlock Read - %s' % (prefix, totalsize))

                    # System Block Write #
                    color = None if fname else 'darkgreen'
                    totalsize, ymax = _drawSystemIo(blkWrite, color, ymax)
                    labelList.append(
                        '%sBlock Write - %s' % (prefix, totalsize))

                    # System Background Reclaim #
                    color = None if fname else 'pink'
                    totalsize, ymax = _drawSystemIo(reclaimBg, color, ymax)
                    labelList.append(
                        '%sReclaim BG - %s' % (prefix, totalsize))

                    # System Direct Reclaim #
                    color = None if fname else 'red'
                    totalsize, ymax = _drawSystemIo(reclaimDr, color, ymax)
                    labelList.append(
                        '%sReclaim FG - %s' % (prefix, totalsize))

                    # System Network Inbound #
                    color = None if fname else 'orange'
                    totalsize, ymax = _drawSystemIo(netRead, color, ymax)
                    labelList.append(
                        '%sNetwork In - %s' % (prefix, totalsize))

                    # System Network Outbound #
                    color = None if fname else 'cyan'
                    totalsize, ymax = _drawSystemIo(netWrite, color, ymax)
                    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 = convSize2Unit(wrUsage[maxIdx] << 10)
                    totalsize = convSize2Unit(long(sum(wrUsage)) << 10)
                    maxval = '%s%s' % (prefix, maxsize)
                    lastval = '%s%s' % \
                        (prefix, convSize2Unit(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=3, color=color, fontweight='bold',
                                ha=_getTextAlign(maxIdx, timeline))
                        if wrUsage[-1] > 0:
                            text(timeline[-1],
                                wrUsage[-1] + margin, lastval, rotation=35,
                                fontsize=3, 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 = convSize2Unit(rdUsage[maxIdx] << 10)
                    totalsize = convSize2Unit(long(sum(rdUsage)) << 10)
                    maxval = '%s%s' % (prefix, maxsize)
                    lastval = '%s%s' % \
                        (prefix, convSize2Unit(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=3, color=color, fontweight='bold',
                                ha=_getTextAlign(maxIdx, timeline))
                        if rdUsage[-1] > 0:
                            text(timeline[-1],
                                rdUsage[-1] + margin, lastval, rotation=35,
                                fontsize=3, 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 = convSize2Unit(wrUsage[maxIdx] << 10)
                    totalsize = convSize2Unit(long(sum(wrUsage)) << 10)
                    busyval = busyUsage[maxIdx]
                    maxval = '%s%s[%s%%]' % (prefix, maxsize, busyval)
                    lastval = '%s%s' % \
                        (prefix, convSize2Unit(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=3, color=color, fontweight='bold',
                                ha=_getTextAlign(maxIdx, timeline))

                        if wrUsage[-1] > 0:
                            text(timeline[-1], wrUsage[-1] + margin, lastval,
                                fontsize=3, 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 = convSize2Unit(rdUsage[maxIdx] << 10)
                    totalsize = convSize2Unit(long(sum(rdUsage)) << 10)
                    busyval = busyUsage[maxIdx]
                    maxval = '%s%s[%s%%]' % (prefix, maxsize, busyval)
                    lastval = '%s%s' % \
                        (prefix, convSize2Unit(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=3, color=color, fontweight='bold',
                                ha=_getTextAlign(maxIdx, timeline))
                        if rdUsage[-1] > 0:
                            text(timeline[-1], rdUsage[-1] + margin, lastval,
                                fontsize=3, color=color, fontweight='bold',
                                ha='right', rotation=35)

                        labelList.append(
                            '%s%s Read - %s' % (prefix, idx, totalsize))

                # Process IO usage #
                for idx, item in blkProcUsage.items():
                    if not SysMgr.showAll:
                        break

                    usage = item['usage'].split()[:lent]
                    rdUsage = list()
                    wrUsage = list()

                    # divide io graph #
                    for item in usage:
                        io = item.split('/')
                        if(len(io) == 2):
                            rdUsage.append(long(io[0]) << 10)
                            wrUsage.append(long(io[1]) << 10)

                    # no io 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 = convSize2Unit(wrUsage[maxIdx] << 10)
                    totalsize = convSize2Unit(long(sum(wrUsage)) << 10)
                    maxval = '%s%s[%s]' % (prefix, idx, maxsize)
                    lastval = '%s%s[%s]' % \
                        (prefix, convSize2Unit(wrUsage[-1] << 10), idx)

                    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, fontsize=3, color=color,
                                fontweight='normal', rotation=35,
                                ha=_getTextAlign(maxIdx, timeline))
                        if wrUsage[-1] > 0:
                            text(timeline[-1], wrUsage[-1] + margin,
                                lastval, fontsize=3, 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 = convSize2Unit(rdUsage[maxIdx] << 10)
                    totalsize = convSize2Unit(long(sum(rdUsage)) << 10)
                    maxval = '%s%s[%s]' % (prefix, idx, maxsize)
                    lastval = '%s%s[%s]' % \
                        (prefix, convSize2Unit(rdUsage[-1] << 10), idx)

                    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, fontsize=3, color=color,
                                fontweight='normal', rotation=35,
                                ha=_getTextAlign(maxIdx, timeline))
                        if rdUsage[-1] > 0:
                            text(timeline[-1], rdUsage[-1] + margin,
                                lastval, fontsize=3, 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=4)
            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 = \
                    [convSize2Unit(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):
                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' % \
                    (prefix, convSize2Unit(usage[minIdx] << 20))
                maxsize = convSize2Unit(usage[maxIdx] << 20)
                maxval = '%s%s' % (prefix, maxsize)
                lastsize = convSize2Unit(usage[-1] << 20)
                lastval = '%s%s' % (prefix, lastsize)

                # set color #
                if len(prefix) > 0:
                    fcolor = None
                else:
                    fcolor = color

                line = plot(timeline, usage, '-', c=fcolor,
                    linewidth=0.7, solid_capstyle='round')

                color = line[0].get_color()

                if usage[minIdx] > 0:
                    text(timeline[minIdx], usage[minIdx], minval,
                        fontsize=3, color=color, fontweight='bold',
                        ha=_getTextAlign(minIdx, timeline))
                if usage[minIdx] != usage[maxIdx] and usage[maxIdx] > 0:
                    text(timeline[maxIdx], usage[maxIdx], maxval,
                        fontsize=3, color=color, fontweight='bold',
                        ha=_getTextAlign(maxIdx, timeline))
                if usage[-1] > 0:
                    text(timeline[-1], usage[-1], lastval,
                        fontsize=3, color=color, fontweight='bold',
                        ha='right')

                return lastsize, ymax

            # define common label list #
            ymax = long(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)

            # 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 #
            if SysMgr.nrTop:
                tcnt = long(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]
                memFree = graphStats['%smemFree' % fname][:lent]
                memAnon = graphStats['%smemAnon' % fname][:lent]
                memCache = graphStats['%smemCache' % fname][:lent]
                memProcUsage = graphStats['%smemProcUsage' % fname]
                totalSwap = graphStats['%stotalSwap' % fname]
                swapUsage = graphStats['%sswapUsage' % fname][:lent]

                # get margin #
                margin = self.getMargin()

                # Process VSS #
                if SysMgr.vssEnable:
                    for key, item in sorted(memProcUsage.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

                        try:
                            minIdx = usage.index(min(usage))
                        except:
                            minIdx = long(0)
                        try:
                            maxIdx = usage.index(item['maxVss'])
                        except:
                            maxIdx = long(0)

                        key = '%s%s' % (prefix, key)
                        minval = '%s [%s]' % \
                            (key, convSize2Unit(usage[minIdx] << 20))
                        maxsize = convSize2Unit(usage[maxIdx] << 20)
                        maxval = '%s [%s]' % (key, maxsize)
                        lastval = '%s [%s]' % \
                            (key, convSize2Unit(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 color #
                        color = plot(timeline, usage, '-',
                            linewidth=0.7)[0].get_color()

                        if usage[minIdx]:
                            text(timeline[minIdx], usage[minIdx] + margin,
                                minval, color=color, fontsize=3, rotation=35,
                                ha=_getTextAlign(minIdx, timeline))
                        if usage[minIdx] != usage[maxIdx] and usage[maxIdx]:
                            text(timeline[maxIdx], usage[maxIdx] + margin,
                                maxval, color=color, fontsize=3, rotation=35,
                                ha=_getTextAlign(maxIdx, timeline))
                        if usage[-1]:
                            text(timeline[-1], usage[-1] + margin,
                                lastval, color=color, fontsize=3, rotation=35,
                                ha='right')

                        labelList.append(
                            '%s [VSS] - %s' % (key, maxsize))

                # Process Leak #
                elif SysMgr.leakEnable:
                    # get VSS diffs #
                    for key, item in sorted(memProcUsage.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 = long(0)

                        if maxVss == 0:
                            item['vssDiff'] = long(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'] = long(0)
                                continue
                        except:
                            pass

                        # get minimum value #
                        try:
                            minVss = min(x for x in usage if x != 0)
                        except:
                            minVss = long(0)

                        diff = maxVss - minVss
                        item['vssDiff'] = diff

                    # draw leakage plots #
                    for key, item in sorted(memProcUsage.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 = long(0)

                        # get maximum value #
                        try:
                            maxIdx = usage.index(item['maxVss'])
                        except:
                            maxIdx = long(0)

                        key = '%s%s' % (prefix, key)
                        minval = '%s [%s]' % \
                            (key, convSize2Unit(usage[minIdx] << 20))
                        diffsize = convSize2Unit(item['vssDiff'] << 20)
                        lastval = '%s [%s/+%s]' % \
                            (key, convSize2Unit(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 color #
                        color = plot(timeline, usage, '-',
                            linewidth=0.7)[0].get_color()

                        if usage[minIdx]:
                            text(timeline[minIdx], usage[minIdx] - margin,
                                minval, color=color, fontsize=3, rotation=35,
                                ha=_getTextAlign(minIdx, timeline))
                        if usage[minIdx] != usage[maxIdx] and usage[maxIdx]:
                            text(timeline[maxIdx], usage[maxIdx] + margin,
                                lastval, color=color, fontsize=3, rotation=35,
                                ha=_getTextAlign(maxIdx, timeline))

                        labelList.append('%s [LEAK] - %s' % (key, diffsize))

                # Process RSS #
                elif SysMgr.rssEnable or \
                    SysMgr.pssEnable or \
                    SysMgr.ussEnable:
                    for key, item in sorted(memProcUsage.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

                        try:
                            minIdx = usage.index(min(usage))
                        except SystemExit:
                            sys.exit(0)
                        except:
                            minIdx = long(0)

                        try:
                            maxIdx = usage.index(item['maxRss'])
                        except SystemExit:
                            sys.exit(0)
                        except:
                            maxIdx = long(0)

                        key = '%s%s' % (prefix, key)
                        minval = '%s [%s]' % \
                            (key, convSize2Unit(usage[minIdx] << 20))
                        maxsize = convSize2Unit(usage[maxIdx] << 20)
                        maxval = '%s [%s]' % (key, maxsize)
                        lastsize = convSize2Unit(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 color #
                        color = plot(timeline, usage, '-',
                            linewidth=0.7)[0].get_color()

                        if usage[minIdx]:
                            text(timeline[minIdx], usage[minIdx] + margin,
                                minval, color=color, fontsize=3, rotation=35,
                                ha=_getTextAlign(minIdx, timeline))
                        if usage[minIdx] != usage[maxIdx] and usage[maxIdx]:
                            text(timeline[maxIdx], usage[maxIdx] + margin,
                                maxval, color=color, fontsize=3, rotation=35,
                                ha=_getTextAlign(maxIdx, timeline))
                        if usage[-1]:
                            text(timeline[-1], usage[-1] + margin,
                                lastval, color=color, fontsize=3, 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:
                    # System Free Memory #
                    lastsize, ymax = _drawSystemMem(memFree, 'blue', ymax)
                    if lastsize is not None:
                        if totalRam:
                            label = \
                                '%s[ RAM Total ] - %s\nRAM Available - %s' % \
                                    (prefix, convSize2Unit(totalRam), lastsize)
                            labelList.append(label)
                        else:
                            labelList.append(
                                '%sRAM Available - %s' % (prefix, lastsize))

                    # System Anon Memory #
                    lastsize, ymax = _drawSystemMem(memAnon, 'skyblue', ymax)
                    if lastsize is not None:
                        labelList.append(
                            '%sRAM User - %s' % (prefix, lastsize))

                    # System Cache Memory #
                    lastsize, ymax = _drawSystemMem(memCache, 'darkgray', ymax)
                    if lastsize is not None:
                        labelList.append(
                            '%sRAM Cache - %s' % (prefix, lastsize))

                    # System Swap Memory #
                    lastsize, ymax = _drawSystemMem(swapUsage, 'orange', ymax)
                    if lastsize is not None:
                        if totalSwap:
                            label = \
                                '%s[ Swap Total ] - %s\nSwap Usage - %s' % \
                                (prefix, convSize2Unit(totalSwap), lastsize)
                            labelList.append(label)
                        else:
                            labelList.append(
                                '%sSwap Usage - %s' % (prefix, 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()

            # set ymin #
            ymin = long(min(ylist))
            if ymin < 0:
                ymin = long(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 = \
                    [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

                ax.set_yticklabels(ytickLabel)
            except SystemExit:
                sys.exit(0)
            except:
                pass

            xticks(fontsize=4)
            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(
                "fail 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 = long(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 _convNameLabel(fileList):
            newList = []
            for idx, name in enumerate(fileList):
                if idx % 2 == 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 = long(0)
            labelList = []

            # create new timeline #
            timeline = range(0, 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')

            #-------------------- 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=1, marker='d', markersize=1,
                        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=4, 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=1, marker='d', markersize=1,
                        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=4, 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=1, marker='d', markersize=1,
                    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=4, 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=1, marker='d', markersize=1,
                    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=4, color='green', fontweight='bold',
                        bbox=dict(boxstyle='round', facecolor='wheat',
                        alpha=0.3),
                        ha=_getTextAlign(idx, timeline))

            # define top variable #
            if SysMgr.nrTop:
                tcnt = long(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

                maxIdx = usage.index(maxusage)
                color = plot(timeline, usage, '-')[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=4, 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=4)
            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

                plot(timeline, usage, '-', c=color,
                    linewidth=1, 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=4,
                        ha=_getTextAlign(maxIdx, timeline))

                return usage[-1], ymax

            # define common label list #
            ymax = long(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 #
            if SysMgr.nrTop:
                tcnt = long(0)

            # create new timeline #
            timeline = range(0, len(graphStats['timeline']))
            lent = len(timeline)

            totalRam = graphStats['totalRam']
            memFree = graphStats['memFree']
            memAnon = graphStats['memAnon']
            memCache = graphStats['memCache']
            memProcUsage = graphStats['memProcUsage']
            totalSwap = graphStats['totalSwap']
            swapUsage = graphStats['swapUsage']

            # get margin #
            margin = self.getMargin()

            # Process VSS #
            if SysMgr.vssEnable:
                for key, item in sorted(memProcUsage.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 color #
                    color = \
                        plot(timeline, usage, '-', linewidth=1)[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=4,
                            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(memProcUsage.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 color #
                    color = \
                        plot(timeline, usage, '-', linewidth=1)[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=4,
                            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=4)
            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(outputFile, dpi=SysMgr.matplotlibDpi) # pylint: disable=undefined-variable
            clf() # pylint: disable=undefined-variable

            # get output size #
            fsize = UtilMgr.getFileSize(outputFile)
            if fsize and fsize != '0':
                fsize = ' [%s]' % fsize
            else:
                fsize = ''

            SysMgr.printStat(
                "wrote resource %s into '%s'%s" %
                    (itype, outputFile, fsize))
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "fail 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.keys()):
                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):
        convertNum = 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: <>] [WaitForChilds: {}] '
                '[WaitOfParent: []]'))
            SysMgr.printPipe(twoLine)

            cnt = long(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})".\
                format('TYPE', 'TIME', 'SENDER',
                'TID', 'SIGNAL', 'RECEIVER', 'TID'))
            SysMgr.printPipe(twoLine)

            cnt = long(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 = long(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 len(self.wqData) > 0:
            totalCnt = long(0)
            totalUsage = float(0)

            SysMgr.printPipe((
                '\n[Thread Workqueue Info] [Elapsed: %.3f] '
                '(Unit: Sec/NR)') % float(self.totalTime))
            SysMgr.printPipe(twoLine)
            SysMgr.printPipe((
                "{0:^32} {1:>12} {2:>10} {3:>10} "
                "{4:>10} {5:>10} {6:>10} {7:>10} {8:>6}").\
                format("Name", "Count", "Usage", "ProcAvg", "ProcMax",
                "ProcMin", "InterMax", "InterMin", "NrTask"))
            SysMgr.printPipe(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.keys()):
                    if item[key] == -1:
                        item[key] = 0

                if not name in wqData:
                    wqData[name] = deepcopy(item)
                    continue

                target = wqData[name]

                # change default stat value -1 to 0 #
                for key in list(target.keys()):
                    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 = convertNum(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'], convertNum(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" % \
                    ('', convertNum(len(wqData)),
                    totalUsage, convertNum(totalCnt)))
            SysMgr.doPrint()
            SysMgr.printPipe(oneLine)

        # print interrupt information #
        if len(self.irqData) > 0:
            totalCnt = long(0)
            totalUsage = float(0)

            SysMgr.printPipe((
                '\n[Thread IRQ Info] [Elapsed: %.3f] '
                '(Unit: Sec/NR)') % float(self.totalTime))
            SysMgr.printPipe(twoLine)
            SysMgr.printPipe((
                "{0:^16} {1:<62} {2:>12} {3:>10} {4:>10} "
                "{5:>10} {6:>10} {7:>10}").\
                format("IRQ", "Name", "Count", "Usage", "ProcMax",
                "ProcMin", "InterMax", "InterMin"))
            SysMgr.printPipe(twoLine)

            SysMgr.clearPrint()

            # print irq list #
            irqList = [irq for irq in list(self.irqData.keys()) \
                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'].keys())),
                    convertNum(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.keys()) \
                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'].keys())),
                    convertNum(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" % \
                    ('', convertNum(len(self.irqData)),
                    totalUsage, convertNum(totalCnt)))
            SysMgr.doPrint()
            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 len(self.customEventInfo) > 0:
            SysMgr.clearPrint()
            SysMgr.printPipe('\n[Thread CUSTOM Event Info]')
            SysMgr.printPipe(twoLine)
            SysMgr.printPipe(
                "{0:^32} {1:>16}({2:>6}) {3:>10} {4:>10} {5:>10}".\
                format('Event', 'COMM', 'TID', 'Count',
                'MaxPeriod', 'MinPeriod'))
            SysMgr.printPipe(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:>16}({2:>6}) {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:>16}({2:>6}) {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]')
            SysMgr.printPipe(twoLine)
            SysMgr.printPipe(
                "{0:^32} {1:^10} {2:>16}({3:>6}) {4:<1}".\
                format('EVENT', 'TIME', 'COMM', 'TID', 'ARG'))
            SysMgr.printPipe(twoLine)

            cnt = long(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:>6}) {4:<1}".\
                    format(val[0], val[3], val[1], val[2], val[4]))
            if cnt == 0:
                SysMgr.printPipe("\tNone")
            SysMgr.printPipe(oneLine)

        # print user event info #
        if len(self.userEventInfo) > 0:
            SysMgr.clearPrint()
            SysMgr.printPipe('\n[Thread User Event Info]')
            SysMgr.printPipe(twoLine)
            SysMgr.printPipe((
                "{0:^32} {1:>16}({2:>6}) {3:>10} {4:>10} "
                "{5:>10} {6:>10} {7:>10} {8:>10}").\
                format('Event', 'COMM', 'TID', 'Usage', 'Count',
                'ProcMax', 'ProcMin', 'InterMax', 'InterMin'))
            SysMgr.printPipe(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:>6}) {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:>6}) {3:>10.6f} {4:>10} "
                        "{5:>10.6f} {6:>10.6f} {7:>10.6f} {8:>10.6f}").\
                        format(' ', self.threadData[key]['comm'], 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]')
            SysMgr.printPipe(twoLine)
            SysMgr.printPipe(
                "{0:^32} {1:>6} {2:^10} {3:>16}({4:>6}) {5:^16} {6:>10}".\
                format('EVENT', 'TYPE', 'TIME', 'COMM', 'TID',
                    'CALLER', 'ELAPSED'))
            SysMgr.printPipe(twoLine)

            cnt = long(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:>6}) "
                    "{5:>16} {6:>10}").\
                    format(val[1], val[0], val[4], val[2],
                    val[3], val[5], elapsed))
            if cnt == 0:
                SysMgr.printPipe("\tNone")
            SysMgr.printPipe(oneLine)

        # print kernel event info #
        if len(self.kernelEventInfo) > 0:
            SysMgr.clearPrint()
            SysMgr.printPipe('\n[Thread Kernel Event Info]')
            SysMgr.printPipe(twoLine)
            SysMgr.printPipe((
                "{0:^32} {1:>16}({2:>6}) {3:>10} {4:>10} "
                "{5:>10} {6:>10} {7:>10} {8:>10}").\
                format('Event', 'COMM', 'TID', 'Usage', 'Count', 'ProcMax',
                'ProcMin', 'InterMax', 'InterMin'))
            SysMgr.printPipe(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:>6}) {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:>6}) {3:>10.6f} {4:>10} "
                        "{5:>10.6f} {6:>10.6f} {7:>10.6f} {8:>10.6f}").\
                        format(' ', self.threadData[key]['comm'], 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]')
        SysMgr.printPipe(twoLine)
        SysMgr.printPipe((
            "{0:^32} {1:>6} {2:^10} {3:>16}({4:>6}) "
            "{5:^22} {6:>10} {7:<1}").\
            format('EVENT', 'TYPE', 'TIME', 'COMM',
            'TID', 'CALLER', 'ELAPSED', 'ARG'))
        SysMgr.printPipe(twoLine)

        cnt = long(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:>6}) "
                "{5:>22} {6:>10} {7:<1}").\
                format(val[1], val[0], val[5], val[3],
                val[4], val[6], elapsed, args))
        if cnt == 0:
            SysMgr.printPipe("\tNone")
        SysMgr.printPipe(oneLine)



    def addSysInterval(self, key, value):
        if not SysMgr.maxInterval:
            return

        self.intervalData.setdefault(key, list())
        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, pid, target, key, value):
        if not SysMgr.maxInterval:
            return

        try:
            target.setdefault(key, self.prevProcData[pid][key])
        except:
            target.setdefault(key, list())

        target[key].append(value)
        mod = len(target[key]) - SysMgr.maxInterval
        if mod > 0:
            target[key] = target[key][mod:]



    def printUsage(self):
        # print thread usage #
        self.printResourceUsage()

        # print communication usage #
        self.printComInfo()

        # print event usage #
        self.printEventInfo()

        # print page info #
        self.printPageInfo()

        # print block usage #
        self.printBlockInfo()

        # print resource usage of threads on timeline #
        self.printIntervalInfo()

        # print kernel module info #
        self.printModuleInfo()

        # print dependency of threads #
        self.printDepInfo()

        # print futex and flock of threads #
        self.printFutexInfo()
        self.printFlockInfo()

        # print syscall usage #
        self.printSyscallInfo()

        # print kernel messages #
        self.printConsoleInfo()



    def printResourceUsage(self):
        # pylint: disable=undefined-variable

        title = 'Thread Info'

        SysMgr.printLogo(big=True)

        # print system information #
        SysMgr.printInfoBuffer()

        convertFunc = UtilMgr.convSize2Unit
        convertNum = 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)") % \
            (title, 'Elapsed', round(float(self.totalTime), 7),
            'Start', round(float(SysMgr.startTime), 7),
            convertNum(self.getRunTaskNum()),
            convertNum(self.cxtSwitch),
            convertFunc(SysMgr.logSize)))
        SysMgr.printPipe(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(""))

        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|") % \
            ('Name', 'TID', 'PID', 'LF', 'Usage', '%', 'Prmt', 'Latc', 'Pri',
            'IRQ', 'Yld', ' Lose', 'Steal', 'Mig',
            'Read', 'MB', 'Cnt', 'Write', 'MB',
            'Sum', 'Usr', 'Buf', 'Ker', lastBField))
        SysMgr.printPipe(twoLine)

        # initialize swapper thread per core #
        for n in range(0, 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'] = long(0)

        # sort by size of io 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 = long(0)
        SysMgr.clearPrint()
        for key, value in sorted(self.threadData.items(),
            key=lambda e: TaskAnalyzer.getCoreId(e[1]['comm']),
            reverse=False):

            if key[0:2] != '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 = long(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 precise:
                    schedLatency = '%5.6f' % value['schedLatency']
                else:
                    schedLatency = '%5.2f' % value['schedLatency']

                yieldCnt = '%5s' % convertFunc(value['yield'])
                preemptedCnt = '%5s' % convertFunc(value['preempted'])
                preemptionCnt = '%5s' % convertFunc(value['preemption'])
                migrateCnt = '%4s' % convertFunc(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)

        # 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 = long(0)
        totalPrtTime = long(0)
        totalSchedLatency = long(0)
        totalYieldCnt = long(0)
        totalPreemptedCnt = long(0)
        totalPreemptionCnt = long(0)
        totalMigrateCnt = long(0)

        # set total irq variables #
        totalIrqTime = long(0)

        # set total io variables #
        totalIoRdWait = long(0)
        totalReadBlock = long(0)
        totalReadBlockCnt = long(0)
        totalIoWrWait = long(0)
        totalWriteBlock = long(0)

        # set total mem variables #
        totalUsedMem = long(0)
        totalUserMem = long(0)
        totalCacheMem = long(0)
        totalKernelMem = long(0)
        totalReclaimedMem = long(0)
        totalWastedMem = long(0)
        totalDreclaimedTime = long(0)
        totalDreclaimedCnt = long(0)

        # define variables for tasks #
        normCnt = long(0)
        newCnt = long(0)
        dieCnt = long(0)
        normThreadString = ''
        newThreadString = ''
        dieThreadString = ''

        # print thread information after sorting by time of CPU usage #
        count = long(0)
        SysMgr.clearPrint()
        for key, value in sortedThreadData:
            if key[0:2] == '0[':
                continue

            try:
                usagePercent = \
                    round(value['usage'] / float(self.totalTime), 7) * 100
            except:
                usagePercent = long(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 precise:
                    prtTime = '%5.6f' % value['cpuWait']
                else:
                    prtTime = '%5.2f' % value['cpuWait']
                totalPrtTime += value['cpuWait']

                if precise:
                    schedLatency = '%5.6f' % value['schedLatency']
                else:
                    schedLatency = '%5.2f' % value['schedLatency']
                totalSchedLatency += value['schedLatency']

                pri = value['pri']

                yieldCnt = '%5s' % convertFunc(value['yield'])
                totalYieldCnt += value['yield']

                preemptedCnt = '%5s' % convertFunc(value['preempted'])
                totalPreemptedCnt += value['preempted']

                preemptionCnt = '%5s' % convertFunc(value['preemption'])
                totalPreemptionCnt += value['preemption']

                migrateCnt = '%4s' % convertFunc(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']])
                elif key == value['tgid']:
                    lastField = "{0:>16}".format(value['comm'])
                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' % convertFunc(totalYieldCnt)
            totalPreemptedCnt = '%5s' % convertFunc(totalPreemptedCnt)
            totalPreemptionCnt = '%5s' % convertFunc(totalPreemptionCnt)
            totalMigrateCnt = '%4s' % convertFunc(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: %d\n%s\n%s" % \
                    ('', 'Hot', normCnt, normThreadString, oneLine))
        else:
            SysMgr.printPipe("\tNone\n%s" % oneLine)

        # print new thread info #
        if newCnt > 0:
            SysMgr.printPipe(
                "%s# %s: %d\n%s\n%s" % \
                    ('', 'New', newCnt, newThreadString, oneLine))

        # print die thread info #
        if dieCnt > 0:
            SysMgr.printPipe(
                "%s# %s: %d\n%s\n%s" % \
                    ('', 'Die', 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 = long(0)

            tid = SysMgr.preemptGroup[index]
            try:
                self.threadData[tid]
            except:
                SysMgr.printErr('fail 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.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)))
                else:
                    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)))

            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 latency stats for preemption #
        if 'schedlat' in self.statData:
            latStats = UtilMgr.convList2Histo(
                self.statData['schedlat'], mult=1000000)
            UtilMgr.printHist(latStats, 'sched_latency', '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(0)
            from matplotlib.ticker import MaxNLocator

            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': float(0), 'loadCnt': long(0),
            'elapsed': float(0), 'freeCnt': long(0), 'refCnt': long(0),
            'getCnt': long(0), 'putCnt': long(0)}

        # print module history #
        SysMgr.clearPrint()
        SysMgr.addPrint('\n[Thread Module History]\n')
        SysMgr.addPrint('%s\n' % twoLine)
        SysMgr.addPrint(
            "{3:>16} ({4:^6})|{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 = long(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:>5})|{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'] = long(0)
                refCnt = moduleTable[module]['refCnt']

                SysMgr.addPrint(
                    "{3:>16} ({4:>5})|{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:>5})|{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'] = long(0)
                    elapsed = '%.6f' % elapsed
                else:
                    elapsed = ''

                SysMgr.addPrint(
                    "{3:>16} ({4:>5})|{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]')
        SysMgr.printPipe(twoLine)
        SysMgr.printPipe(
            "{0:^32}|{1:^10}|{2:^12}|{3:^10}|{4:^10}|{5:^10}|".\
            format("Module", "LoadCnt", "LoadTime",
            "FreeCnt", "GetCnt", "PutCnt"))
        SysMgr.printPipe(twoLine)

        printCnt = long(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()



    def printDepInfo(self):
        if not SysMgr.depEnable:
            return

        SysMgr.printPipe('\n[Thread Dependency Info]')
        SysMgr.printPipe(twoLine)
        SysMgr.printPipe(
            "\t%5s/%4s \t%32s(%7s) -> %32s(%7s) \t%5s" % \
            ("Total", "Inter", "From", "TID", "To", "TID", "Event"))
        SysMgr.printPipe(twoLine)
        SysMgr.printPipe(
            "%s# %s: %d\n" % ('', 'Dep', len(self.depData)))

        for icount in range(0, len(self.depData)):
            SysMgr.addPrint(self.depData[icount] + '\n')

        SysMgr.doPrint()
        SysMgr.printPipe(oneLine)



    def printFutexInfo(self):
        SysMgr.clearPrint()

        if not self.futexData:
            return

        convertNum = UtilMgr.convNum

        outputCnt = long(0)
        SysMgr.printPipe(
            '\n[Thread Futex Lock Info] [Elapsed: %.3f] (Unit: Sec/NR)' % \
                float(self.totalTime))
        SysMgr.printPipe(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}').\
            format('Name', 'TID', 'PID', 'Elapsed', 'Process', 'Block',
            'NrBlock', 'CallMax', 'Lock', 'LockMax', 'NrLock', 'NrWait',
            'LBlock', 'NrLBlock', 'LastStat'))
        SysMgr.printPipe(twoLine)

        totalInfo = {'ftxTotal': long(0), 'ftxMax': long(0),
            'ftxLock': long(0), 'ftxLockMax': long(0), 'ftxLockCnt': long(0),
            'ftxWaitCnt': long(0), 'ftxProcess': long(0),
            'ftxBlockTotal': long(0), 'ftxLBlockTotal': long(0),
            'ftxBlockCnt': long(0), 'ftxLSwitch': long(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[0:2] == '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 = convertNum(value['ftxLockCnt'])
            ftxWaitCall = convertNum(value['ftxWaitCnt'])

            # set total info #
            totalInfo['ftxTotal'] += value['ftxTotal']
            totalInfo['ftxLock'] += value['ftxLock']
            totalInfo['ftxLockCnt'] += value['ftxLockCnt']
            totalInfo['ftxWaitCnt'] += value['ftxWaitCnt']
            if totalInfo['ftxMax'] == 0 or \
                totalInfo['ftxMax'] < value['ftxMax']:
                totalInfo['ftxMax'] = value['ftxMax']
            if totalInfo['ftxLockMax'] == 0 or \
                totalInfo['ftxLockMax'] < value['ftxLockMax']:
                totalInfo['ftxLockMax'] = value['ftxLockMax']

            if SysMgr.cpuEnable:
                ftxProcess = '%.3f' % float(value['ftxProcess'])
                ftxBlock = '%.3f' % float(value['ftxBlockTotal'])
                ftxLBlock = '%.3f' % float(value['ftxLBlockTotal'])
                ftxBlockCall = convertNum(value['ftxBlockCnt'])
                ftxLSwitch = value['ftxLSwitch']

                totalInfo['ftxProcess'] += value['ftxProcess']
                totalInfo['ftxBlockTotal'] += value['ftxBlockTotal']
                totalInfo['ftxLBlockTotal'] += value['ftxLBlockTotal']
                totalInfo['ftxBlockCnt'] += value['ftxBlockCnt']
                totalInfo['ftxLSwitch'] += value['ftxLSwitch']
            else:
                ftxProcess = totalInfo['ftxProcess'] = '-'
                ftxBlock = totalInfo['ftxBlockTotal'] = '-'
                ftxLBlock = totalInfo['ftxLBlockTotal'] = '-'
                ftxBlockCall = totalInfo['ftxBlockCnt'] = '-'
                ftxLSwitch = totalInfo['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, ftxLock, ftxLockMax, ftxLockCall,
                ftxWaitCall, ftxLBlock, ftxLSwitch, status)

            SysMgr.addPrint('%s\n%s\n' % (futexInfo, oneLine))
            outputCnt += 1

        if outputCnt == 0:
            SysMgr.printPipe('\tNone\n%s' % oneLine)
        else:
            # print total info #
            totalInfo['ftxTotal'] = '%.3f' % totalInfo['ftxTotal']
            totalInfo['ftxMax'] = '%.3f' % totalInfo['ftxMax']
            totalInfo['ftxLock'] = '%.3f' % totalInfo['ftxLock']
            totalInfo['ftxLockMax'] = '%.3f' % totalInfo['ftxLockMax']
            totalInfo['ftxLockCnt'] = convertNum(totalInfo['ftxLockCnt'])
            totalInfo['ftxWaitCnt'] = convertNum(totalInfo['ftxWaitCnt'])

            if totalInfo['ftxProcess'] != '-':
                totalInfo['ftxProcess'] = '%.3f' % totalInfo['ftxProcess']
            if totalInfo['ftxBlockTotal'] != '-':
                totalInfo['ftxBlockTotal'] = '%.3f' % totalInfo['ftxBlockTotal']
            if totalInfo['ftxLBlockTotal'] != '-':
                totalInfo['ftxLBlockTotal'] = '%.3f' % totalInfo['ftxLBlockTotal']
            if totalInfo['ftxBlockCnt'] != '-':
                totalInfo['ftxBlockCnt'] = convertNum(totalInfo['ftxBlockCnt'])
            if totalInfo['ftxLSwitch'] != '-':
                totalInfo['ftxLSwitch'] = convertNum(totalInfo['ftxLSwitch'])

            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 ]',
                totalInfo['ftxTotal'], totalInfo['ftxProcess'],
                totalInfo['ftxBlockTotal'], totalInfo['ftxBlockCnt'],
                totalInfo['ftxMax'], totalInfo['ftxLock'],
                totalInfo['ftxLockMax'], totalInfo['ftxLockCnt'],
                totalInfo['ftxWaitCnt'], totalInfo['ftxLBlockTotal'],
                totalInfo['ftxLSwitch'], '-')

            SysMgr.printPipe('%s\n%s' % (totalFutexInfo, oneLine))

            # print thread info #
            SysMgr.doPrint()
            SysMgr.clearPrint()

        if not SysMgr.showAll:
            return

        SysMgr.printPipe(
            '\n[Thread Futex Lock History] (Unit: Sec/NR)')
        SysMgr.printPipe(twoLine)
        SysMgr.printPipe((
            "{0:>12} {1:>16}{2:>17} {3:>4} {4:^24} " + \
            "{5:^10} {6:>12} {7:>16} {8:>16} {9:>16}").\
            format("Time", "Name", "(  Tid/  Pid)", "Core", "Operation",
             "Type", "Elapsed", "Target", "Value", "Timer"))
        SysMgr.printPipe(twoLine)

        cnt = long(0)
        for icount in range(0, len(self.futexData)):
            try:
                value = self.futexData[icount]

                if value[1] == -1:
                    continue

                atime = float(value[1])
                time = '%.6f' % (atime - float(SysMgr.startTime))

                comm = self.threadData[value[0]]['comm']
                tid = '(%6s/%6s)' % \
                    (value[0], self.threadData[value[0]]['tgid'])
                core = value[2]

                try:
                    if icount > 0:
                        if self.futexData[icount-1][2] == value[2]:
                            core = ''

                        if self.futexData[icount-1][0] == value[0]:
                            tid = comm = ''
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

                if icount + 1 <= len(self.futexData) and \
                    self.futexData[icount+1][0] == value[0] and \
                    self.futexData[icount][4].startswith('ENT') and \
                    self.futexData[icount+1][4].endswith('RET'):
                    otype = '{0:^10}'.format('ALL')
                    elapsed = self.futexData[icount+1][5]
                    self.futexData[icount+1][1] = -1
                else:
                    otype = value[4]
                    elapsed = value[5]

                # convert error code #
                ret = long(value[7])
                if ret < 0:
                    try:
                        ret = '%s' % ConfigMgr.ERR_TYPE[abs(ret+1)]
                    except:
                        pass

                SysMgr.printPipe((
                    "{0:>12} {1:>16}{2:>17} {3:>4} {4:<24} " + \
                    "{5:>10} {6:>12} {7:>16} {8:>16} {9:>16}").\
                    format(time, comm, tid, core, value[3],
                    otype, elapsed, value[6], ret, value[8]))

                cnt += 1
            except:
                pass
        if cnt == 0:
            SysMgr.printPipe("\tNone")
        SysMgr.printPipe(oneLine)



    def printFlockInfo(self):
        SysMgr.clearPrint()

        if not self.flockData:
            return

        outputCnt = long(0)
        SysMgr.printPipe('\n[Thread File Lock Info] (Unit: Sec/NR)')
        SysMgr.printPipe(twoLine)
        SysMgr.printPipe(
            '{0:>16}({1:>6})\t{2:>12}\t{3:>12}\t{4:>10}\t{5:>10}'.format(
            'Name', 'TID', 'Wait', 'Lock', 'nrTryLock', 'nrLocked'))
        SysMgr.printPipe(twoLine)

        for key, value in sorted(self.threadData.items(),
            key=lambda e: e[1]['lockWait'], reverse=True):

            if key[0:2] == '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)')
        SysMgr.printPipe(twoLine)
        SysMgr.printPipe(
            "{0:>16}({1:>6}) {2:>10} {3:>4} {4:>10} {5:>16} {6:>16} {7:>20}"\
            .format("Name", "TID", "Time", "Core",
            "Type", "Device", "Inode", "Context"))
        SysMgr.printPipe(twoLine)

        cnt = long(0)
        for icount in range(0, len(self.flockData)):
            try:
                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 icount > 0 and \
                    self.flockData[icount-1][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]))
                cnt += 1
            except:
                continue
        if cnt == 0:
            SysMgr.printPipe("\tNone")
        SysMgr.printPipe(oneLine)



    def printSyscallInfo(self):
        if not self.syscallData:
            return

        convertNum = UtilMgr.convNum

        outputCnt = long(0)
        SysMgr.printPipe(
            '\n[Thread Syscall Info] [Elapsed: %.3f] (Unit: Sec/NR)' % \
                float(self.totalTime))
        SysMgr.printPipe(twoLine)
        SysMgr.printPipe((
            '{0:>16}({1:>7}) {2:>30}({3:>3}) {4:>12} {5:>12} '
            '{6:>12} {7:>12} {8:>12} {9:>12}').format(
            "Name", "TID", "Syscall", "SID", "Elapsed", "Count",
            "Error", "Min", "Max", "Avg"))
        SysMgr.printPipe(twoLine)

        totalInfo = dict()

        for key, value in sorted(self.threadData.items(),
            key=lambda e: e[1]['nrSyscall'], reverse=True):

            threadInfo = ''
            syscallInfo = ''

            # skip swapper #
            if key[0:2] == '0[':
                continue

            try:
                if len(value['syscallInfo']) > 0:
                    threadInfo = "%16s(%7s)" % (value['comm'], key)
                else:
                    continue
            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(
                        '%s%s' % (syscallInfo, ' ' * len(threadInfo)),
                        syscall, sysId, '%.6f' % val['usage'],
                        convertNum(val['count']), convertNum(val['err']),
                        '%.6f' % val['min'], '%.6f' % val['max'],
                        val['average'])
                except:
                    pass

                # add total info #
                try:
                    if not sysId in totalInfo:
                        totalInfo[sysId] = dict()
                        totalInfo[sysId]['usage'] = long(0)
                        totalInfo[sysId]['count'] = long(0)
                        totalInfo[sysId]['err'] = long(0)
                        totalInfo[sysId]['min'] = long(0)
                        totalInfo[sysId]['max'] = long(0)
                        totalInfo[sysId]['average'] = long(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:
                    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'], convertNum(val['count']),
                    convertNum(val['err']), '%.6f' % val['min'],
                    '%.6f' % val['max'], '%.6f' % val['average'])

                SysMgr.printPipe(syscallInfo)
            SysMgr.printPipe('\n%s' % oneLine)

            # print thread info #
            SysMgr.doPrint()
            SysMgr.clearPrint()

        if not SysMgr.showAll:
            return

        SysMgr.printPipe('\n[Thread Syscall History] (Unit: Sec/NR)')
        SysMgr.printPipe(twoLine)
        SysMgr.printPipe((
            "{0:>10} {1:>16}({2:>7}) {3:>4} {4:>18} {5:>3} "
            "{6:>5} {7:>10} {8:>16} {9:<1}").format(
            "Time", "Name", "TID", "Core", "Syscall",
            "SID", "Type", "Elapsed", "Return", "Arguments"))
        SysMgr.printPipe(twoLine)

        # remove calls of unavailable threads #
        for icount in range(0, len(self.syscallData)):
            try:
                self.threadData[self.syscallData[icount][2]]
            except:
                try:
                    del self.syscallData[icount]
                except:
                    break

        cnt = long(0)
        proto = ConfigMgr.SYSCALL_PROTOTYPES
        startTime = float(SysMgr.startTime)
        for icount in range(0, len(self.syscallData)):
            try:
                prevData = self.syscallData[icount-1]
                nowData = self.syscallData[icount]

                if nowData[1] == -1:
                    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(
                        'fail to recognize syscall %s for %s number' % \
                            (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(
                            "fail to analyze syscall info", True, reason=True)

                elif nowData[0] == 'RET':
                    eventType = nowData[0]
                    eventTime = float(nowData[1]) - startTime
                    param = ' '
                    ret = nowData[5]

                    try:
                        elapsed = '%6.6f' % nowData[6]
                    except:
                        elapsed = ' ' * 8

                try:
                    # convert error code #
                    nrRet = long(ret)
                    if nrRet < 0:
                        ret = ConfigMgr.ERR_TYPE[abs(nrRet) - 1]
                except:
                    pass

                if icount > 0 and prevData[2] == nowData[2]:
                    tid = comm = ''
                else:
                    comm = self.threadData[nowData[2]]['comm']
                    tid = '(%7s)' % nowData[2]

                if icount > 0 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))

                cnt += 1
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    "fail to analyze syscall info", True)

        if cnt == 0:
            SysMgr.printPipe("\tNone")
        SysMgr.printPipe(oneLine)



    def printConsoleInfo(self):
        if not self.consoleData or not SysMgr.showAll:
            return

        SysMgr.printPipe('\n[Thread Message Info]')
        SysMgr.printPipe(twoLine)
        SysMgr.printPipe(
            "%16s %7s %4s %10s %30s" % \
            ('Name', 'TID', 'Core', 'Time', 'Console message'))
        SysMgr.printPipe(twoLine)

        startTime = float(SysMgr.startTime)

        cnt = long(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.keys()))
        orders = ' '.join(['{0:>5}'.format(
            UtilMgr.convNum(order)) for order in orderTable])
        SysMgr.printPipe(
            '\n[Thread Page Info] (Unit: Order)')
        SysMgr.printPipe(twoLine)
        SysMgr.printPipe("{0:^25} {1:>1}".format('Thread', orders))
        SysMgr.printPipe(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):
            for num, val in sorted(
                data.items(), key=lambda e:e[1], reverse=True):
                if tcnt == 0:
                    pass
                else:
                    cid = ' '

                try:
                    mountInfo = SysMgr.savedMountTree
                    dev = mountInfo[num]['dev']
                    filesystem = mountInfo[num]['filesystem']
                except SystemExit:
                    sys.exit(0)
                except:
                    dev = '?'
                    filesystem = '?'

                try:
                    seqPer = round((val[3] / float(val[0])) * 100, 1)
                except SystemExit:
                    sys.exit(0)
                except:
                    seqPer = '?'

                try:
                    size = format((val[0] >> 10), ',')
                except SystemExit:
                    sys.exit(0)
                except:
                    size = val[0] >> 10

                try:
                    seqSize = format((val[3] >> 10), ',')
                except SystemExit:
                    sys.exit(0)
                except:
                    seqSize = '?'

                seqString = '%s(%5s)' % (seqSize, seqPer)

                if tcnt > 0:
                    SysMgr.printPipe()

                SysMgr.printPipe(
                    "{0:>25} {1:>5} {2:>8} {3:>20} {4:>25} {5:^12} {6:<20}".\
                    format(cid, opt, num, size, seqString, filesystem, dev))

                opt = ''

                # print per-operation size statistics #
                for optSize, cnt in sorted(val[5].items()):
                    start = UtilMgr.convSize2Unit(optSize)
                    end = UtilMgr.convSize2Unit(optSize << 1)
                    SysMgr.printPipe(
                        "{0:^25} {0:^8} {0:^5} {1:>20} {2:>25} {0:^12} {0:<20}".\
                        format('', '[%7s - %7s]' % (start, end), cnt))

                tcnt += 1

            return tcnt


        # check block option #
        if not SysMgr.blockEnable:
            return

        SysMgr.printPipe('\n[Thread Block Info] (Unit: KB/NR)')
        SysMgr.printPipe(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}".\
            format('', '', '', '[ACCESS]', 'COUNT', '', ''))
        SysMgr.printPipe(twoLine)

        tcnt = long(0)
        totalStr = '{0:^25}'.format('TOTAL')

        # total read #
        if len(self.blockTable[0]) > 0:
            tcnt = _printBlkUsage(totalStr, self.blockTable[0], 'READ', tcnt)

        # total write #
        if len(self.blockTable[1]) > 0:
            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:sorted(e[1][0]), reverse=True):
            tcnt = long(0)
            comm = self.threadData[tid]['comm']
            cid = '%s(%s)' % (comm, tid)

            # thread read #
            if len(data[0]) > 0:
                tcnt = _printBlkUsage(cid, data[0], 'READ', tcnt)

            # thread write #
            if len(data[1]) > 0:
                tcnt = _printBlkUsage(cid, data[1], 'WRITE', tcnt)

            if tcnt > 0:
                SysMgr.printPipe(oneLine)



    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 range(0, 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()
                SysMgr.printPipe(oneLine)
                SysMgr.clearPrint()

        # 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 range(0, 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()
                SysMgr.printPipe(oneLine)
                SysMgr.clearPrint()

        # 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 range(0, 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()
                SysMgr.printPipe(oneLine)
                SysMgr.clearPrint()


    def printIntervalInfo(self):
        # pylint: disable=undefined-variable

        if SysMgr.intervalEnable <= 0 or \
            not (SysMgr.cpuEnable or \
            SysMgr.memEnable or \
            SysMgr.blockEnable):
            return

        intervalEnable = SysMgr.intervalEnable

        SysMgr.printPipe(
            '\n[Thread Interval Info] (Unit: %s Sec)' % intervalEnable)
        SysMgr.printPipe(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 range(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" % (titleLine, timeLine))
        SysMgr.printPipe(twoLine)
        SysMgr.clearPrint()

        # total CPU usage on timeline #
        for key, value in sorted(self.threadData.items(),
            key=lambda e: TaskAnalyzer.getCoreId(e[1]['comm']),
            reverse=False):

            if not SysMgr.cpuEnable:
                break

            if key[0:2] != '0[':
                continue

            timeLine = ''
            timeLineLen = titleLineLen
            lval = long(float(self.totalTime) / intervalEnable) + 1
            for icount in range(0, lval):
                try:
                    # revise core usage in DVFS system #
                    if self.threadData[key]['coreSchedCnt'] == 0 and \
                        self.threadData[key]['offCnt'] > 0:
                        raise Exception('core off')
                    else:
                        per = (100 - self.intData[icount][key]['cpuPer'])
                        timeLine += '%3d ' % per
                except:
                    timeLine += '%3s ' % '0'

                if timeLineLen + 4 >= maxLineLen:
                    timeLine += ('\n' + (' ' * (titleLineLen + 1)))
                    timeLineLen = titleLineLen + 4
                else:
                    timeLineLen += 4

            SysMgr.addPrint("%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)

        # total memory usage on timeline #
        timeLine = ''
        timeLineLen = titleLineLen
        lval = long(float(self.totalTime) / intervalEnable) + 1
        for icount in range(0, 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 = long(0)
            timeLine = ''
            timeLineLen = titleLineLen
            lval = long(float(self.totalTime) / intervalEnable) + 1
            for icount in range(0, 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 = long(0)
            timeLine = ''
            timeLineLen = titleLineLen
            lval = long(float(self.totalTime) / intervalEnable) + 1
            for icount in range(0, 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
            lval = long(float(self.totalTime) / intervalEnable) + 1
            for icount in range(0, 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
            lval = long(float(self.totalTime) / intervalEnable) + 1
            for icount in range(0, 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
            lval = long(float(self.totalTime) / intervalEnable) + 1
            for icount in range(0, 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(0)
            from matplotlib.ticker import MaxNLocator

            SysMgr.matplotlibVersion = \
                float('.'.join(matplotlib.__version__.split('.')[:2]))

            # set backend #
            matplotlib.pyplot.switch_backend('agg')

            # get pylab object #
            SysMgr.importPkgItems('pylab')

        # draw io 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(range(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=4,
                        color=color, fontweight='bold')
                if maxIdx > 0:
                    maxUsage = str(item[maxIdx])
                    text(maxIdx + 1, item[maxIdx] - margin, maxUsage, fontsize=4,
                        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 #
                convertNum = UtilMgr.convSize2Unit
                ytickLabel = \
                    [convertNum(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=4)

            # 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[0:2] == '0[':
                continue

            timeLine = ''
            timeLineLen = titleLineLen
            lval = \
                long(float(self.totalTime) / intervalEnable) + 1
            for icount in range(0, 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(range(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=3, 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(range(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=4)

            # 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[0:2] == '0[':
                continue

            timeLine = ''
            timeLineLen = titleLineLen
            lval = long(float(self.totalTime) / intervalEnable) + 1
            for icount in range(0, 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[0:2] == '0[':
                    continue

                timeLine = ''
                timeLineLen = titleLineLen
                lval = \
                    long(float(self.totalTime) / intervalEnable) + 1
                for icount in range(0, 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[0:2] == '0[':
                    continue

                timeLine = ''
                timeLineLen = titleLineLen
                lval = long(float(self.totalTime) / intervalEnable) + 1
                for icount in range(0, 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[0:2] == '0[':
                    continue

                timeLine = ''
                timeLineLen = titleLineLen
                lval = long(float(self.totalTime) / intervalEnable) + 1
                for icount in range(0, 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 = long(0)

        idx = -1

        for line in now:
            idx += 1
            if not line:
                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])

                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():
        try:
            orig = SysMgr.processEnable
            SysMgr.processEnable = False
            obj = TaskAnalyzer(onlyInstance=True)
            obj.saveProcStat()
            TaskAnalyzer.printProcTree(
                instance=obj.procData, printFunc=SysMgr.infoBufferPrint)
            SysMgr.infoBufferPrint('%s\n' % oneLine)
        except SystemExit:
            sys.exit(0)
        except:
            pass
        finally:
            SysMgr.processEnable = orig



    @staticmethod
    def readTraceData(file):
        try:
            # not compressed data #
            if SysMgr.isRecordMode() or \
                not UtilMgr.isCompressed(file):
                with open(file, 'r') as fd:
                    return fd.readlines()

            # compressed data #
            with open(file, 'rb') as fd:
                compressor = SysMgr.getPkg('gzip')
                fd = compressor.GzipFile(fileobj=fd)

                lines = list()
                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(file)
            sys.exit(0)



    @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(
                "fail to set '%s' as a last field" % option)



    @staticmethod
    def parseProcLine(index, procLine):
        TA = TaskAnalyzer

        # Get time info #
        if 'time' not in TA.procIntData[index]:
            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()
                TA.procIntData[index]['time'] = d['time']
                TA.procIntData[index]['nrCtxt'] = d['nrCtxt']
                TA.procIntData[index]['nrIrq'] = d['nrIrq']
                TA.procIntData[index]['nrCore'] = d['nrCore']
                TA.procIntData[index]['nrProc'] = d['nrProc']
                TA.procIntData[index]['nrThread'] = d['nrThread']
            return

        # define converter #
        convUnit2Size = UtilMgr.convUnit2Size

        # Split stats #
        tokenList = procLine.split('|')

        # Get Total resource usage #
        if 'total' not in TA.procIntData[index] and \
            tokenList[0].startswith('Total'):

            # 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]+)'), tokenList[1])
            if not m:
                return

            d = m.groupdict()

            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

            TA.procIntData[index]['total'] = dict(TA.init_procIntData)

            # save CPU usage on this interval #
            try:
                TA.procIntData[index]['total']['cpu'] = cpu
            except:
                TA.procIntData[index]['total']['cpu'] = long(0)

            # save blkwait on this interval #
            try:
                TA.procIntData[index]['total']['blkwait'] = long(d['block'])
            except:
                TA.procIntData[index]['total']['blkwait'] = long(0)

            # 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]+)'), tokenList[2])
            if not m:
                return

            d = m.groupdict()

            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

            TA.procIntData[index]['total']['mem'] = freeMem
            TA.procIntData[index]['total']['memper'] = freeMemPer
            TA.procIntData[index]['total']['anonmem'] = anonMem
            TA.procIntData[index]['total']['cachemem'] = cacheMem
            TA.procIntData[index]['total']['kernelmem'] = kernelMem

            try:
                TA.procIntData[index]['total']['blk'] = tokenList[5]
            except:
                TA.procIntData[index]['total']['blk'] = '-'

            m = re.match(r'\s*(?P<swap>\-*[0-9]+)', tokenList[3])
            if not m:
                return

            d = m.groupdict()

            TA.procIntData[index]['total']['swap'] = long(d['swap'])

            try:
                TA.procIntData[index]['total']['rclm'] = tokenList[4].strip()
            except:
                TA.procIntData[index]['total']['rclm'] = '-'

            try:
                TA.procIntData[index]['total']['nrFlt'] = long(tokenList[6])
            except:
                TA.procIntData[index]['total']['nrFlt'] = '-'

            try:
                TA.procIntData[index]['total']['netIO'] = tokenList[11].strip()
            except:
                TA.procIntData[index]['total']['netIO'] = '-'

            return

        # Get GPU resource usage #
        elif len(tokenList) == 5:
            m = re.match(
                r'\s*(?P<gpu>.+)\s*\(\s*(?P<usage>[0-9]+)\s*%\)', tokenList[0])
            if m:
                d = m.groupdict()

                gpu = d['gpu'].strip()
                usage = long(d['usage'])

                TA.procIntData[index]['total'].setdefault(
                    'gpu', dict())
                TA.procTotData['total'].setdefault('gpu', dict())

                try:
                    TA.procTotData['total']['gpu'][gpu]['usage'] += usage

                    if TA.procTotData['total']['gpu'][gpu]['min'] > usage:
                        TA.procTotData['total']['gpu'][gpu]['min'] = usage
                    elif TA.procTotData['total']['gpu'][gpu]['max'] < usage:
                        TA.procTotData['total']['gpu'][gpu]['max'] = usage
                except:
                    TA.procTotData['total']['gpu'][gpu] = dict()
                    TA.procTotData['total']['gpu'][gpu]['usage'] = usage
                    TA.procTotData['total']['gpu'][gpu]['min'] = usage
                    TA.procTotData['total']['gpu'][gpu]['max'] = usage

                try:
                    TA.procIntData[index]['total']['gpu'][gpu] = usage
                except:
                    pass

                return

        # Get Storage resource usage #
        elif len(tokenList) == 12 and tokenList[0][0] == '/':
            TA.procIntData[index]['total'].setdefault('storage', dict())

            TA.procTotData['total'].setdefault('storage', dict())

            try:
                # get device name #
                dev = tokenList[0].strip()
                dev = dev[dev.rfind('/')+1:]

                TA.procIntData[index]['total']['storage'].setdefault(dev, dict())
                TA.procTotData['total']['storage'].setdefault(dev, dict())

                # get busy time and average queue-length #
                busy = convUnit2Size(tokenList[1].strip()[:-1])
                avq = tokenList[2].strip()

                # get storage stats in MB #
                read = convUnit2Size(tokenList[3].strip())
                write = convUnit2Size(tokenList[4].strip())

                freestat = tokenList[5].strip().split('(')
                freeDiff = convUnit2Size(freestat[1][:-1].strip())

                # busy #
                try:
                    TA.procIntData[index]['total']['storage'][dev]['busy'] = busy
                    TA.procTotData['total']['storage'][dev]['busy'] += busy
                except:
                    TA.procTotData['total']['storage'][dev]['busy'] = busy

                # avq #
                try:
                    TA.procIntData[index]['total']['storage'][dev]['avq'] = avq
                    TA.procTotData['total']['storage'][dev]['avq'] += avq
                except:
                    TA.procTotData['total']['storage'][dev]['avq'] = avq

                # read #
                try:
                    TA.procIntData[index]['total']['storage'][dev]['read'] = read
                    TA.procTotData['total']['storage'][dev]['read'] += read
                except:
                    TA.procTotData['total']['storage'][dev]['read'] = read

                # write #
                try:
                    TA.procIntData[index]['total']['storage'][dev]['write'] = \
                        write
                    TA.procTotData['total']['storage'][dev]['write'] += write
                except:
                    TA.procTotData['total']['storage'][dev]['write'] = write

                # freediff #
                try:
                    TA.procIntData[index]['total']['storage'][dev]['free'] = \
                        freeDiff
                    TA.procTotData['total']['storage'][dev]['free'] += freeDiff
                except:
                    TA.procTotData['total']['storage'][dev]['free'] = freeDiff
            except SystemExit:
                sys.exit(0)
            except:
                pass

            return

        # Get Network resource usage #
        elif len(tokenList) == 13 and \
            not tokenList[0].startswith('Total'):
            # check condition #
            if tokenList[0].strip() == 'ID' or \
                tokenList[0].strip() == 'Dev':
                return

            TA.procIntData[index]['total'].setdefault('netdev', dict())

            TA.procTotData['total'].setdefault('netdev', dict())

            try:
                # get device name #
                dev = tokenList[0].strip()

                TA.procIntData[index]['total']['netdev'].setdefault(dev, dict())
                TA.procTotData['total']['netdev'].setdefault(dev, dict())

                # get storage stats in MB #
                recv = convUnit2Size(tokenList[2].strip())
                tran = convUnit2Size(tokenList[7].strip())

                # recv #
                try:
                    TA.procIntData[index]['total']['netdev'][dev]['recv'] = recv
                    TA.procTotData['total']['netdev'][dev]['recv'] += recv
                except:
                    TA.procTotData['total']['netdev'][dev]['recv'] = recv

                # tran #
                try:
                    TA.procIntData[index]['total']['netdev'][dev]['tran'] = tran
                    TA.procTotData['total']['netdev'][dev]['tran'] += tran
                except:
                    TA.procTotData['total']['netdev'][dev]['tran'] = tran
            except:
                pass

            return

        # Get Cgroup resource usage #
        elif len(tokenList) == 8:
            tokenList = UtilMgr.cleanItem(tokenList, False)

            system, proc, task, cpu, mem, read, write = tokenList

            # CPU #
            target = 'cgroup.cpu'

            try:
                usage = float(cpu)
            except:
                return

            try:
                TA.procTotData['total'].setdefault(target, dict())

                TA.procTotData['total'][target][system]['usage'] += usage

                if TA.procTotData['total'][target][system]['min'] > usage:
                    TA.procTotData['total'][target][system]['min'] = usage
                elif TA.procTotData['total'][target][system]['max'] < usage:
                    TA.procTotData['total'][target][system]['max'] = usage
            except:
                TA.procTotData['total'][target][system] = dict()
                TA.procTotData['total'][target][system]['usage'] = usage
                TA.procTotData['total'][target][system]['min'] = usage
                TA.procTotData['total'][target][system]['max'] = usage

            try:
                TA.procIntData[index]['total'].setdefault(target, dict())
                TA.procIntData[index]['total'][target][system] = usage
            except:
                pass

            # Memory #
            target = 'cgroup.mem'

            try:
                usage = UtilMgr.convUnit2Size(mem)
            except:
                return

            try:
                TA.procTotData['total'].setdefault(target, dict())
                TA.procTotData['total'][target][system]['usage'] = usage

                if TA.procTotData['total'][target][system]['min'] > usage:
                    TA.procTotData['total'][target][system]['min'] = usage
                elif TA.procTotData['total'][target][system]['max'] < usage:
                    TA.procTotData['total'][target][system]['max'] = usage
            except:
                TA.procTotData['total'][target][system] = dict()
                TA.procTotData['total'][target][system]['usage'] = usage
                TA.procTotData['total'][target][system]['min'] = usage
                TA.procTotData['total'][target][system]['max'] = usage

            try:
                TA.procIntData[index]['total'].setdefault(target, dict())
                TA.procIntData[index]['total'][target][system] = usage
            except:
                pass

            return

        # Get process resource usage #
        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<blk>\S+)\(\s*(?P<blkrd>.+)\/\s*(?P<blkwr>.+)\/'), procLine)
        if not m:
            return

        d = m.groupdict()
        pid = d['pid']
        comm = d['comm']

        try:
            # ignore special processes #
            if comm[0] == '[' and comm[2] == ']':
                # define real comm #
                rcomm = comm[3:]

                # check item #
                if rcomm not in TA.lifecycleData:
                    TA.lifecycleData[rcomm] = [0] * 8

                # initialize lifedata #
                TA.lifeIntData.setdefault(pid, dict())
                TA.lifeIntData[pid].setdefault(index, list())

                # add died process to list #
                if comm[1] == '-':
                    TA.lifecycleData[rcomm][1] += 1
                    if not pid in TA.procIntData[index-1]:
                        TA.procIntData[index-1][pid] = \
                            dict(TA.init_procIntData)

                    TA.procIntData[index-1][pid]['die'] = True
                    TA.lifeIntData[pid][index].append('FINISH')
                # add created process to list #
                elif comm[1] == '+':
                    TA.lifecycleData[rcomm][0] += 1
                    TA.lifeIntData[pid][index].append('START')
                # add zomebie process to list #
                elif comm[1].upper() == 'Z':
                    TA.lifecycleData[rcomm][2] += 1
                    TA.lifeIntData[pid][index].append('ZOMBIE')
                # add stopped process to list #
                elif comm[1] == 'T':
                    TA.lifecycleData[rcomm][3] += 1
                # add traced process to list #
                elif comm[1] == 't':
                    TA.lifecycleData[rcomm][4] += 1
                # add wait process to list #
                elif comm[1].upper() == 'D':
                    TA.lifecycleData[rcomm][5] += 1
                # add waking process to list #
                elif comm[1].upper() == 'W':
                    TA.lifecycleData[rcomm][6] += 1
                # add parked process to list #
                elif comm[1].upper() == 'P':
                    TA.lifecycleData[rcomm][7] += 1

                return
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # 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 = long(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'] = long(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 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 TA.procIntData[index]:
            TA.procIntData[index][pid] = dict(TA.init_procIntData)
            TA.procIntData[index][pid]['cpu'] = cpu
            TA.procIntData[index][pid]['dly'] = dly
            TA.procIntData[index][pid]['vss'] = vss
            TA.procIntData[index][pid]['blk'] = blk
            TA.procIntData[index][pid]['blkrd'] = blkrd
            TA.procIntData[index][pid]['blkwr'] = blkwr
            TA.procIntData[index][pid]['mem'] = rss
            TA.procIntData[index][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 = long(0)
        for val in reversed(SysMgr.procBuffer):
            if len(TaskAnalyzer.procIntData) < idx + 1:
                TaskAnalyzer.procIntData.append({})

            procData = val.split('\n')

            for line in procData:
                TaskAnalyzer.parseProcLine(idx, line)

            idx += 1
            UtilMgr.printProgress(idx, len(SysMgr.procBuffer))

        UtilMgr.deleteProgress()

        if idx == 0:
            return

        # 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 = long(0)
        for filename in list(SysMgr.fileInstance.keys()):
            # 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("%s\n" % twoLine)
        SysMgr.printPipe("{0:^5} | {1:^144} |\n".format('REF', 'FILE'))
        SysMgr.printPipe("%s\n" % 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')
        SysMgr.printPipe("%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 = long(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:
            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:
            return

        if not TaskAnalyzer.procEventData:
            return

        SysMgr.printPipe('\n[Top Event Info] (Unit: %)\n')
        SysMgr.printPipe("%s\n" % twoLine)
        SysMgr.printPipe(("{0:^12} | {1:^12} | {2:^12} | {3:1}\n").\
            format('Timeline', 'Realtime', 'Duration', 'Event'))
        SysMgr.printPipe("%s\n" % twoLine)

        procIntData = TaskAnalyzer.procIntData
        procEventData = TaskAnalyzer.procEventData
        for idx, event in enumerate(procEventData):
            time = '%.2f' % float(event[0])
            name = event[1]
            rtime = '%.2f' % float(event[2])

            try:
                diff = '%.2f' % \
                    (float(procEventData[idx+1][2]) - float(rtime))
            except:
                diff = '%.2f' % \
                    (float(procIntData[-1]['time']) - float(rtime))

            SysMgr.printPipe(("{0:>12} | {1:>12} | {2:>12} | {3:1}\n").\
                format(time, rtime, diff, name))

        SysMgr.printPipe("%s\n" % oneLine)



    @staticmethod
    def printCpuInterval():
        TA = TaskAnalyzer

        # set comm and pid size #
        pd = SysMgr.pidDigit
        cl = 26 - (pd * 2)

        SysMgr.printPipe('\n[Top CPU Info] (Unit: %) (New: +) (Die: -)\n')
        SysMgr.printPipe("%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]', '-', '-', '-', '-', cpuInfo, cl=cl, pd=pd)
        procInfoLen = len(procInfo)
        maxLineLen = SysMgr.lineLength

        timeLine = ''
        lineLen = len(procInfo)
        for idx in range(0,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 = long(0)

            timeLine = '%s%s' % (timeLine, '{0:>6} '.format(usage))
            lineLen += margin + 2

        SysMgr.printPipe(("{0:1} {1:1}\n").format(procInfo, timeLine))
        SysMgr.printPipe("%s\n" % 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 = long(0)
            for idx in range(0,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 = long(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 += '-'
                        elif item == 'ZOMBIE':
                            lflag += 'z'

                # append lifecycle flag to usage #
                usage = '%s%s' % (lflag, usage)

                timeLine = '%s%s' % (timeLine, '{0:>6} '.format(usage))
                lineLen += margin + 2

            # skip process used no CPU #
            if total == 0:
                continue

            SysMgr.printPipe(
                ("{0:1} {1:1}\n").format(procInfo, timeLine))
            SysMgr.printPipe("%s\n" % oneLine)



    @staticmethod
    def printDlyInterval():
        TA = TaskAnalyzer

        # set comm and pid size #
        pd = SysMgr.pidDigit
        cl = 26 - (pd * 2)

        SysMgr.printPipe('\n[Top Delay Info] (Unit: %) (Target: THREAD)\n')
        SysMgr.printPipe("%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 = long(0)
            for idx in range(0,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 = long(0)

                timeLine = '%s%s' % (timeLine, '{0:>6} '.format(usage))
                lineLen += margin + 2

            # skip no delayed procdss #
            if total == 0:
                continue

            SysMgr.printPipe(
                ("{0:1} {1:1}\n").format(procInfo, timeLine))
            SysMgr.printPipe("%s\n" % oneLine)

            cnt += 1

        if cnt == 0:
            SysMgr.printPipe('\tNone\n%s\n' % oneLine)



    @staticmethod
    def printGpuInterval():
        TA = TaskAnalyzer

        # Check gpu data #
        if 'gpu' not in TA.procTotData['total']:
            return

        SysMgr.printPipe('\n[Top GPU Info] (Unit: %)\n')
        SysMgr.printPipe("%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'] / len(TA.procIntData)
            except:
                avg = long(0)

            # get stats #
            stats = '%d/%d/%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 = long(0)
            margin = 5
            for idx in range(0,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 = long(0)

                timeLine = '%s%s' % (timeLine, '{0:>6} '.format(usage))
                lineLen += 7

            SysMgr.printPipe(("{0:1} {1:1}\n").format(gpuInfo, timeLine))
            SysMgr.printPipe("%s\n" % oneLine)



    @staticmethod
    def printRssInterval():
        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' % mtype)
        SysMgr.printPipe("%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 range(0,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 = long(0)

            timeLine = '%s%s' % (timeLine, '{0:>6} '.format(usage))
            lineLen += 7

        SysMgr.printPipe(("{0:1} {1:1}\n").format(procInfo, timeLine))
        SysMgr.printPipe("%s\n" % 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 = long(0)
            timeLine = ''
            minRss = maxRss = long(0)
            lineLen = len(procInfo)
            intData = TA.procIntData
            for idx in range(0,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 = long(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 = long(0)
                        # process is alive #
                        else:
                            usage = prev
                    except:
                        usage = prev
                else:
                    prev = usage = long(0)

                if usage == 0:
                    pass
                else:
                    if minRss == 0 or minRss > usage:
                        minRss = usage
                    if maxRss == 0 or maxRss < usage:
                        maxRss = usage

                timeLine = '%s%s' % (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").format(procInfo, timeLine))
            SysMgr.printPipe("%s\n" % oneLine)



    @staticmethod
    def printVssInterval():
        TA = TaskAnalyzer

        # set comm and pid size #
        pd = SysMgr.pidDigit
        cl = 26 - (pd * 2)

        SysMgr.printPipe('\n[Top VSS Info] (Unit: MB) (Change: ^)\n')
        SysMgr.printPipe("%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 range(0,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 = long(0)

            timeLine = '%s%s' % (timeLine, '{0:>6} '.format(usage))
            lineLen += 7

        SysMgr.printPipe(("{0:1} {1:1}\n").format(procInfo, timeLine))
        SysMgr.printPipe("%s\n" % 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 = long(0)
            timeLine = ''
            minVss = maxVss = long(0)
            lineLen = len(procInfo)
            intData = TA.procIntData
            for idx in range(0,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 = long(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 = long(0)
                        # process is alive #
                        else:
                            usage = prev
                    except:
                        usage = prev
                else:
                    prev = usage = long(0)

                if usage == 0:
                    pass
                else:
                    if minVss == 0 or minVss > usage:
                        minVss = usage
                    if maxVss == 0 or maxVss < usage:
                        maxVss = usage

                timeLine = '%s%s' % (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").format(procInfo, timeLine))
            SysMgr.printPipe("%s\n" % oneLine)



    @staticmethod
    def printBlkInterval():
        TA = TaskAnalyzer

        # set comm and pid size #
        pd = SysMgr.pidDigit
        cl = 26 - (pd * 2)

        SysMgr.printPipe('\n[Top Block Info] (Unit: %)\n')
        SysMgr.printPipe("%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 = long(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'], 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 range(0,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:
                        usage = '%s/%s' % (target['blkrd'], target['blkwr'])
                    else:
                        usage = target['blk']
                else:
                    if SysMgr.blockEnable:
                        usage = '0/0'
                    else:
                        usage = long(0)

                timeLine = '%s%s' % (timeLine, '{0:>6} '.format(usage))
                lineLen += 7

            SysMgr.printPipe(("{0:1} {1:1}\n").format(procInfo, timeLine))
            SysMgr.printPipe("%s\n" % oneLine)
            itemCnt += 1

        if itemCnt == 0:
            SysMgr.printPipe('\tNone\n')
            SysMgr.printPipe("%s\n" % oneLine)



    @staticmethod
    def printStorageInterval():
        TA = TaskAnalyzer

        convSize2Unit = UtilMgr.convSize2Unit

        SysMgr.printPipe('\n[Top Storage Info] (Unit: %)\n')
        SysMgr.printPipe("%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:
                continue

            storageInfo = "{0:>16} | {1:^21} |".format(dev, total)
            storageInfoLen = len(storageInfo)
            maxLineLen = SysMgr.lineLength

            timeLine = ''
            lineLen = len(storageInfo)
            for idx in range(0,len(TA.procIntData)):
                if lineLen + margin > maxLineLen:
                    timeLine += ('\n' + (' ' * (storageInfoLen - 1)) + '| ')
                    lineLen = len(storageInfo)

                try:
                    stats = TA.procIntData[idx]['total']['storage'][dev]
                    usage = '%s/%s/%s/%s' % \
                        (stats['busy'],
                        convSize2Unit(stats['read'], True),
                        convSize2Unit(stats['write'], True),
                        convSize2Unit(stats['free'], True))
                except:
                    usage = '0/0/0/0'

                timeLine = '%s%s' % (timeLine, '{0:>21} '.format(usage))
                lineLen += margin

            SysMgr.printPipe(
                ("{0:1} {1:1}\n").format(storageInfo, timeLine))
            SysMgr.printPipe("%s\n" % oneLine)



    @staticmethod
    def printNetworkInterval():
        TA = TaskAnalyzer

        convSize2Unit = UtilMgr.convSize2Unit

        SysMgr.printPipe('\n[Top Network Info] (Unit: %)\n')
        SysMgr.printPipe("%s\n" % twoLine)

        # Print menu #
        networkInfo = "{0:>16} | {1:^21} |".format('Device', 'Read/Write')
        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 range(0,len(TA.procIntData)):
                if lineLen + margin > maxLineLen:
                    timeLine += ('\n' + (' ' * (networkInfoLen - 1)) + '| ')
                    lineLen = len(networkInfo)

                try:
                    stats = TA.procIntData[idx]['total']['netdev'][dev]
                    usage = '%s/%s' % \
                        (convSize2Unit(stats['recv'], True),
                        convSize2Unit(stats['tran'], True))
                except:
                    usage = '0/0'

                timeLine = '%s%s' % (timeLine, '{0:>21} '.format(usage))
                lineLen += margin

            SysMgr.printPipe(
                ("{0:1} {1:1}\n").format(networkInfo, timeLine))
            SysMgr.printPipe("%s\n" % 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 range(1,len(TaskAnalyzer.procIntData) + 1):
            if lineLen + margin > maxLineLen:
                timeLine += ('\n' + (' ' * (length - 1)) + '| ')
                lineLen = length

            timeLine = '%s%s' % \
                (timeLine, '{0:>{margin}} '.format(i, margin=margin+more))
            lineLen += margin + spaces

        SysMgr.printPipe(("{0:1} {1:1}\n").format(title, timeLine))
        SysMgr.printPipe("%s\n" % twoLine)



    @staticmethod
    def printCgCpuInterval():
        TA = TaskAnalyzer

        convSize2Unit = UtilMgr.convSize2Unit

        SysMgr.printPipe('\n[Top Cgroup.CPU Info] (Unit: %)\n')
        SysMgr.printPipe("%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 TA.procTotData['total']['cgroup.cpu'].items():
            total = long(val['usage'])
            minval = long(val['min'])
            maxval = long(val['max'])

            try:
                avg = total / len(TaskAnalyzer.procIntData)
            except:
                avg = long(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 range(0,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 = '%s%s' % (timeLine, '{0:>6} '.format(usage))
                lineLen += margin + 2

            SysMgr.printPipe(
                ("{0:1} {1:1}\n").format(cgroupInfo, timeLine))
            SysMgr.printPipe("%s\n" % oneLine)



    @staticmethod
    def printCgMemInterval():
        TA = TaskAnalyzer

        convSize2Unit = UtilMgr.convSize2Unit

        SysMgr.printPipe('\n[Top Cgroup.Mem Info] (Unit: %)\n')
        SysMgr.printPipe("%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 TA.procTotData['total']['cgroup.mem'].items():
            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 range(0,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 = '%s%s' % (timeLine, '{0:>6} '.format(usage))
                lineLen += margin + 2

            SysMgr.printPipe(
                ("{0:1} {1:1}\n").format(cgroupInfo, timeLine))
            SysMgr.printPipe("%s\n" % oneLine)



    @staticmethod
    def printIntervalUsage():
        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))

        if SysMgr.fileTopEnable:
            TaskAnalyzer.printFileTable()
        elif SysMgr.jsonEnable or \
            SysMgr.dltTopEnable or \
            SysMgr.dbusTopEnable:
            pass
        else:
            # build summary interval table #
            TaskAnalyzer.summarizeInterval()

            # print interval info #
            TaskAnalyzer.printTimeline()
            TaskAnalyzer.printEventInterval()
            TaskAnalyzer.printCpuInterval()
            TaskAnalyzer.printDlyInterval()
            TaskAnalyzer.printGpuInterval()
            TaskAnalyzer.printVssInterval()
            TaskAnalyzer.printRssInterval()
            TaskAnalyzer.printBlkInterval()
            TaskAnalyzer.printStorageInterval()
            TaskAnalyzer.printNetworkInterval()
            TaskAnalyzer.printCgCpuInterval()
            TaskAnalyzer.printCgMemInterval()

        # print interval info #
        TaskAnalyzer.printMemAnalysis()

        # print detailed statistics #
        _printMenu(' Detailed Statistics ')
        if 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(
                'fail to save kernel message', reason=True)

        # initialize parse buffer #
        TaskAnalyzer.lifeIntData = {}
        TaskAnalyzer.lifecycleData = {}
        TaskAnalyzer.procTotData = {}
        TaskAnalyzer.procIntData = []



    @staticmethod
    def printLeakHint():
        if not SysMgr.isTopMode() or \
            not SysMgr.topInstance:
            SysMgr.printPipe("\n\tNone")
            return

        convertNum = UtilMgr.convNum
        convertFunc = UtilMgr.convSize2Unit

        for pid in tuple(SysMgr.procInstance.keys()):
            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 = long(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][1:-1]
            runtime = \
                SysMgr.uptime - (float(val['stat'][starttimeIdx]) / 100)

            if SysMgr.processEnable:
                ppid = stat[ppidIdx]
            else:
                ppid = val['mainID']

            SysMgr.printPipe((
                "{0:>16}({1:>7}/{2:>7}) "
                "{3:>8} {4:>8} {5:>8} {6:>12} {7:>20}\n").format(
                    comm, pid, ppid,
                    convertFunc(long(stat[vssIdx])),
                    convertFunc(long(stat[rssIdx]) << 12),
                    convertFunc(long(statm[shrIdx]) << 12),
                    convertNum(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 printProcTree(instance=None, title=False, printFunc=None):
        if not instance and SysMgr.procInstance:
            instance = SysMgr.procInstance

        if not printFunc:
            printFunc = SysMgr.printPipe

        if not instance:
            printFunc("\n\tNone")
            return

        commIdx = ConfigMgr.STAT_ATTR.index("COMM")
        stttimeIdx = 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:
            printFunc("\n\tNone")
            return

        # set target #
        if SysMgr.processEnable:
            target = 'Process'
        else:
            target = 'Thread'

        # print title #
        printFunc((
            "\n[%s Tree Info]\n%s\n"
            "  %-22s %4s(%8s/%11s) <%s>\n%s") % \
                (target, twoLine, 'Name(ID)', 'Per', 'CPUTIME',
                    'RUNTIME', 'SUB', oneLine))

        # print nodes in tree #
        def _printTreeNodes(root, depth):
            treestr = ''

            # check depth #
            if SysMgr.funcDepth > 0 and SysMgr.funcDepth <= depth:
                return treestr

            for pid, childs in sorted(root.items(), key=lambda x: long(x[0])):
                indent = ''

                # get comm #
                try:
                    comm = instance[pid]['comm']
                    if SysMgr.filterGroup and \
                        UtilMgr.isValidStr(comm, inc=True, ignCap=True):
                        comm = UtilMgr.convColor(comm, 'RED')
                except:
                    comm = '?'

                # get runtime #
                try:
                    runtime = long(instance[pid]['stat'][stttimeIdx]) / 100
                    runtime = SysMgr.uptime - runtime
                    runtimestr = UtilMgr.convTime(runtime)
                except SystemExit:
                    sys.exit(0)
                except:
                    runtime = '?'
                    runtimestr = '?'

                # get CPU time #
                try:
                    utime = long(instance[pid]['stat'][utimeIdx])
                    stime = long(instance[pid]['stat'][stimeIdx])
                    ttime = (utime + stime) / 100
                    ttimestr = UtilMgr.convTime(ttime)
                    if ttime > 0:
                        ttimestr = UtilMgr.convColor(ttimestr, 'YELLOW')
                except SystemExit:
                    sys.exit(0)
                except:
                    ttime = '?'
                    ttimestr = '?'

                # get CPU time by runtime #
                try:
                    cpuPer = round(ttime / float(runtime) * 100, 1)
                    if cpuPer > 0:
                        cpuPer = UtilMgr.convColor(cpuPer, 'GREEN')
                    else:
                        cpuPer = 0
                except SystemExit:
                    sys.exit(0)
                except:
                    cpuPer = 0

                if depth == 0:
                    indent = '\n'

                for idx in range(0, depth):
                    indent = '%s%s|' % (indent, ' ' * 5)

                procInfo = "%s(%s)" % (comm, pid)
                treestr += '%s- %-22s %3s%%(%s/%s) ' % \
                    (indent, procInfo, cpuPer, ttimestr, runtimestr)

                nrChild = len(childs)
                if nrChild > 0:
                    treestr += '<%s>' % nrChild

                treestr += '\n'

                treestr += _printTreeNodes(childs, depth + 1)

            return treestr

        # get string for tree #
        finalstr = _printTreeNodes(procTree, 0)

        # print tree #
        printFunc(finalstr.strip('\n'))



    @staticmethod
    def printMemAnalysis():
        if 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')
        SysMgr.printPipe("%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(
                "fail 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 #
            if not value['maps']:
                TaskAnalyzer.saveProcSmapsData(value['taskPath'], key)

            if not value['maps']:
                continue

            cnt += 1

            totalCnt = long(0)
            totalVmem = long(0)
            totalRss = long(0)
            totalPss = long(0)
            totalSwap = long(0)
            totalHuge = long(0)
            totalLock = long(0)
            totalPdirty = long(0)
            totalSdirty = long(0)
            totalRef = long(0)
            totalNone = long(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:
                    vmem = long(0)

                try:
                    rss = item['Rss:'] >> 10
                    totalRss += rss
                except:
                    rss = long(0)

                try:
                    pss = item['Pss:'] >> 10
                    totalPss += pss
                except:
                    pss = long(0)

                try:
                    swap = item['Swap:'] >> 10
                    totalSwap += swap
                except:
                    swap = long(0)

                try:
                    huge = item['AnonHugePages:'] >> 10
                    totalHuge += huge
                except:
                    huge = long(0)

                try:
                    lock = item['Locked:']
                    totalLock += lock
                except:
                    lock = long(0)

                try:
                    pdirty = item['Private_Dirty:']
                    totalPdirty += pdirty
                except:
                    pdirty = long(0)

                try:
                    sdirty = item['Shared_Dirty:']
                    totalSdirty += sdirty
                except:
                    sdirty = long(0)

                try:
                    ref = item['Referenced:']
                    totalRef += ref
                except:
                    ref = long(0)

                try:
                    none = item['NOPM']
                    totalNone += none
                except:
                    none = long(0)

                procDetails = \
                    "%s%s" % (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][1:-1][: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(0)

            # 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(
                    "fail 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.isRecordMode() and \
                SysMgr.progressCnt >= SysMgr.repeatInterval:
                return 0

            # update fd #
            try:
                if SysMgr.isRecordMode():
                    verbose = False
                else:
                    verbose = True

                if compressor and fd:
                    if verbose:
                        SysMgr.printStat(
                            r"start checking '%s'..." % fname)
                else:
                    try:
                        fd = UtilMgr.getTextLines(fname, verbose, retfd=True)
                    except SystemExit:
                        sys.exit(0)
                    except:
                        SysMgr.printErr(
                            "fail to read %s\n" % fname, reason=True)
                        sys.exit(0)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenErr(fname)
                sys.exit(0)

            # 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(
                    "fail to read because there is no log")
                sys.exit(0)



    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):
            try:
                targetTable[did][0] += size
                targetTable[did][1] += 1
                if targetTable[did][2] == addr:
                    targetTable[did][3] += size
                    targetTable[did][4] += 1
                targetTable[did][2] = blkOffset
            except:
                sizeTable = {}
                targetTable[did] = [size, 1, blkOffset, size, 1, sizeTable]

            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)

        if size > 1:
            blkOffset = addr + (size >> 9)
        else:
            # convert page to real size #
            size = SysMgr.pageSize
            blkOffset = addr + 1

        blkSize = _getBlkOptSize(size)

        # revise real minor number by address #
        for did, val in SysMgr.savedMountTree.items():
            try:
                if did.split(':')[0] == major and \
                    val['start'] <= addr <= val['end']:
                    minor = did.split(':')[1]
                    break
            except:
                pass

        # make device id #
        did = '%s:%s' % (major, minor)

        if opt == 'R':
            targetTable = readTable
        elif opt == 'W':
            targetTable = writeTable
        else:
            SysMgr.printWarn(
                "fail to recognize block operation '%s'" % opt)
            return

        # apply total block info #
        _applyBlkOpt(targetTable, addr, size, blkSize, blkOffset)

        if tid not in taskTable:
            taskTable[tid] = [{}, {}]

        if opt == 'R':
            targetTable = taskTable[tid][0]
        elif opt == 'W':
            targetTable = taskTable[tid][1]
        else:
            SysMgr.printWarn(
                "fail to recognize block operation '%s'" % opt)
            return

        # apply thread block info #
        _applyBlkOpt(targetTable, addr, size, blkSize, blkOffset)



    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': long(0), 'totalBw': long(0),
                    'totalMem': long(0), 'totalKmem': long(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))

            # save total usage in this interval #
            curIntval['totalUsage'] = \
                float(self.threadData[key]['usage'])
            curIntval['totalPreempted'] = \
                float(self.threadData[key]['cpuWait'])
            curIntval['totalCoreSchedCnt'] = \
                long(self.threadData[key]['coreSchedCnt'])
            curIntval['totalBrUsage'] = \
                long(self.threadData[key]['reqRdBlock'])
            curIntval['totalBwUsage'] = \
                long(self.threadData[key]['writeBlock']) + \
                (long(self.threadData[key]['awriteBlock']) << 3)
            curIntval['totalMemUsage'] = \
                long(self.threadData[key]['nrPages'])
            curIntval['totalKmemUsage'] = \
                long(self.threadData[key]['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 self.threadData[key]['new'] != ' ':
                curIntval['new'] = self.threadData[key]['new']
            if self.threadData[key]['die'] != ' ':
                curIntval['die'] = self.threadData[key]['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'] = \
                            self.threadData[key]['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'] = \
                            self.threadData[key]['userEvent'][evt]['count']

                        curIntval['totalUserEvent'][evt]['usage'] = \
                            self.threadData[key]['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'] = \
                            self.threadData[key]['kernelEvent'][evt]['count']

                        curIntval['totalKernelEvent'][evt]['usage'] = \
                            self.threadData[key]['kernelEvent'][evt]['usage']
                    except SystemExit:
                        sys.exit(0)
                    except:
                        pass

            # first interval #
            if SysMgr.intervalNow == intervalEnable:
                curIntval['cpuUsage'] = \
                    float(self.threadData[key]['usage'])
                curIntval['preempted'] = \
                    float(self.threadData[key]['cpuWait'])
                curIntval['coreSchedCnt'] = \
                    float(self.threadData[key]['coreSchedCnt'])
                curIntval['brUsage'] = \
                    long(self.threadData[key]['reqRdBlock'])
                curIntval['bwUsage'] = \
                    long(self.threadData[key]['writeBlock']) + \
                    (long(self.threadData[key]['awriteBlock']) << 3)
                curIntval['memUsage'] = \
                    long(self.threadData[key]['nrPages'])
                curIntval['kmemUsage'] = \
                    long(self.threadData[key]['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'].keys()):
                    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'].keys()):
                    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'].keys()):
                    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 range(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 range(
                        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 = self.threadData[key]['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'] = long(0)

            # revise thread interval usage in DVFS system #
            if curIntval['cpuPer'] > 100:
                curIntval['cpuPer'] = 100
            elif curIntval['cpuPer'] < 0:
                curIntval['cpuPer'] = long(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 range(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[0:2] == '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.moduleData = []
        self.intData = []
        self.depData = []
        self.sigData = []
        self.lockTable = {}
        self.flockData = []
        self.futexData = []
        self.customEventData = []
        self.userEventData = []
        self.kernelEventData = []
        self.syscallData = []
        self.lastJob = {}
        self.preemptData = []
        self.suspendData = []
        self.markData = []
        self.consoleData = []
        self.statData = {}

        self.customEventInfo = {}
        self.userEventInfo = {}
        self.kernelEventInfo = {}

        self.customInfo = {}
        self.userInfo = {}
        self.kernelInfo = {}

        self.stopFlag = False
        self.totalTime = long(0)
        self.totalTimeOld = long(0)
        self.cxtSwitch = long(0)
        self.nrNewTask = long(0)
        self.thisInterval = long(0)
        self.trimStart = float(0)
        self.trimStop = float(0)



    def handleUserEvent(self, event, time):
        # initialize TaskAnalyzer data #
        if event == 'START':
            self.initThreadData()

            SysMgr.startTime = time

            # initialize preempt thread list #
            if SysMgr.preemptGroup:
                for index in SysMgr.preemptGroup:
                    self.preemptData.append(
                        [False, {}, float(0), 0, float(0)])
        # finish data processing #
        elif event == 'STOP':
            SysMgr.totalLine = SysMgr.curLine
            self.finishTime = time
            self.stopFlag = True
        # restart data processing #
        elif event == 'RESTART':
            self.threadDataOld = self.threadData
            self.irqDataOld = self.irqData
            self.ioDataOld = self.ioData
            self.reclaimDataOld = self.reclaimData
            self.pageTableOld = self.pageTable
            self.kmemTableOld = self.kmemTable
            self.blockTableOld = self.blockTable
            self.moduleDataOld = self.moduleData
            self.intDataOld = self.intData
            self.depDataOld = self.depData
            self.sigDataOld = self.sigData
            self.lockTableOld = self.lockTable
            self.flockDataOld = self.flockData
            self.customEventDataOld = self.customEventData
            self.userEventDataOld = self.userEventData
            self.kernelEventDataOld = self.kernelEventData
            self.syscallDataOld = self.syscallData
            self.preemptDataOld = self.preemptData
            self.suspendDataOld = self.suspendData
            self.markDataOld = self.markData
            self.consoleDataOld = self.consoleData

            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 parse(self, string):
        def _printEventWarning(func):
            SysMgr.printWarn(
                "fail 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)

        # check trim range #
        if self.trimStart > 0 and allTime < self.trimStart:
            return time
        elif self.trimStop > 0 and allTime > 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 == '<...>' and thread in SysMgr.commCache:
            comm = SysMgr.commCache[thread]

        # 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 #
        try:
            if d['tgid'].startswith('-'):
                raise Exception('no tgid')
            threadData['tgid'] = d['tgid']
        except:
            try:
                threadData['tgid'] = \
                    SysMgr.savedProcTree[thread]
            except:
                pass

        # 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

            '''
            /* 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 */

            /* states beyond TASK_REPORT: */
            "I (idle)",     /* 0x80 */
            '''

            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

            # 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'] = long(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'] = float(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 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 len(self.threadData[prev_id]['futexObj']) > 0:
                    self.threadData[prev_id]['ftxLBlock'] = ftime
                    self.threadData[prev_id]['ftxLSwitch'] += 1

                    # remove previous BLOCK enter event #
                    if len(self.futexData) > 0 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:
                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'] = long(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'] = long(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 = long(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 #
            if not prev_id.startswith('0[') and \
                (not SysMgr.filterGroup or \
                    prev_id in SysMgr.filterGroup or \
                    UtilMgr.isValidStr(prev_comm)):

                # add runtime to list for histogram #
                self.statData.setdefault('runtime', list())
                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.timelineData['segments'].append({
                    'group': long(coreId[2:-1]),
                    'text': '%s(%s)' % (tcomm, prev_id),
                    'id': prev_id,
                    'state': prev_state,
                    'time_start': start_delta,
                    'time_end': 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 == 'S' or prev_state == 'D' or \
                prev_state == 't' or prev_state == 'T':
                # except for core sched event #
                if prev_id != coreId:
                    self.threadData[prev_id]['yield'] += 1
                    self.threadData[coreId]['yield'] += 1

                self.threadData[prev_id]['stop'] = long(0)
                self.threadData[prev_id]['lastStatus'] = 'S'

            else:
                self.threadData[prev_id]['stop'] = long(0)
                self.threadData[prev_id]['lastStatus'] = prev_state

            # 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'] = long(0)

                self.statData.setdefault('schedlat', list())
                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'] == 'P':
                preemptedTime = next_start - next_stop

                if preemptedTime >= 0:
                    self.threadData[next_id]['cpuWait'] += preemptedTime
                else:
                    SysMgr.printWarn(
                        "preempted time of %s(%s) is negative(%f) at line %d" % \
                        (next_comm, next_id, preemptedTime, 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', list())
                    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', dict())
            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'] = long(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'] = long(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'] = long(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'] = long(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', dict())
            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 range(0, 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 range(0, 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+)\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 == "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

            # apply thread filter #
            if SysMgr.isExceptTarget(thread, self.threadData):
                return time

            # update futex lock stat #
            if nr == ConfigMgr.sysList.index("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((
                            "fail to find return of %s for thread %s at %s line\n"\
                            "\tso report 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 == ConfigMgr.sysList.index("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:
                threadData['syscallInfo']
            except:
                threadData['syscallInfo'] = dict()
            try:
                threadData['syscallInfo'][nrstr]
            except:
                threadData['syscallInfo'][nrstr] = \
                    dict(self.init_syscallInfo)

            # save syscall info #
            threadData['nrSyscall'] += 1
            threadData['lastNrSyscall'] = nr
            threadData['syscallInfo'][nrstr]['count'] += 1
            threadData['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

            # apply filter #
            if SysMgr.isExceptTarget(thread, self.threadData):
                return time

            # handle wrong syscall number #
            if nr < 0 and td['lastNrSyscall'] >= 0:
                nr = td['lastNrSyscall']

            # update futex lock stat #
            if nr == ConfigMgr.sysList.index("sys_futex"):
                lockEnter = td['ftxEnter']
                lockStat = td['ftxStat']

                # futex call status #
                if lockEnter > 0:
                    # elasped time #
                    futexTime = ftime - lockEnter

                    if futexTime > td['ftxMax']:
                        td['ftxMax'] = futexTime

                    td['ftxTotal'] += futexTime
                    td['ftxEnter'] = long(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 = long(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 == ConfigMgr.sysList.index("sys_write") and \
                    self.wakeupData['valid'] > 0:
                    self.wakeupData['valid'] -= 1
                elif SysMgr.arch != 'aarch64' and \
                    (nr == ConfigMgr.sysList.index("sys_poll") or \
                    nr == ConfigMgr.sysList.index("sys_select") or \
                    nr == ConfigMgr.sysList.index("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), " ", " ",
                            threadData['comm'], thread, "wakeup"))

                        self.wakeupData['time'] = allTime
                        self.lastJob[core]['prevWakeupTid'] = thread
                elif (SysMgr.arch == 'arm' and \
                    nr == ConfigMgr.sysList.index("sys_recv")) or \
                    nr == ConfigMgr.sysList.index("sys_recvfrom") or \
                    nr == ConfigMgr.sysList.index("sys_recvmsg") or \
                    nr == ConfigMgr.sysList.index("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), " ", " ",
                            threadData['comm'], thread, "recv"))

                        self.wakeupData['time'] = allTime
                        self.lastJob[core]['prevWakeupTid'] = thread
            except SystemExit:
                sys.exit(0)
            except:
                pass

            # register syscall #
            try:
                threadData['syscallInfo']
            except:
                threadData['syscallInfo'] = {}
            try:
                threadData['syscallInfo'][nrstr]
            except:
                threadData['syscallInfo'][nrstr] = \
                    dict(self.init_syscallInfo)

            # save syscall usage #
            diff = ''
            sysItem = threadData['syscallInfo'][nrstr]
            if sysItem['last'] > 0:
                start_delta = long((float(sysItem['last'])-stime)*1000000)
                stop_delta = long((float(ftime)-stime)*1000000)
                text = '%s(%s)_%s' % (comm, thread, ConfigMgr.sysList[nr])

                # add timeline data #
                self.timelineData['segments'].append({
                    'group': core,
                    'text': text,
                    'id': thread,
                    'state': 'SYSCALL',
                    'time_start': start_delta,
                    'time_end': stop_delta,
                })

                diff = ftime - sysItem['last']
                threadData['syscallInfo'][nrstr]['usage'] += diff
                threadData['syscallInfo'][nrstr]['last'] = long(0)

                if sysItem['max'] == 0 or sysItem['max'] < diff:
                    threadData['syscallInfo'][nrstr]['max'] = diff
                if sysItem['min'] <= 0 or sysItem['min'] > diff:
                    threadData['syscallInfo'][nrstr]['min'] = diff

                if ret[0] == '-':
                    threadData['syscallInfo'][nrstr]['err'] += 1
            else:
                start_delta = long(0)
                stop_delta = long((float(ftime)-stime)*1000000)
                text = '%s(%s)_%s' % (comm, thread, ConfigMgr.sysList[nr])

                # add timeline data #
                self.timelineData['segments'].append({
                    'group': core,
                    'text': text,
                    'id': thread,
                    'state': 'SYSCALL',
                    'time_start': start_delta,
                    'time_end': stop_delta,
                })

            # 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 #
                if sig == str(signal.SIGCHLD):
                    if self.threadData[pid]['waitStartAsParent'] > 0:
                        if self.threadData[pid]['waitPid'] == 0 or \
                            self.threadData[pid]['waitPid'] == long(thread):
                            diff = ftime - \
                                self.threadData[pid]['waitStartAsParent']
                            threadData['waitParent'] = diff
                            self.threadData[pid]['waitChild'] += diff
                elif sig == str(signal.SIGSEGV):
                    self.threadData[pid]['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'])

            # 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': long(d['size'])}

            self.saveBlkOpt(thread, comm, opt[0], d['major'], d['minor'],
                d['address'], SysMgr.blockSize * long(d['size']))

            # read operations #
            if opt[0] == 'R':
                threadData['reqRdBlock'] += long(d['size'])
                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'] += long(d['size'])
                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*(?P<operation>\S+)'
                r'\s*\(.*\)\s*(?P<address>\S+)\s+\+\s+(?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 = long(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'] = long(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.timelineData['segments'].append({
                            'group': lastCore,
                            'text': text,
                            'id': reqThd,
                            'state': 'RD',
                            'time_start': start_delta,
                            'time_end': 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'] = long(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.timelineData['segments'].append({
                            'group': lastCore,
                            'text': text,
                            'id': reqThd,
                            'state': 'WR',
                            'time_start': start_delta,
                            'time_end': stop_delta,
                        })

        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

            bid = d['ino'] + d['index']

            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'], 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': float(0)}

            if self.reclaimData[thread]['start'] <= 0:
                self.reclaimData[thread]['start'] = ftime

            threadData['reclaimCnt'] += 1

        elif func == "mm_vmscan_kswapd_sleep":
            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'])
                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'] = long(0)

        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((
                    "fail to handle a new task %s(%s) "
                    "because it is already exist") % (data['comm'], pid))
            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'] = list()

                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']

            try:
                data = self.threadData[cpid]
                SysMgr.printWarn((
                    "fail to handle a new task %s(%s) "
                    "because it is already exist") % (data['comm'], cpid))
            except:
                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'] = list()

                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'] = long(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'] = long(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":
            pass

        elif func == "netif_receive_skb":
            pass

        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 == "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 = long(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'] = float(0)
                # undefined #
                else:
                    return time

                stop_delta = long((float(ftime)-stime)*1000000)

                # add timeline data #
                self.timelineData['segments'].append({
                    'group': long(core),
                    'text': 'OFF',
                    'id': thread,
                    'state': 'OFF',
                    'time_start': start_delta,
                    'time_end': 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'] = dict()

        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 consol 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.timelineData['segments'].append({
                'group': long(core),
                'text': d['event'],
                'id': thread,
                'state': 'EVENT_MARK',
                'time_start': start_delta,
                'time_end': 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 = long(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 = long(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 = long(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>.+) <(?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(
                            "fail to recognize '%s' kernel event" % etc)

                if not isSaved:
                    continue

                # get interval #
                interDiff = long(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(
                            "fail 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):
        for key, value in sorted(self.threadData.items(),
            key=lambda e: e[1]['usage'], reverse=True):

            per = float(value['usage']) / float(self.totalTime)
            newPercent = round(per, 7) * 100

            try:
                self.threadDataOld[key]
            except:
                if long(newPercent) < 1:
                    del self.threadData[key]
                continue

            oldPercent = \
                round(float(self.threadDataOld[key]['usage']) / \
                float(self.totalTimeOld), 7) * 100
            if long(oldPercent) >= long(newPercent) or long(newPercent) < 1:
                del self.threadData[key]



    def printFileStat(self, filters):
        # update uptime #
        SysMgr.updateUptime()

        convNum = UtilMgr.convNum

        # print cpu usage #
        cpuUsage = TaskAnalyzer.dbgObj.getCpuUsage()
        diff = SysMgr.uptimeDiff
        if diff == 0:
            diff = 0.1
        ttime = cpuUsage[0] / diff
        utime = cpuUsage[1] / diff
        stime = cpuUsage[2] / diff
        cpuStr = '%d%%(Usr:%d%%/Sys:%d%%)' % (ttime, utime, stime)

        SysMgr.addPrint((
            "[Top File Info] [Time: %7.3f] [Proc: %s] "
            "[FD: %s] [File: %s] [CPU: %s] (Unit: %%/MB/NR)\n") % \
            (SysMgr.uptime, convNum(self.nrProcess),
            convNum(self.nrFd), convNum(len(self.fileData)), cpuStr))

        SysMgr.addPrint("%s\n" % twoLine + \
            ("{0:^16} ({1:^7}/{2:^7}/{3:^4}/{4:>4})|{5:^4}|{6:^103}|\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)

        procFilter, fileFilter = filters

        # print process info #
        procCnt = long(0)
        for idx, value in sortedProcData:
            stat = value['stat']
            comm = stat[self.commIdx][1:-1]
            pid = stat[self.ppidIdx]

            if ConfigMgr.SCHED_POLICY[int(stat[self.policyIdx])] == 'C':
                schedValue = "%3d" % (long(stat[self.prioIdx]) - 20)
            else:
                schedValue = "%3d" % (abs(long(stat[self.prioIdx]) + 1))

            procInfo = ("{0:>16} ({1:>7}/{2:>7}/{3:>4}/{4:>4})").\
                format(comm, idx, pid, stat[self.nrthreadIdx],
                ConfigMgr.SCHED_POLICY[int(stat[self.policyIdx])] + \
                str(schedValue))

            procInfoLen = len(procInfo)

            if 'fdInfo' in value:
                details = '   '.join(["%s: %s" % (fd,path) for fd, path in \
                    sorted(value['fdInfo'].items(),
                    key=lambda e: long(e[1]), reverse=True)])
            else:
                details = ' '

            procInfo = "%s|%s\n" % \
                (procInfo, '{0:>4}| {1:<106}|'.format(
                len(value['fdList']), details))

            fdCnt = long(0)
            if SysMgr.sort == 'f':
                if procInfo != '':
                    ret = SysMgr.addPrint(procInfo)
                    procInfo = ''
                    if not ret:
                        break

                fdCnt += 1
                procCnt += 1

                continue

            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 len(addr) > 0:
                            path = '%s (%s)' % (path, addr[0])
                            raise Exception('skip UDS socket')
                        uds = SysMgr.getSocketPathList([obj])
                        if len(uds) > 0:
                            path = '%s (%s)' % (path, uds[0])
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

                # apply filter #
                if fileFilter:
                    found = False
                    for fileItem in fileFilter:
                        if fileItem in path:
                            found = True
                            break
                    if not found:
                        continue

                if procInfo != '':
                    ret = SysMgr.addPrint(procInfo)
                    procInfo = ''
                    if not ret:
                        break

                # read pos and permission #
                try:
                    assert path.startswith('/')

                    attr = ''
                    fdinfoPath = "%s/%s/fdinfo/%s" % \
                        (SysMgr.procPath, idx, fd)
                    with open(fdinfoPath, 'r') as infofd:
                        lines = infofd.readlines()

                        for item in lines:
                            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(
                        'fail to read attributes from %s' % fdinfoPath,
                            reason=True)

                SysMgr.addPrint(
                    ("{0:>1}|{1:>4}| {2:<106}|\n").format(
                    ' ' * procInfoLen, fd, path))

                fdCnt += 1

            if fdCnt > 0:
                procCnt += 1

            if fdCnt > 0:
                ret = SysMgr.addPrint("%s\n" % oneLine)
                if not ret:
                    break

        if 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 SysMgr.sort == 'f':
            SysMgr.addPrint("{0:1}\n".format(oneLine))

        SysMgr.printTopStats()



    def saveFileStat(self, filters):
        # save proc and file instance #
        SysMgr.topInstance = self
        SysMgr.procInstance = self.procData
        SysMgr.fileInstance = self.fileData

        procFilter, fileFilter = filters

        # get process list #
        if procFilter:
            pids = SysMgr.convPidList(
                procFilter, isThread=True, inc=True)
            newPids = []
            for pid in pids:
                ret = SysMgr.getTgid(pid)
                if ret:
                    newPids.append(ret)
            pids = list(set(newPids))
        else:
            try:
                pids = os.listdir(SysMgr.procPath)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenErr(SysMgr.procPath)
                sys.exit(0)

        # remove myself info #
        try:
            del pids[pids.index(str(SysMgr.pid))]
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # get thread list #
        for pid in pids:
            try:
                long(pid)
                self.nrProcess += 1
            except:
                continue

            # make path of tid #
            procPath = "%s/%s" % (SysMgr.procPath, pid)
            fdlistPath = "%s/fd" % (procPath)

            # save stat of process #
            self.saveProcData(procPath, pid)

            # save file info per process #
            try:
                fdlist = os.listdir(fdlistPath)
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenWarn(fdlistPath)
                continue

            # save fd info of process #
            for fd in fdlist:
                try:
                    long(fd)
                    self.nrFd += 1
                except SystemExit:
                    sys.exit(0)
                except:
                    continue

                try:
                    # 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'] = long(0)
                        self.procData[pid]['fdInfo']['SOCKET'] = long(0)
                        self.procData[pid]['fdInfo']['DEVICE'] = long(0)
                        self.procData[pid]['fdInfo']['PIPE'] = long(0)
                        self.procData[pid]['fdInfo']['NORMAL'] = long(0)
                        self.procData[pid]['fdInfo']['PROC'] = long(0)

                    # increase type count per process #
                    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 saveZoneInfo(self):
        # save zone info #
        try:
            memBuf = None
            SysMgr.zoneFd.seek(0)
            memBuf = SysMgr.zoneFd.readlines()
        except:
            try:
                memPath = "%s/%s" % (SysMgr.procPath, 'zoneinfo')
                SysMgr.zoneFd = open(memPath, 'r')

                memBuf = SysMgr.zoneFd.readlines()
            except:
                SysMgr.printOpenWarn(memPath)

        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] = dict()
            elif item == 'pages' and zl[1] == 'free':
                self.zoneData[zone]['free'] = long(zl[2])
            elif item == 'min' or item == 'low' or item == 'high' or \
                item == 'spanned' or item == 'present' or item == 'managed':
                self.zoneData[zone][item] = long(zl[1])
            else:
                continue



    def saveIrqs(self):
        # save irq info #
        try:
            irqBuf = None
            SysMgr.irqFd.seek(0)
            irqBuf = SysMgr.irqFd.readlines()
        except SystemExit:
            sys.exit(0)
        except:
            try:
                irqPath = "%s/%s" % (SysMgr.procPath, 'interrupts')
                SysMgr.irqFd = open(irqPath, 'r')

                irqBuf = SysMgr.irqFd.readlines()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenWarn(irqPath)

        # save softirq info #
        try:
            sirqBuf = None
            SysMgr.softirqFd.seek(0)
            sirqBuf = SysMgr.softirqFd.readlines()
            irqBuf += sirqBuf[1:]
        except SystemExit:
            sys.exit(0)
        except:
            try:
                sirqPath = "%s/%s" % (SysMgr.procPath, 'softirqs')
                SysMgr.softirqFd = open(sirqPath, 'r')

                sirqBuf = SysMgr.softirqFd.readlines()
                irqBuf += sirqBuf[1:]
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenWarn(sirqPath)

        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, dict())
            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, dict())
                        root[sub][dpath][item] = stat
                    except SystemExit:
                        sys.exit(0)
                    except:
                        SysMgr.printWarn(
                            'fail 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:
            SysMgr.printOpenErr(SysMgr.cgroupPath)
            sys.exit(0)

        # 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.keys())
        else:
            # get process list #
            try:
                pids = os.listdir(SysMgr.procPath)
            except:
                SysMgr.printOpenErr(SysMgr.procPath)
                sys.exit(0)

        # 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 saveGenSystemInfo(self):
        # get psutil object #
        psutil = SysMgr.getPkg('psutil')

        '''
        python psutil APIs
        refer to https://psutil.readthedocs.io/en/latest
        '''

        # CPU #
        psutil.cpu_times(percpu=False)
        psutil.cpu_percent(interval=None, percpu=False)
        psutil.cpu_count(logical=True)
        psutil.cpu_stats()
        psutil.cpu_freq(percpu=False)
        psutil.getloadavg()

        # Memory #
        psutil.virtual_memory()
        psutil.swap_memory()

        # Disk #
        psutil.disk_partitions(all=False)
        #psutil.disk_usage(path=None)
        psutil.disk_io_counters(perdisk=False, nowrap=True)

        # Network #
        psutil.net_io_counters(pernic=False, nowrap=True)
        psutil.net_connections(kind='inet')
        psutil.net_if_addrs()
        psutil.net_if_stats()

        # ETC #
        psutil.sensors_temperatures(fahrenheit=False)
        psutil.sensors_fans()
        psutil.sensors_battery()
        psutil.users()

        # Process #
        psutil.process_iter(attrs=None, ad_value=None)
        psutil.pid_exists(pid=os.getpid())
        proc = psutil.Process(pid=None)
        procDict = proc.as_dict(attrs=None, ad_value=None)
        procMem = proc.memory_full_info()
        proc.is_running()
        proc.send_signal()
        proc.suspend()
        proc.resume()
        proc.terminate()
        proc.kill()
        proc.wait()



    def saveSystemStat(self, target='task'):
        # update uptime #
        SysMgr.updateUptime()

        # save CPU info #
        try:
            cpuBuf = None
            SysMgr.statFd.seek(0)
            cpuBuf = SysMgr.statFd.readlines()
        except SystemExit:
            sys.exit(0)
        except:
            try:
                cpuPath = "%s/stat" % SysMgr.procPath
                SysMgr.statFd = open(cpuPath, 'r')
                cpuBuf = SysMgr.statFd.readlines()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printErr(
                    'fail to read %s' % cpuPath, 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])}
                else:
                    if not cpuId in self.cpuData:
                        self.cpuData[cpuId] = {cpuId: long(statList[1])}

            # set the number of core #
            SysMgr.nrCore = long(0)
            for idx in list(self.cpuData.keys()):
                try:
                    SysMgr.maxCore = long(idx)
                    SysMgr.nrCore += 1
                except:
                    continue

        # save mem info #
        try:
            memBuf = None
            SysMgr.memFd.seek(0)
            memBuf = SysMgr.memFd.readlines()
        except SystemExit:
            sys.exit(0)
        except:
            try:
                memPath = "%s/%s" % (SysMgr.procPath, 'meminfo')
                SysMgr.memFd = open(memPath, 'r')

                memBuf = SysMgr.memFd.readlines()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenWarn(memPath)

        # parse meminfo data #
        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()

        if SysMgr.memEnable:
            self.saveZoneInfo()

        # save vmstat info #
        # vmstat list from https://access.redhat.com/solutions/406773 #
        try:
            vmBuf = None
            SysMgr.vmstatFd.seek(0)
            vmBuf = SysMgr.vmstatFd.readlines()
        except SystemExit:
            sys.exit(0)
        except:
            try:
                vmstatPath = "%s/%s" % (SysMgr.procPath, 'vmstat')
                SysMgr.vmstatFd = open(vmstatPath, 'r')

                vmBuf = SysMgr.vmstatFd.readlines()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenWarn(vmstatPath)

        # parse vmstat data #
        if vmBuf:
            self.prevVmData = self.vmData
            self.vmData = {}

            for line in vmBuf:
                vmList = line.split()
                self.vmData[vmList[0]] = long(vmList[1])

        # save swap info #
        try:
            swapBuf = None
            SysMgr.swapFd.seek(0)
            swapBuf = SysMgr.swapFd.readlines()
        except SystemExit:
            sys.exit(0)
        except:
            try:
                swapPath = "%s/%s" % (SysMgr.procPath, 'swaps')
                SysMgr.swapFd = open(swapPath, 'r')

                swapBuf = SysMgr.swapFd.readlines()
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenWarn(swapPath)

        # get swap usage if it changed #
        if self.prevSwaps != swapBuf and swapBuf:
            swapTotal = long(0)
            swapUsed = long(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'] = long(0)
                self.vmData['swapUsed'] = long(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)

        # save loadavg #
        try:
            SysMgr.loadavgFd.seek(0)
            SysMgr.loadavg = SysMgr.loadavgFd.readlines()[0]
        except SystemExit:
            sys.exit(0)
        except:
            try:
                loadavgPath = "%s/%s" % (SysMgr.procPath, 'loadavg')
                SysMgr.loadavgFd = open(loadavgPath, 'r')
                SysMgr.loadavg = SysMgr.loadavgFd.readlines()[0]
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printOpenWarn(loadavgPath)

        # collect perf data #
        if SysMgr.perfEnable:
            SysMgr.collectSystemPerfData()

        # save gpu stat #
        self.saveGpuData()

        # check atop mode #
        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(0)



    @staticmethod
    def getProcTreeFromList(procInstance):
        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
                    tmpid = procInstance[tmpid]['stat'][ppidIdx]

                    if 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 #
        starttimeIdx = ConfigMgr.STAT_ATTR.index("STARTTIME")
        for pid, item in sorted(procInstance.items(),
            key=lambda e: long(e[1]['stat'][starttimeIdx])):
            ppid = procInstance[pid]['stat'][ppidIdx]

            if ppid == '0':
                procTree[pid] = {}
            else:
                relationList = _getRelationList(pid, procInstance)
                _addItemsToList(relationList, procTree)

        return procTree



    @staticmethod
    def saveProcSmapsData(path, tid):
        # check root permission #
        if not SysMgr.isRoot():
            return

        buf = ''
        mtype = ''
        stable = {}
        ftable = {}
        isInaccessable = False
        fpath = '%s/%s' % (path, 'smaps')
        ptable = {'ANON': {}, 'FILE': {}, 'STACK': {}, 'ETC': {}, 'SHM': {}}

        checkCnt = long(0)
        checklist = ['Size:', 'Rss:', 'Pss:', 'Shared_Clean:',
            'Shared_Dirty:', 'Private_Dirty:', 'Referenced:',
            'AnonHugePages:', 'Swap:', 'Locked:']

        # share the map table for main thread #
        try:
            ppid = SysMgr.procInstance[tid]['mainID']
            if SysMgr.procInstance[ppid]['maps']:
                SysMgr.procInstance[tid]['maps'] = \
                    SysMgr.procInstance[ppid]['maps']
                return
        except:
            pass

        try:
            SysMgr.procInstance[tid]['maps'] = ptable
        except:
            SysMgr.printWarn('fail to find %s process' % tid)
            return

        try:
            with open(fpath, 'r') as fd:
                buf = fd.readlines()
        except:
            SysMgr.procInstance[tid]['maps'] = None
            SysMgr.printOpenWarn(fpath)
            return

        # check kernel thread #
        if not buf:
            return

        for line in buf:
            d = {}
            tmplist = line.split()

            # memory map info #
            if not line[0].isupper():
                checkCnt = long(0)

                d['range'] = tmplist[0]
                d['perm'] = tmplist[1]
                d['offset'] = tmplist[2]
                d['devid'] = tmplist[3]
                d['inode'] = tmplist[4]

                if len(tmplist) > 5:
                    ptype = tmplist[5]
                else:
                    ptype = ''

                # shared memory #
                if d['perm'][3] == 's':
                    mtype = 'SHM'
                    stable[ptype] = long(0)
                # file-mapped memory #
                elif ptype.startswith('/'):
                    mtype = 'FILE'
                    ftable[ptype] = long(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 #
                isInaccessable = d['perm'].startswith('---')

                try:
                    ptable[mtype]['count'] += 1
                except:
                    ptable[mtype]['count'] = long(1)
            # memory detail info #
            else:
                prop = tmplist[0]
                val = tmplist[1]

                try:
                    if checklist[checkCnt] == prop:
                        checkCnt += 1

                        val = long(val)
                        try:
                            ptable[mtype][prop] += val
                        except:
                            ptable[mtype][prop] = val

                        if isInaccessable:
                            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 = SysMgr.procInstance[tid]['mainID']
            SysMgr.procInstance[ppid]['maps'] = \
                SysMgr.procInstance[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] = dict()
                        self.gpuNameList[path] = 'NVIDIA'

                    # QUALCOMM #
                    if 'kgsl-3d0' in nodes:
                        name = '%s/%s/devfreq' % (path, 'kgsl-3d0')
                        candList[name] = dict()
                        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] = dict()
                    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] = dict()
                    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'] = long(0)
        self.procData[tid]['waitTime'] = long(0)

        if not SysMgr.schedstatEnable:
            return

        try:
            schedBuf = self.saveTaskData(path, tid, 'schedstat')
            if not schedBuf:
                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 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):
        buf = []

        try:
            fd = '%sFd' % name
            self.prevProcData[tid][fd].seek(0)
            self.procData[tid][fd] = self.prevProcData[tid][fd]
            buf = self.procData[tid][fd].readlines()
        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)

        if 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 = ''
        for item in cgroupBuf:
            clist = item[:-1].split(':')
            if len(clist) != 3 or clist[-1] == '/':
                continue
            cstr = '%s%s:%s, ' % (cstr, clist[1], clist[2])

        if len(cstr) > 0:
            self.procData[tid]['cgroup'] = cstr[:-2]



    def saveProcStatusData(self, path, tid):
        if not tid in self.procData:
            return

        stat = 'status'
        statusBuf = self.saveTaskData(path, tid, stat)
        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']
            del self.prevProcData[tid]['statusOrig']
        else:
            for line in statusBuf:
                try:
                    statusList = line.split(':')
                    self.procData[tid]['status'][statusList[0]] = \
                        statusList[1].strip()
                except:
                    pass

        stat = 'statm'
        mainID = self.procData[tid]['mainID']

        # kernel thread #
        if self.isKernelThread(tid):
            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):
            self.procData[tid]['statFd'] = open(path, 'rb')
            statBuf = self.procData[tid]['statFd'].read().decode()

            if tid in self.prevProcData:
                self.prevProcData[tid]['alive'] = True

            # fd resource is about to run out #
            if SysMgr.maxKeepFd < \
                self.procData[tid]['statFd'].fileno():
                self.procData[tid]['statFd'].close()
                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:
            if tid in self.prevProcData and \
                'statFd' in self.prevProcData[tid] and \
                self.prevProcData[tid]['statFd']:
                self.prevProcData[tid]['statFd'].seek(0)
                self.procData[tid]['statFd'] = self.prevProcData[tid]['statFd']
                statBuf = self.procData[tid]['statFd'].read().decode()
                self.prevProcData[tid]['alive'] = True
            else:
                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.split()

            # 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][1:-1]

        # 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')
            self.procData[tid]['ioData'] = ioBuf

            # check I/O data #
            if tid in self.prevProcData and \
                self.prevProcData[tid]['ioData'] == ioBuf:
                self.procData[tid]['io'] = self.prevProcData[tid]['io']
            else:
                self.procData[tid]['io'] = {}
                for line in ioBuf:
                    line = line.split()
                    item = line[0]
                    if item != 'read_bytes:' and item != 'write_bytes:':
                        continue
                    self.procData[tid]['io'][item[:-1]] = long(line[1])

        # 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):
        nsPath = "%s/%s" % (path, 'ns')
        try:
            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

                    value = value[1:-1]

                    if not node in self.nsData:
                        self.nsData[node] = {}

                    if not value in self.nsData[node]:
                        self.nsData[node][value] = {tid: 0}
                    else:
                        self.nsData[node][value][tid] = 0
        except SystemExit:
            sys.exit(0)
        except:
            comm = self.procData[tid]['stat'][self.commIdx][1:-1]
            SysMgr.printWarn(
                'fail to read namespace value for %s(%s)' % \
                    (comm, tid), reason=True)



    def updateOOMScore(self, path, tid):
        # check main thread to remove redundant operation #
        if SysMgr.checkMode('ttop'):
            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 = long(0)
        for pid, val in sorted(
            self.procData.items(), key=lambda x:int(x[0])):
            for item in val.keys():
                if not item.endswith('Fd'):
                    continue

                # close file descriptors #
                try:
                    val[item].close()
                    val[item] = None
                    nrRclm += 1
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

            if nrRclm >= nrReq:
                return nrRclm



    def printSystemUsage(self):
        vmData = self.vmData
        prevVmData = self.prevVmData
        memData = self.memData
        prevMemData = self.prevMemData

        # total memory #
        try:
            totalMem = memData['MemTotal'] >> 10
        except SystemExit:
            sys.exit(0)
        except:
            totalMem = long(0)
            SysMgr.printWarn("fail to get totalMem")

        # free memory #
        try:
            freeMem = memData['MemFree'] >> 10
            freeMemDiff = freeMem - (prevMemData['MemFree'] >> 10)
        except SystemExit:
            sys.exit(0)
        except:
            freeMem = freeMemDiff = long(0)
            SysMgr.printWarn("fail to get freeMem")

        # 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 = long(0)

            availMemPer = long(availMem / float(totalMem) * 100)
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.freeMemEnable = True
            availMem = availMemDiff = long(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
        except SystemExit:
            sys.exit(0)
        except:
            actAnonMem = inactAnonMem = totalAnonMem = anonMemDiff = long(0)
            SysMgr.printWarn("fail to get anonMem")

        # 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
        except SystemExit:
            sys.exit(0)
        except:
            actFileMem = inactFileMem = totalFileMem = fileMemDiff = long(0)
            SysMgr.printWarn("fail to get fileMem")

        # 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 = long(0)
            SysMgr.printWarn("fail to get dirtyMem")

        # 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
        except SystemExit:
            sys.exit(0)
        except:
            slabReclm = slabUnReclm = slabReclmDiff = \
                slabUnReclmDiff = totalSlabMem = slabMemDiff = long(0)
            SysMgr.printWarn("fail to get slabMem")

        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 = long(0)
            SysMgr.printWarn("fail to get faultMem")

        # paged in/out from/to disk #
        try:
            pgInMemDiff = \
                (vmData['pgpgin'] - self.prevVmData['pgpgin']) >> 10
            pgOutMemDiff = \
                (vmData['pgpgout'] - self.prevVmData['pgpgout']) >> 10
        except SystemExit:
            sys.exit(0)
        except:
            pgInMemDiff = pgOutMemDiff = long(0)
            SysMgr.printWarn("fail to get pgMem")

        # swap memory #
        try:
            swapTotal = vmData['swapTotal'] >> 10
            swapUsage = vmData['swapUsed'] >> 10
            swapFree = swapTotal - swapUsage
            if swapTotal:
                swapUsagePer = long(swapUsage / float(swapTotal) * 100)
            else:
                swapUsagePer = 0
            swapUsageDiff = \
                (self.prevVmData['swapUsed'] - vmData['swapUsed']) >> 10
            swapInMem = \
                (vmData['pswpin'] - self.prevVmData['pswpin']) >> 10
            swapOutMem = \
                (vmData['pswpout'] - self.prevVmData['pswpout']) >> 10
        except SystemExit:
            sys.exit(0)
        except:
            swapTotal = swapUsage = swapUsageDiff = swapUsagePer = \
                swapInMem = swapOutMem = long(0)
            SysMgr.printWarn("fail to get swapMem")

        # background reclaim #
        try:
            pgRclmBg = long(0)
            if 'pgsteal_kswapd' in vmData:
                pgRclmBg += \
                    vmData['pgsteal_kswapd'] - \
                    self.prevVmData['pgsteal_kswapd']
            if 'pgsteal_kswapd_normal' in vmData:
                pgRclmBg += \
                    vmData['pgsteal_kswapd_normal'] - \
                    self.prevVmData['pgsteal_kswapd_normal']
            if 'pgsteal_kswapd_high' in vmData:
                pgRclmBg += \
                    vmData['pgsteal_kswapd_high'] - \
                    self.prevVmData['pgsteal_kswapd_high']
            if 'pgsteal_kswapd_dma' in vmData:
                pgRclmBg += \
                    vmData['pgsteal_kswapd_dma'] - \
                    self.prevVmData['pgsteal_kswapd_dma']
            if 'pgsteal_kswapd_dma32' in vmData:
                pgRclmBg += \
                    vmData['pgsteal_kswapd_dma32'] - \
                    self.prevVmData['pgsteal_kswapd_dma32']
            if 'pgsteal_kswapd_movable' in vmData:
                pgRclmBg += \
                    vmData['pgsteal_kswapd_movable'] - \
                    self.prevVmData['pgsteal_kswapd_movable']

            # convert to MB #
            #pgRclmBg = pgRclmBg >> 8

            try:
                nrBgReclaim = \
                    vmData['pageoutrun'] - \
                    self.prevVmData['pageoutrun']
            except SystemExit:
                sys.exit(0)
            except:
                nrBgReclaim = long(0)
        except SystemExit:
            sys.exit(0)
        except:
            pgRclmBg = nrBgReclaim = long(0)
            SysMgr.printWarn("fail to get bgReclmMem")

        # direct reclaim #
        try:
            pgRclmFg = long(0)
            if 'pgsteal_direct' in vmData:
                pgRclmFg += \
                    vmData['pgsteal_direct'] - \
                    self.prevVmData['pgsteal_direct']
            if 'pgsteal_direct_normal' in vmData:
                pgRclmFg += \
                    vmData['pgsteal_direct_normal'] - \
                    self.prevVmData['pgsteal_direct_normal']
            if 'pgsteal_direct_high' in vmData:
                pgRclmFg += \
                    vmData['pgsteal_direct_high'] - \
                    self.prevVmData['pgsteal_direct_high']
            if 'pgsteal_direct_dma' in vmData:
                pgRclmFg += \
                    vmData['pgsteal_direct_dma'] - \
                    self.prevVmData['pgsteal_direct_dma']
            if 'pgsteal_direct_dma32' in vmData:
                pgRclmFg += \
                    vmData['pgsteal_direct_dma32'] - \
                    self.prevVmData['pgsteal_direct_dma32']
            if 'pgsteal_direct_movable' in vmData:
                pgRclmFg += \
                    vmData['pgsteal_direct_movable'] - \
                    self.prevVmData['pgsteal_direct_movable']

            # convert to MB #
            #pgRclmFg = pgRclmFg >> 8

            try:
                nrDrReclaim = \
                    vmData['allocstall'] - self.prevVmData['allocstall']
            except SystemExit:
                sys.exit(0)
            except:
                nrDrReclaim = long(0)
        except SystemExit:
            sys.exit(0)
        except:
            pgRclmFg = nrDrReclaim = long(0)
            SysMgr.printWarn("fail to get drReclmMem")


        # mlock #
        try:
            pgMlock = vmData['nr_mlock']
            #mappedMem = vmData['nr_mapped'] >> 8
        except:
            pgMlock = long(0)
            SysMgr.printWarn("fail to get mlockMem")

        # pending #
        try:
            nrBlocked = self.cpuData['procs_blocked']['procs_blocked']
        except:
            nrBlocked = long(0)
            SysMgr.printWarn("fail to get nrBlocked")

        # cma mem #
        try:
            if 'CmaTotal' in memData:
                cmaTotalMem = memData['CmaTotal']

                if 'CmaFree' in memData:
                    cmaFreeMem = memData['CmaFree']
                else:
                    cmaFreeMem = long(0)
                if 'CmaDeviceAlloc' in memData:
                    cmaDevMem = memData['CmaDeviceAlloc']
                else:
                    cmaDevMem = long(0)
            else:
                cmaTotalMem = long(0)
        except SystemExit:
            sys.exit(0)
        except:
            cmaTotalMem = cmaFreeMem = cmaDevMem = long(0)
            SysMgr.printWarn("fail to get cmaMem")

        try:
            pass
            '''
            shMem = vmData['nr_shmem'] >> 8
            pageTableMem = vmData['nr_page_table_pages'] >> 8
            kernelStackMem = vmData['nr_kernel_stack'] * 8 >> 10
            '''
        except:
            SysMgr.printWarn("fail to get etcMem")

        # check available memory type #
        if SysMgr.freeMemEnable:
            memTitle = 'MemFre'
        else:
            memTitle = 'MemAvl'

        # get iowait time #
        #iowait = SysMgr.getIowaitTime()

        # print system status menu #
        SysMgr.addPrint(
            ("%s\n%s%s\n" % (twoLine,
            (("{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")), oneLine)),
            newline = 3)

        interval = SysMgr.uptimeDiff
        if interval == 0:
            return

        try:
            nrCtxSwc = \
                self.cpuData['ctxt']['ctxt'] - \
                self.prevCpuData['ctxt']['ctxt']
        except SystemExit:
            sys.exit(0)
        except:
            nrCtxSwc = long(0)

        try:
            nrIrq = \
                self.cpuData['intr']['intr'] - \
                self.prevCpuData['intr']['intr']
        except SystemExit:
            sys.exit(0)
        except:
            nrIrq = long(0)

        try:
            nrSoftIrq = \
                self.cpuData['softirq']['softirq'] - \
                self.prevCpuData['softirq']['softirq']
        except SystemExit:
            sys.exit(0)
        except:
            nrSoftIrq = long(0)

        # get total CPU usage #
        try:
            nowData = self.cpuData['all']
            prevData = self.prevCpuData['all']
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printErr(
                "fail 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 = long(0)
        coreStats = dict()

        for idx in list(self.cpuData.keys()):
            try:
                nowData = self.cpuData[int(idx)]

                if not long(idx) 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

                prevData = self.prevCpuData[int(idx)]

                coreStats[idx] = dict()

                #-------------------- 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 --------------------#
                # 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']
            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 idleUsage < maxUsage:
            totalUsage = maxUsage - idleUsage - ioUsage
        else:
            totalUsage = long(0)

        # add CPU interval #
        self.addSysInterval('cpu', totalUsage)

        # get network usage in bytes #
        (netIn, netOut) = \
            self.getNetworkUsage(SysMgr.prevNetstat, SysMgr.netstat)

        # add network interval #
        self.addSysInterval('inbound', netIn)
        self.addSysInterval('outbound', netOut)

        # convert network usage #
        try:
            netIO = '%s/%s' % \
                (UtilMgr.convSize2Unit(netIn, True),
                    UtilMgr.convSize2Unit(netOut, True))
        except SystemExit:
            sys.exit(0)
        except:
            netIO = '-/-'

        # check available memory #
        if availMem == 0:
            availMem = freeMem
            availMemDiff = freeMemDiff

        # add memory interval #
        self.addSysInterval('available', availMem)

        # convert color for CPU usage #
        totalUsageStr = r'%3s %%' % totalUsage
        if totalUsage == 0:
            pass
        elif totalUsage >= SysMgr.cpuPerHighThreshold:
            totalUsageStr = UtilMgr.convColor(totalUsageStr, 'RED')
        else:
            totalUsageStr = UtilMgr.convColor(totalUsageStr, 'YELLOW')

        # convert color for mem available #
        availMemStr = r'%6s' % availMem
        if availMemPer == 0:
            pass
        elif availMemPer <= SysMgr.memAvailPerThreshold:
            availMemStr = UtilMgr.convColor(availMemStr, 'RED')
        else:
            availMemStr = UtilMgr.convColor(availMemStr, 'YELLOW')

        # convert color for swap usage #
        swapUsageStr = r'%5s' % swapUsage
        if swapUsagePer == 0:
            pass
        elif swapUsagePer >= SysMgr.swapPerThreshold:
            swapUsageStr = UtilMgr.convColor(swapUsageStr, 'RED')
        else:
            swapUsageStr = UtilMgr.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 = UtilMgr.convColor(pgRclmStr, 'RED')

        # convert color for io stats #
        pgIOMemDiffStr = r'%s/%s' % (pgInMemDiff, pgOutMemDiff)
        pgIOMemDiffStr = r'{0:^7}'.format(pgIOMemDiffStr)
        if pgInMemDiff > 0 or pgOutMemDiff > 0:
            pgIOMemDiffStr = UtilMgr.convColor(pgIOMemDiffStr, 'RED')

        # convert color for network stats #
        if not (netIO == '-/-' or netIO == '0/0'):
            netIO = r'{0:^12}'.format(netIO)
            netIO = UtilMgr.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,
            ioUsage, 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 temperature #
        if SysMgr.cpuEnable or SysMgr.gpuEnable:
            coreTempData = {}
            tempDirList = []
            tempPath = '/sys/class/hwmon'

            try:
                self.tempFdList
            except:
                self.tempFdList = dict()

            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:
                tempDirList = \
                    [ '%s/%s' % (hwPath, item.replace('input', 'label')) \
                    for item in os.listdir(hwPath) if item.endswith('_input') ]
                phyId = long(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 #
        if SysMgr.cpuEnable or SysMgr.reportEnable or SysMgr.jsonEnable:
            shortCoreStats = ''
            percoreStats = {}
            lenCoreStat = 0

            if len(self.cpuData) > 0:
                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

            # traverse core files #
            for idx in list(self.cpuData.keys()):
                try:
                    curCore = long(idx)
                    percoreStats[curCore] = dict()

                    if SysMgr.checkCutCond():
                        return

                    # 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 idleCoreUsage < 100:
                        totalCoreUsage = 100 - idleCoreUsage - ioCoreUsage
                    else:
                        totalCoreUsage = long(0)

                    # limit total core usage in each modes #
                    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

                    if totalCoreUsage == 0:
                        totalCoreUsageStr = totalCoreUsage
                    elif totalCoreUsage >= SysMgr.cpuPerHighThreshold:
                        totalCoreUsageStr = UtilMgr.convColor(
                            totalCoreUsage, 'RED', 3)
                    else:
                        totalCoreUsageStr = UtilMgr.convColor(
                            totalCoreUsage, 'YELLOW', 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

                # 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:
                    self.prevCpuData[idx]['curFd'].seek(0)
                    curFreq = self.prevCpuData[idx]['curFd'].readline()[:-1]
                    self.cpuData[idx]['curFd'] = \
                        self.prevCpuData[idx]['curFd']
                    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:
                        self.cpuData[idx]['curFd'] = open(curPath, 'r')
                        curFreq = self.cpuData[idx]['curFd'].readline()[:-1]
                        percoreStats[idx]['curFreq'] = curFreq
                    except SystemExit:
                        sys.exit(0)
                    except:
                        curFreq = None

                # get CPU min frequency #
                try:
                    self.prevCpuData[idx]['minFd'].seek(0)
                    minFreq = self.prevCpuData[idx]['minFd'].readline()[:-1]
                    self.cpuData[idx]['minFd'] = \
                        self.prevCpuData[idx]['minFd']
                    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:
                        self.cpuData[idx]['minFd'] = open(minPath, 'r')
                        minFreq = self.cpuData[idx]['minFd'].readline()[:-1]
                        percoreStats[idx]['minFreq'] = minFreq
                    except SystemExit:
                        sys.exit(0)
                    except:
                        minFreq = None

                # get CPU max frequency #
                try:
                    self.prevCpuData[idx]['maxFd'].seek(0)
                    maxFreq = self.prevCpuData[idx]['maxFd'].readline()[:-1]
                    self.cpuData[idx]['maxFd'] = \
                        self.prevCpuData[idx]['maxFd']
                    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:
                        self.cpuData[idx]['maxFd'] = open(maxPath, 'r')
                        maxFreq = self.cpuData[idx]['maxFd'].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 core 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)

                        self.cpuData[idx]['cidFd'] = open(cidPath, 'r')
                        coreId = \
                            long(self.cpuData[idx]['cidFd'].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)

                        self.cpuData[idx]['pidFd'] = open(pidPath, 'r')
                        phyId = \
                            long(self.cpuData[idx]['pidFd'].readline()[:-1])

                    if phyId < 0:
                        phyId = '?'

                    cid = '%s-%s' % (phyId, coreId)
                    percoreStats[idx]['id'] = cid
                except SystemExit:
                    sys.exit(0)
                except:
                    cid = None
                    percoreStats[idx]['id'] = None

                # set frequency info #
                try:
                    coreFreq = ''
                    if curFreq:
                        coreFreq = '%d Mhz' % (long(curFreq) >> 10)
                    else:
                        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 core 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:
                        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 = UtilMgr.getRealLen(coreStat)

                    # use short core stats for many-core system #
                    if not SysMgr.barGraphEnable and SysMgr.nrCore > 8:
                        shortCoreStats += coreStat
                        coreFactor = long(maxCols / lenCoreStat)
                        if (curCore+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 totalCoreUsage > 0:
                        coreGraph = '#' * long(lenLine * totalCoreUsage / 100)
                        coreGraph += (' ' * (lenLine - len(coreGraph)))

                        if totalCoreUsage >= SysMgr.cpuPerHighThreshold:
                            coreGraph = UtilMgr.convColor(coreGraph, 'RED')
                        else:
                            coreGraph = UtilMgr.convColor(coreGraph, 'YELLOW')
                    else:
                        coreGraph = ' ' * lenLine

                    SysMgr.addPrint(
                        '%s%s| %s\n' % (coreStat, coreGraph, coreFreq))
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

        # print GPU stats #
        if SysMgr.gpuEnable:
            gpuStats = {}

            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)
                        if totalGpuUsage >= SysMgr.cpuPerHighThreshold:
                            totalGpuUsageStr = UtilMgr.convColor(
                                totalGpuUsageStr, 'RED')
                        else:
                            totalGpuUsageStr = UtilMgr.convColor(
                                totalGpuUsageStr, 'YELLOW')

                    coreStat = "{0:<23}({1:>5})|".format(
                        idx[:23], totalGpuUsageStr)

                    gpuStats[idx] = totalGpuUsage

                    # set frequency info #
                    try:
                        coreFreq = '%d Mhz' % value['CUR_FREQ']
                    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 temperature info #
                    try:
                        coreFreq = '%3s C | %s' % (value['TEMP'], coreFreq)
                    except:
                        try:
                            coreFreq = '%3s C | %s' % \
                                (coreTempData['GPU'], coreFreq)
                        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

                        if totalGpuUsage >= SysMgr.cpuPerHighThreshold:
                            coreGraph = UtilMgr.convColor(coreGraph, 'RED')
                        else:
                            coreGraph = UtilMgr.convColor(coreGraph, 'YELLOW')

                        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 #
        self.reportData = dict()

        # timestamp #
        self.reportData['timestamp'] = SysMgr.uptime
        datetime = SysMgr.getPkg('datetime', False)
        if datetime:
            self.reportData['utctime'] = \
                datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%SZ')

        # system #
        self.reportData['system'] = {
            'pid': SysMgr.pid,
            'uptime': SysMgr.uptime,
            'interval': interval,
            'nrIrq': nrIrq,
            'nrSoftIrq': nrSoftIrq,
            'os': SysMgr.sysInstance.uname[0],
            'host': SysMgr.sysInstance.uname[1],
            'kernel': SysMgr.sysInstance.uname[2],
            'release': SysMgr.sysInstance.uname[3],
            }

        # 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

        # CPU #
        try:
            percoreStats
        except:
            percoreStats = None

        self.reportData['cpu'] = {
            'total': totalUsage,
            'idle': idleUsage,
            'user': userUsage,
            'kernel': kerUsage,
            'irq': irqUsage,
            'iowait': ioUsage,
            'nrCore': SysMgr.nrCore,
            'percore': percoreStats
            }

        # gpu #
        try:
            self.reportData['gpu'] = gpuStats
        except:
            pass

        # 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
            }

        if SysMgr.sysInstance.macAddr:
            macAddr = SysMgr.sysInstance.macAddr
            macStr = '%s_%s' % (macAddr[0], macAddr[1])
            self.reportData['net']['repmac'] = macStr

        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] = dict()
                reportData = self.reportData['net'][dev]

                reportData['ipaddr'] = value['ipaddr']

                rdiff = value['rdiff']
                tdiff = value['tdiff']

                reportData['trans'] = {
                    '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['recv'] = {
                    'bytes': tdiff[0],
                    'packets': tdiff[1],
                    'errs': tdiff[2],
                    'drop': tdiff[3],
                    'fifo': tdiff[4],
                    'frame': tdiff[5],
                    'compressed': tdiff[6],
                    'multicast': tdiff[7]
                    }

        # storage #
        if SysMgr.diskEnable:
            SysMgr.sysInstance.updateStorageInfo()

            # copy storage data into report data structure #
            self.reportData['storage'] = \
                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()):
                # get read size on this interval #
                try:
                    value['read'] -= prevStorageData[dev]['read']
                except:
                    value['read'] = long(0)

                # get write size on this interval #
                try:
                    value['write'] -= prevStorageData[dev]['write']
                except:
                    value['write'] = long(0)

                # get readtime on this interval #
                try:
                    value['readtime'] -= prevStorageData[dev]['readtime']
                except:
                    value['readtime'] = long(0)

                # get writetime on this interval #
                try:
                    value['writetime'] -= prevStorageData[dev]['writetime']
                except:
                    value['writetime'] = long(0)

                # get iotime on this interval #
                try:
                    value['iotime'] -= prevStorageData[dev]['iotime']
                except:
                    value['iotime'] = long(0)

                # get iowtime on this interval #
                try:
                    value['iowtime'] -= prevStorageData[dev]['iowtime']
                except:
                    value['iowtime'] = long(0)

                # get avq on this interval #
                try:
                    value['avq'] = value['iowtime'] / value['iotime']
                except:
                    value['avq'] = long(0)
        else:
            self.reportData['storage'] = dict()

        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(
                    pid, value, 'rssInterval', 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 io #
                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']

                # check stat change #
                if not value['changed']:
                    value['utime'] = value['stime'] = value['ttime'] = \
                        value['btime'] = value['cttime'] = long(0)

                    # add CPU interval #
                    self.addProcInterval(
                        pid, value, 'cpuInterval', 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'] = long(0)

                # add CPU interval #
                self.addProcInterval(
                    pid, value, 'cpuInterval', 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'] = long(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 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 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 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 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']

            # check delayacct_blkio_ticks error #
            if value['btime'] >= 100:
                value['btime'] = long(0)



    def getMemDetails(self, idx, maps):
        rss = long(0)
        sss = long(0)
        pss = long(0)
        memBuf = []

        if not maps:
            return [], 0, 0, 0

        convertFunc = UtilMgr.convSize2Unit

        for key, item in sorted(maps.items(), reverse=True):
            tmpstr = ''

            if not item or item['count'] == 0:
                continue

            try:
                prop = 'Size:'
                tmpstr = "%s%s%7s / " % \
                    (tmpstr, "VSS:", convertFunc(item[prop] << 10))
            except:
                tmpstr = "%s%s%7s / " % (tmpstr, prop.upper(), 0)

            try:
                prop = 'Rss:'
                tmpstr = "%s%s%7s / " % \
                    (tmpstr, prop.upper(), convertFunc(item[prop] << 10))
                rss += item[prop]
            except:
                tmpstr = "%s%s%7s / " % (tmpstr, prop.upper(), 0)

            try:
                prop = 'Pss:'
                tmpstr = "%s%s%7s / " % \
                    (tmpstr, prop.upper(), convertFunc(item[prop] << 10))
                pss += item[prop]
            except:
                tmpstr = "%s%s%7s / " % (tmpstr, prop.upper(), 0)

            try:
                prop = 'Swap:'
                tmpstr = "%s%s%7s / " % \
                    (tmpstr, prop.upper(), convertFunc(item[prop] << 10))
            except:
                tmpstr = "%s%s%7s / " % (tmpstr, prop.upper(), 0)

            try:
                prop = 'AnonHugePages:'
                tmpstr = "%s%s:%5s / " % \
                    (tmpstr, 'HUGE', convertFunc(item[prop] << 10, True))
            except:
                tmpstr = "%s%s:%5s / " % (tmpstr, 'HUGE', 0)

            try:
                prop = 'Locked:'
                tmpstr = "%s%s%6s / " % \
                    (tmpstr, 'LOCK:', convertFunc(item[prop] << 10, True))
            except:
                tmpstr = "%s%s%6s / " % (tmpstr, 'LOCK:', 0)

            try:
                prop = 'Shared_Clean:'
                sss += item[prop]
            except:
                pass

            try:
                prop = 'Shared_Dirty:'
                sss += item[prop]
                tmpstr = "%s%s:%7s / " % \
                    (tmpstr, 'SDRT', convertFunc(item[prop] << 10))
            except:
                tmpstr = "%s%s:%7s / " % (tmpstr, 'SDRT', 0)

            try:
                prop = 'Private_Dirty:'
                tmpstr = "%s%s:%7s" % \
                    (tmpstr, 'PDRT', convertFunc(item[prop] << 10))
            except:
                tmpstr = "%s%s:%7s" % (tmpstr, 'PDRT', 0)

            '''
            try:
                prop = 'NOPM'
                tmpstr = "%s%s:%5s" % \
                    (tmpstr, prop, convertFunc(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:
                    wss =  convertFunc(item['Referenced:'] << 10, False)
                except:
                    wss =  0

                # get previous WSS history #
                try:
                    self.procData[idx]['wss'] = \
                        self.prevProcData[idx]['wss']
                except:
                    self.procData[idx].setdefault('wss', dict())

                    # clear reference bits #
                    try:
                        path = '%s/%s/clear_refs' % \
                            (SysMgr.procPath, idx)
                        with open(path, 'w') as fd:
                            fd.write('1')
                    except:
                        pass

                # update WSS history #
                try:
                    history = self.procData[idx]['wss'][key]
                    self.procData[idx]['wss'][key] = \
                        '%s -> %7s' % (history, wss)
                except:
                    self.procData[idx]['wss'][key] = '[%7s]' % wss

        # update pss #
        pss = pss >> 2

        # update uss #
        uss = (rss - sss) >> 2

        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:
            loadlist = SysMgr.loadavg.split()[:3]
            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 = long(0)

        try:
            nrCtxt = \
                self.cpuData['ctxt']['ctxt'] - self.prevCpuData['ctxt']['ctxt']
        except SystemExit:
            sys.exit(0)
        except:
            nrCtxt = long(0)

        try:
            nrTermThreads = \
                abs(self.nrThread - nrNewThreads - self.nrPrevThread)
        except SystemExit:
            sys.exit(0)
        except:
            nrTermThreads = long(0)

        try:
            nrIrq = \
                self.cpuData['intr']['intr'] - self.prevCpuData['intr']['intr']
        except SystemExit:
            sys.exit(0)
        except:
            nrIrq = long(0)

        try:
            memTotal = UtilMgr.convSize2Unit(
                self.memData['MemTotal'] << 10)
        except SystemExit:
            sys.exit(0)
        except:
            memTotal = long(0)

        try:
            swapTotal = UtilMgr.convSize2Unit(
                self.memData['SwapTotal'] << 10)
        except SystemExit:
            sys.exit(0)
        except:
            swapTotal = long(0)

        # add JSON stats #
        if SysMgr.jsonEnable:
            SysMgr.jsonData.setdefault('system', dict())
            jsonData = SysMgr.jsonData['system']

            jsonData['uptime'] = SysMgr.uptime
            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

        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]\n") % \
            (title, SysMgr.uptime, SysMgr.uptimeDiff,
            nrCtxt, nrNewThreads, nrTermThreads, oomstr, nrIrq,
            SysMgr.nrCore, self.nrProcess, self.nrThread, loadavg,
            memTotal, swapTotal), 'BOLD'))



    def printZoneUsage(self, nrIndent):
        if not self.zoneData:
            return

        nrZone = long(0)
        zoneData = '%s [Node %s > ' % (' ' * nrIndent, 0)
        lenZone = len(zoneData)

        # add JSON stats #
        if SysMgr.jsonEnable:
            SysMgr.jsonData.setdefault('zone', dict())

        for node, items in sorted(self.zoneData.items()):
            zoneData = '%s [%-10s > ' % (' ' * nrIndent, 'N%s' % node)
            lenZone = len(zoneData)
            nrZone += 1

            for info, val in sorted(items.items()):
                if SysMgr.jsonEnable:
                    SysMgr.jsonData['zone'].setdefault(node, dict())

                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]

                    diff = UtilMgr.convSize2Unit(diff << 12)
                    ninfo = 'diff'

                    if SysMgr.jsonEnable:
                        SysMgr.jsonData['zone'][node][ninfo] = diff

                    zoneStat = '%s: %7s / ' % (ninfo, diff)
                    lenZoneStat = len(zoneStat)

                    if lenZone + lenZoneStat >= len(oneLine):
                        zoneData = '%s\n%s %s' % \
                            (zoneData, ' ' * 7, ' ' * nrIndent)
                        lenZone = nrIndent

                    zoneData = '%s%s' % (zoneData, zoneStat)
                    lenZone += lenZoneStat

                stat = UtilMgr.convSize2Unit(val << 12)

                if SysMgr.jsonEnable:
                    SysMgr.jsonData['zone'][node][info] = stat
                    continue

                zoneStat = '%s: %6s / ' % (info, stat)
                lenZoneStat = len(zoneStat)

                if lenZone + lenZoneStat >= len(oneLine):
                    zoneData = '%s\n%s %s' % \
                        (zoneData, ' ' * 7, ' ' * nrIndent)
                    lenZone = nrIndent

                zoneData = '%s%s' % (zoneData, zoneStat)
                lenZone += lenZoneStat

            SysMgr.addPrint("{0:<1}]\n".format(zoneData[:-2]))



    def printIrqUsage(self, nrIndent):
        if not self.irqData:
            return

        nrIrq = long(0)
        irqData = '%s [IRQ > ' % (' ' * nrIndent)
        lenIrq = len(irqData)

        # add JSON stats #
        if SysMgr.jsonEnable:
            SysMgr.jsonData.setdefault('irq', dict())

        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 lenIrq + lenNewIrq >= len(oneLine):
                irqData = '%s\n%s %s' % (irqData, ' ' * 7, ' ' * nrIndent)
                lenIrq = nrIndent

            irqData = '%s%s' % (irqData, newIrq)
            lenIrq += lenNewIrq

        if nrIrq > 0:
            SysMgr.addPrint("{0:<1}]\n".format(irqData[:-2]))



    def printPerfUsage(self, nrIndent):
        if not SysMgr.perfEventData:
            return

        perfString = SysMgr.getPerfString(SysMgr.perfEventData)
        if len(perfString) > 0:
            SysMgr.addPrint("%s %s\n" % (' ' * nrIndent, perfString))

            # add JSON stats #
            if SysMgr.jsonEnable:
                SysMgr.jsonData.setdefault('PMU', dict())
                jsonData = SysMgr.jsonData['PMU']

                plist = perfString[1:-1].split(' / ')
                for stat in plist:
                    metric, value = stat.split(':')
                    jsonData['PMU'][metric] = value.strip()



    def printNetworkUsage(self):
        if not SysMgr.networkEnable:
            return
        elif SysMgr.uptimeDiff == 0:
            return
        elif SysMgr.checkCutCond():
            return

        # update network usage #
        SysMgr.sysInstance.updateNetworkInfo()

        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)

        convertFunc = UtilMgr.convSize2Unit

        if SysMgr.jsonEnable:
            SysMgr.jsonData.setdefault('net', dict())

        cnt = long(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]

                # convert color for network usage #
                recvSize = '%8s' % convertFunc(rdiff[0])
                if rdiff[0] > 0:
                    recvSize = '%s' % UtilMgr.convColor(recvSize, 'YELLOW')
                tranSize = '%8s' % convertFunc(tdiff[0])
                if tdiff[0] > 0:
                    tranSize = '%s' % UtilMgr.convColor(tranSize, 'YELLOW')

                # convert color for network error #
                recvErr = '%8s' % convertFunc(rdiff[2])
                if rdiff[2] > 0:
                    recvErr = '%s' % UtilMgr.convColor(recvErr, 'RED')
                tranErr = '%8s' % convertFunc(tdiff[2])
                if tdiff[2] > 0:
                    tranErr = '%s' % 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, val['ipaddr'],
                        recvSize, convertFunc(rdiff[1]), recvErr,
                        convertFunc(rdiff[3]), convertFunc(rdiff[-1]),
                        tranSize, convertFunc(tdiff[1]), tranErr,
                        convertFunc(tdiff[3]), convertFunc(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' % convertFunc(rdiff[0])
            if rdiff[0] > 0:
                recvSize = '%s' % UtilMgr.convColor(recvSize, 'YELLOW')
            tranSize = '%8s' % convertFunc(tdiff[0])
            if tdiff[0] > 0:
                tranSize = '%s' % UtilMgr.convColor(tranSize, 'YELLOW')

            # convert color for network error #
            recvErr = '%8s' % convertFunc(rdiff[2])
            if rdiff[2] > 0:
                recvErr = '%s' % UtilMgr.convColor(recvErr, 'RED')
            tranErr = '%8s' % convertFunc(tdiff[2])
            if tdiff[2] > 0:
                tranErr = '%s' % 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, convertFunc(rdiff[1]), recvErr,
                    convertFunc(rdiff[3]), convertFunc(rdiff[-1]),
                    tranSize, convertFunc(tdiff[1]), tranErr,
                    convertFunc(tdiff[3]), convertFunc(tdiff[-1])))



    def printDiskUsage(self):
        if not SysMgr.diskEnable:
            return
        elif SysMgr.uptimeDiff == 0:
            return
        elif SysMgr.checkCutCond():
            return

        # update storage usage #
        SysMgr.sysInstance.updateStorageInfo()

        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', dict())

        printCnt = long(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

            origDev = dev
            if 'mount' in value and \
                value['mount']['fs'] == 'tmpfs':
                dev = value['mount']['path']

            # get readtime #
            try:
                readtime = value['readtime'] - \
                    prevStorageData[origDev]['readtime']
            except SystemExit:
                sys.exit(0)
            except:
                readtime = long(0)

            # get writetime #
            try:
                writetime = value['writetime'] - \
                    prevStorageData[origDev]['writetime']
            except SystemExit:
                sys.exit(0)
            except:
                writetime = long(0)

            # get busytime #
            try:
                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 = '%s' % UtilMgr.convColor(busytime, 'RED')
            except SystemExit:
                sys.exit(0)
            except:
                busytime = '0%'

            # get avq #
            try:
                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:
                readSize = value['read'] - \
                    prevStorageData[origDev]['read']

                readSize = convSize2Unit(readSize << 20)
            except SystemExit:
                sys.exit(0)
            except:
                readSize = long(0)

            # get write size on this interval #
            try:
                writeSize = value['write'] - \
                    prevStorageData[origDev]['write']

                writeSize = convSize2Unit(writeSize << 20)
            except SystemExit:
                sys.exit(0)
            except:
                writeSize = long(0)

            total = convSize2Unit(value['total'] << 20)

            free = convSize2Unit(value['free'] << 20)

            # 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 = '%s%s' % \
                    (op, convSize2Unit(long(abs(freeDiff)) << 20))
            except SystemExit:
                sys.exit(0)
            except:
                freeDiff = long(0)

            # convert color for storage usage #
            usePer = '%4s%%' % value['usagePer']
            if value['usagePer'] > SysMgr.diskPerHighThreshold:
                usePer = '%s' % UtilMgr.convColor(usePer, 'RED')
            elif value['usagePer'] > 0:
                usePer = '%s' % UtilMgr.convColor(usePer, 'YELLOW')

            favail = '%7s' % convSize2Unit(value['favail'])
            if value['favail'] == 0:
                favail = '%s' % UtilMgr.convColor(favail, 'RED')

            fs = value['mount']['fs']
            path = value['mount']['path']
            option = value['mount']['option']

            # make disk stat string #
            if len(option) > 0:
                mountInfo = '%s <%s>' % (path, option)
            else:
                mountInfo = path

            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, busytime, avq, readSize, writeSize, free,
                freeDiff, usePer, total, favail, fs, mountInfo[:51])

            if SysMgr.checkCutCond():
                return

            SysMgr.addPrint(diskInfo)

            printCnt += 1

        if printCnt == 0:
            SysMgr.addPrint('\tNone\n')



    def getSortedProcData(self):
        checkCond = True

        # memory #
        if SysMgr.sort == 'm':
            sortedProcData = sorted(self.procData.items(),
                key=lambda e: long(e[1]['stat'][self.rssIdx]), reverse=True)
        # block #
        elif SysMgr.sort == 'b':
            sortedProcData = sorted(self.procData.items(),
                key=lambda e: e[1]['btime'], reverse=True)
        # WFC #
        elif SysMgr.sort == 'w':
            sortedProcData = sorted(self.procData.items(),
                key=lambda e: e[1]['cttime'], reverse=True)
        # pid #
        elif SysMgr.sort == 'p':
            sortedProcData = sorted(self.procData.items(),
                key=lambda e: long(e[0]))
            checkCond = False
        # new #
        elif SysMgr.sort == 'n':
            sortedProcData = sorted(self.procData.items(),
                key=lambda e: e[1]['new'], reverse=True)
            checkCond = False
        # runtime #
        elif SysMgr.sort == 'r':
            sortedProcData = sorted(self.procData.items(),
                key=lambda e: e[1]['runtime'], reverse=True)
        # oomscore #
        elif SysMgr.sort == 'o':
            sortedProcData = sorted(self.procData.items(),
                key=lambda e: e[1]['oomScore'], reverse=True)
        # priority #
        elif SysMgr.sort == 'P':
            sortedProcData = sorted(self.procData.items(),
                key=lambda e: long(e[1]['stat'][self.prioIdx]), reverse=False)
            checkCond = False
        # exectime #
        elif SysMgr.sort == 'e' or SysMgr.sort == '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)
            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)
            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)
            checkCond = False
        # name #
        elif SysMgr.sort == 'N':
            sortedProcData = sorted(self.procData.items(),
                key=lambda e: e[1]['stat'][self.commIdx], reverse=False)
            checkCond = False
        # CPU #
        else:
            # set CPU usage as default #
            sortedProcData = sorted(self.procData.items(),
                key=lambda e: e[1]['ttime'], reverse=True)

        # convert sort condition type to number #
        if checkCond and SysMgr.sortCond:
            try:
                SysMgr.sortCond = long(SysMgr.sortCond)
            except:
                SysMgr.printErr(
                    "fail to convert '%s' to number for sort condition" % \
                        SysMgr.sortCond)
                sys.exit(0)

        return sortedProcData



    def getCgroupUsage(self):
        interval = SysMgr.uptimeDiff
        if interval == 0:
            interval = 0.1

        stats = {}
        prevData = self.prevCgroupData

        for system, groups in self.cgroupData.items():
            for group, values in groups.items():
                # filter group #
                if SysMgr.filterGroup:
                    if not UtilMgr.isValidStr(
                        group, inc=True, ignCap=True):
                        continue

                for name, value in values.items():
                    stats.setdefault(group, dict())

                    if name == 'tasks' or name == 'cgroup.procs':
                        stat = value.count('\n')
                    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:<112}|{2:>4}|{3:>4}|"
                "{4:>6}|{5:>7}|{6:>7}|{7:>7}|\n{8:1}\n").format(
                twoLine, 'Control Group', 'Proc', 'Task',
                'CPU(%)', '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 #
            try:
                usage = value['cpuacct.usage'] / 10000000
                cpu = '%6.1f' % usage

                # convert color for CPU usage #
                if usage < SysMgr.cpuPerLowThreshold:
                    pass
                else:
                    if usage >= SysMgr.cpuPerHighThreshold:
                        cpu = UtilMgr.convColor(cpu, 'RED')
                    else:
                        cpu = UtilMgr.convColor(cpu, 'YELLOW')
            except SystemExit:
                sys.exit(0)
            except:
                cpu = 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:<112}|{1:>4}|{2:>4}|"
                "{3:>6}|{4:>7}|{5:>7}|{6:>7}|\n").format(
                    system, proc, task, cpu, mem, '-', '-'))
            if not ret:
                return -1

        SysMgr.addPrint("%s\n" % oneLine)



    def printProcUsage(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['btime']
            elif SysMgr.sort == 'w':
                target = value['cttime']
            elif SysMgr.sort == 'n':
                target = value['new']
            elif SysMgr.sort == 'o':
                target = value['oomScore']
            elif SysMgr.sort == 'r':
                target = value['runtime'] / 1000000000
            elif SysMgr.sort == 'e':
                target = value['execTime'] / 1000000000
            elif SysMgr.sort == 'd':
                target = value['waitTime']
            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

                nowStat = value['status']
                nowCtx = \
                    long(nowStat['voluntary_ctxt_switches']) + \
                    long(nowStat['nonvoluntary_ctxt_switches'])

                target = nowCtx - prevCtx
            else:
                target = 1

            # check sort condition #
            if SysMgr.sortCond and \
                target < SysMgr.sortCond:
                return True

            # check filter #
            if not SysMgr.filterGroup and \
                not SysMgr.showAll and \
                not target:
                return True
            else:
                return False

        def _isExceptTask(idx):
            exceptFlag = False

            for item in list(SysMgr.filterGroup):
                exceptFlag = False
                # group mode #
                if SysMgr.groupProcEnable:
                    # process mode #
                    if SysMgr.processEnable:
                        ppid = procData[idx]['stat'][self.ppidIdx]

                        # check current pid #
                        if idx == item:
                            break
                        # check current thread comm #
                        elif item in stat[self.commIdx]:
                            break
                        # check current's parent pid by comm #
                        elif ppid in plist:
                            break
                        # check current's parent comm #
                        elif ppid in procData and \
                            item in procData[ppid]['stat'][self.commIdx]:
                            break
                        # check current's parent pid #
                        elif item.isdigit() and \
                            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 process comm #
                        if pid in procData and \
                            item in procData[pid]['stat'][self.commIdx]:
                            break
                        # check current pid by comm #
                        elif pid in plist:
                            break
                        # check current's pid #
                        elif item.isdigit() and \
                            item in procData and \
                            procData[item]['mainID'] == value['mainID']:
                            break
                        elif idx == item or \
                            value['mainID'] == item:
                            break
                        else:
                            exceptFlag = True
                # single mode #
                else:
                    if idx == item:
                        break
                    elif item in stat[self.commIdx]:
                        break
                    else:
                        exceptFlag = True

            return exceptFlag

        def _getParentList():
            plist = {}
            if not SysMgr.groupProcEnable:
                return plist

            for idx, value in sortedProcData:
                for item in SysMgr.filterGroup:
                    if not item in value['stat'][self.commIdx]:
                        continue

                    if not SysMgr.processEnable:
                        plist[self.procData[idx]['mainID']] = long(0)
                        break

                    plist[self.procData[idx]['stat'][self.ppidIdx]] = long(0)
                    break

            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'

            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] = long(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 = long(0)
                            fullstack = '%s%s\n' % (fullstack, line)
                            newLine += 1
                            line = ' ' * initIndent

                        line = '%s%s <- ' % (line, astack)
                    except:
                        pass

                fullstack = '%s%s' % (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

        # set comm and pid size #
        pd = self.getPidLen()
        cl = 26 - (pd * 2)

        # calculate resource usage of processes #
        self.setProcUsage()

        # get types #
        mode, pidType, ppidType, sidType,\
            pgrpType, dprop, etc, mem = _getTypes()

        # add JSON stats #
        if SysMgr.jsonEnable:
            jtype = mode.lower()
            SysMgr.jsonData.setdefault(jtype, dict())
            jsonData = SysMgr.jsonData[jtype]

        # print menu #
        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 #
        convertNum = UtilMgr.convNum
        convertFunc = UtilMgr.convSize2Unit
        convTime = UtilMgr.convTime

        totalStats = {\
            'read': long(0), 'write': long(0),
            'yld': long(0), 'prtd': long(0), 'task': long(0)}

        # clear id list #
        if idIndex:
            SysMgr.idList = []

        # print resource usage of processes / threads #
        procCnt = long(0)
        procData = self.procData
        for idx, value in sortedProcData:
            stat = value['stat']

            # check exception flag #
            if _isExceptTask(idx):
                continue

            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, dict())

                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'] = long(0)
                    except:
                        SysMgr.printOpenWarn(spath)

                        self.stackTable.pop(idx, None)

            # check limit #
            if _isBreakCond(idx, value):
                break

            if SysMgr.checkCutCond():
                return

            # get comm #
            comm = value['comm']

            # get parent id #
            if SysMgr.processEnable:
                pid = stat[self.ppidIdx]
            else:
                pid = value['mainID']

            # get code size #
            codeSize = (long(stat[self.ecodeIdx]) - \
                long(stat[self.scodeIdx])) >> 20

            # get sched #
            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))

            # get lifetime #
            lifeTime = UtilMgr.convTime(value['runtime'])

            # save status info to get memory status #
            self.saveProcStatusData(value['taskPath'], idx)

            # 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 or SysMgr.pssEnable or SysMgr.ussEnable:
                TaskAnalyzer.saveProcSmapsData(value['taskPath'], idx)

            # swap #
            try:
                swapSize = \
                    long(value['status']['VmSwap'].split()[0]) >> 10
            except:
                swapSize = '-'

            # shared #
            try:
                shr = long(value['statm'][self.shrIdx]) >> 8
            except:
                shr = '-'

            if not SysMgr.processEnable:
                try:
                    value['yield'] = \
                        value['status']['voluntary_ctxt_switches']
                    value['preempted'] = \
                        value['status']['nonvoluntary_ctxt_switches']
                except:
                    value['yield'] = '-'
                    value['preempted'] = '-'

            # user #
            try:
                userData = SysMgr.sysInstance.userData
                uid = value['status']['Uid'].split()[0]
                value['user'] = userData[uid]['name']
            except SystemExit:
                sys.exit(0)
            except:
                value['user'] = '-'

            # save size of file descriptor table #
            try:
                value['fdsize'] = value['status']['FDSize']
            except:
                value['fdsize'] = '-'

            # scheduling info #
            if SysMgr.processEnable:
                # sid #
                yld = stat[self.sidIdx][-5:]
                if yld == '0':
                    yld = '-'

                # user #
                try:
                    prtd = value['user'][:6]
                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:
                    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:
                    prtd = '-'

            try:
                # get blocked 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 = UtilMgr.convColor('%3s' % dtime, 'RED')
            except SystemExit:
                sys.exit(0)
            except:
                dtime = '-'

            # get io size #
            try:
                readSize = value['read'] >> 20
                if readSize > 0:
                    readSize = UtilMgr.convColor('%4s' % readSize, 'RED')

                writeSize = value['write'] >> 20
                if writeSize > 0:
                    writeSize = UtilMgr.convColor('%4s' % writeSize, 'RED')
            except:
                readSize = '-'
                writeSize = '-'

            # set 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 = value['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]
                    etc = '%s(%s)' % (procData[pgid]['comm'], pgid)
            except SystemExit:
                sys.exit(0)
            except:
                etc = '-'

            try:
                sched = \
                    SCHED_POLICY[int(stat[self.policyIdx])] + str(schedValue)
            except:
                sched = '?'

            try:
                vss = long(stat[self.vssIdx]) >> 20
            except:
                vss = long(0)

            # get memory details #
            memBuf, nrss, pss, uss = self.getMemDetails(idx, value['maps'])
            if SysMgr.pssEnable:
                mems = pss >> 8
            elif SysMgr.ussEnable:
                mems = uss >> 8
            else:
                mems = value['rss']

            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(':')]

            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:
                pass
            else:
                if value['ttime'] >= SysMgr.cpuPerHighThreshold:
                    ttime = UtilMgr.convColor(ttime, 'RED', 4)
                else:
                    ttime = UtilMgr.convColor(ttime, 'YELLOW', 4)

            # convert color for RSS #
            if mems < SysMgr.memLowThreshold:
                memstr = mems
            else:
                if mems >= SysMgr.memHighThreshold:
                    memstr = UtilMgr.convColor(mems, 'RED', 4)
                else:
                    memstr = UtilMgr.convColor(mems, 'YELLOW', 4)

            # convert color for BTIME #
            if float(btime) > 0:
                btimestr = UtilMgr.convColor(btime, 'RED', 4)
            else:
                btimestr = btime

            try:
                if nrPrio < 20:
                    if nrPrio >= 0:
                        sched = UtilMgr.convColor(sched, 'YELLOW', 4)
                    else:
                        sched = UtilMgr.convColor(sched, 'RED', 4)
            except SystemExit:
                sys.exit(0)
            except:
                pass

            # 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, value['fdsize'], lifeTime[:9], etc[:21],
                cl=cl, pd=pd))
            if not ret:
                return

            # 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:
                    pass
            else:
                totalStats['yld'] = '-'
                totalStats['prtd'] = '-'

            if SysMgr.blockEnable:
                try:
                    totalStats['read'] += value['read']
                    totalStats['write'] += value['write']
                except:
                    try:
                        totalStats['read'] = value['read']
                        totalStats['write'] = value['write']
                    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 len(perfString) > 0:
                        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))

            # 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]

                while len(pstr) > limit:
                    slimit = len(pstr[:limit])
                    des = '%s' % pstr[:slimit]
                    tstr = '%s%s\n%s' % \
                        (tstr, des, ' ' * (indent + indenta))

                    if isFirstLined:
                        limit -= indenta + lenItem
                        isFirstLined = False

                    pstr = '%s' % pstr[slimit:]

                tstr = '%s%s' % (tstr, pstr)

                # count newlines #
                newline = tstr.count('\n')+1

                ret = SysMgr.addPrint(
                    "{0:>39} | WSS: {1:1}\n".format(' ', tstr), newline)
                if not ret:
                    return

            # print memory summary #
            if memBuf:
                vmlist = \
                    ['VmPeak', 'VmHWM', 'VmData', 'HugetlbPages',
                        'RssAnon', 'RssFile', 'RssShmem']

                if 'status' in value:
                    memstr = ''
                    memset = value['status']

                    for item in vmlist:
                        try:
                            vmsize = long(memset[item].split()[0]) << 10
                            memstr += \
                                '%s: %s, ' % (item, convertFunc(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 \
                len(value['cmdline']) > 0:
                SysMgr.addPrint(
                    "{0:>39} | {1:1}\n".format('CMDLINE', value['cmdline']))

            # print cgroup #
            if 'cgroup' in value:
                SysMgr.addPrint(
                    "{0:>39} | {1:1}\n".format('CGROUP', value['cgroup']))

            # 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' % convertNum(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 \
                len(value['dbusList']) > 0:
                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'] = long(0)
                except:
                    pass

            procCnt += 1
            if SysMgr.memEnable:
                SysMgr.addPrint("%s\n" % oneLine)

        if procCnt > 0:
            # total CPU #
            totalTime = '%6.1f' % totalStats['ttime']
            if totalStats['ttime'] == 0:
                pass
            elif totalStats['ttime'] >= SysMgr.cpuPerHighThreshold:
                totalTime = UtilMgr.convColor(totalTime, 'RED')
            else:
                totalTime = UtilMgr.convColor(totalTime, 'YELLOW')

            # total BLOCK #
            totalBtime = totalStats['btime']
            if totalStats['btime'] > 0:
                totalBtime = UtilMgr.convColor(totalBtime, 'RED', 4)

            # total READ #
            readsize = totalStats['read']
            if readsize != '-':
                readsize = readsize >> 20
                if readsize > 0:
                    readsize = UtilMgr.convColor(readsize, 'RED', 4)

            # total WRITE #
            writesize = totalStats['write']
            if writesize != '-':
                writesize = writesize >> 20
                if writesize > 0:
                    writesize = UtilMgr.convColor(writesize, 'RED', 4)

            # print total stats #
            SysMgr.addPrint(
                ("{0:>{td}}|"
                "{1:>6}({2:>4}/{3:>4})|"
                "{4:>3}:{5:>5} / {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,
                convertFunc(totalStats['mem'] << 20, True),
                'Swp', convertFunc(totalStats['swap'], True),
                totalBtime, readsize, writesize, totalStats['majflt'],
                'Yld: %s' % convertNum(totalStats['yld']),
                'Prmt: %s' % convertNum(totalStats['prtd']),
                'Task: %s' % convertNum(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 processes #
        if not self.printSpecialTask('abnormal'):
            return
        if not self.printSpecialTask('new'):
            return
        if not self.printSpecialTask('die'):
            return



    def getPidLen(self):
        pidlen = len(str(self.maxPid))
        if pidlen < 4:
            return 4
        else:
            return pidlen



    def printSpecialTask(self, taskType):
        # set comm and pid size #
        pd = self.getPidLen()
        cl = 26 - (pd * 2)

        if SysMgr.reportEnable:
            self.reportData.setdefault('task', dict())
            self.reportData['task'].setdefault(taskType, dict())
            jsonData = self.reportData['task'][taskType]

        # get task list #
        if taskType == 'abnormal':
            taskList = set(self.abnormalTasks.keys())
        elif taskType == 'new':
            taskList = \
                set(self.procData.keys()) - set(self.prevProcData.keys())
        elif taskType == 'die':
            taskList = \
                set(self.prevProcData.keys()) - set(self.procData.keys())

        procCnt = long(0)
        for tid in sorted(list(map(long, taskList))):
            if SysMgr.checkCutCond():
                return False

            idx = str(tid)

            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][1:-1]
            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:
                codeSize = (long(stat[self.ecodeIdx]) - \
                    long(stat[self.scodeIdx])) >> 20
            except:
                codeSize = 0

            try:
                if ConfigMgr.SCHED_POLICY[int(stat[self.policyIdx])] == 'C':
                    schedValue = "%3d" % (long(stat[self.prioIdx]) - 20)
                else:
                    schedValue = "%3d" % (abs(long(stat[self.prioIdx]) + 1))
                schedPolicy = \
                    ConfigMgr.SCHED_POLICY[int(stat[self.policyIdx])] + \
                    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 = '-'
            try:
                shr = long(value['statm'][self.shrIdx]) >> 8
            except:
                shr = '-'

            if SysMgr.blockEnable:
                try:
                    readSize = value['read'] >> 20
                    writeSize = value['write'] >> 20
                except:
                    readSize = writeSize = long(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

            # 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(
                "fail 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(0)

        if type(packet) is tuple:
            data = packet[0]
            addr = packet[1]
        else:
            return

        if type(data) is bytes:
            try:
                data = data.decode()
            except:
                pass

        if not UtilMgr.isString(data):
            SysMgr.printErr("fail to recognize data from server")
            return

        # get address info from server #
        try:
            ip = addr[0]
            port = long(addr[1])
        except:
            SysMgr.printErr("fail to recognize address from server")

        # wrong request from client #
        if SysMgr.remoteServObj == 'NONE' and \
            data in TaskAnalyzer.requestType:
            SysMgr.printErr(
                "fail 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("fail 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(
                "fail to request service because of no support from server")
            sys.exit(0)

        # DUPLICATED response #
        elif data == 'PRINT' or data.startswith('REPORT'):
            SysMgr.printErr(
                "fail to request service "
                "because of same port used between client and sever")
            sys.exit(0)

        # 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(0)

                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(
                "fail to send request '%s'" % \
                SysMgr.remoteServObj.request)



    def checkServer(self):
        if not SysMgr.localServObj:
            return

        while 1:
            # get message from clients #
            ret = SysMgr.localServObj.recvfrom(verbose=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(
                    "fail 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_'):
                event = message[message.find('_')+1:]

                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))

                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_ALWAYS' or message == 'REPORT_BOUND':
                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(
                        "fail to find %s:%d as remote address" % (ip, port))

            # wrong request or just data from server #
            else:
                SysMgr.printErr(
                    "fail to recognize the request from client")



    def executeEventCommand(self, eventList):
        if not eventList:
            return

        # check event handling process #
        runList = SysMgr.getChildList()
        for event, pid in deepcopy(self.eventCommandList).items():
            if not pid in runList:
                self.eventCommandList.pop(event, None)

        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 self.eventCommandList:
                continue
            elif not value['run']:
                continue

            for cmd in value['command']:
                if 'COMMAND' in SysMgr.thresholdData and \
                    cmd in SysMgr.thresholdData['COMMAND']:
                    cmd = SysMgr.thresholdData['COMMAND'][cmd]

                # convert EVTPID #
                if 'task' in value:
                    pid = list(value['task'].keys())[0]
                    cmd = cmd.replace('EVTPID', pid)

                # convert SELFPID #
                cmd = cmd.replace('SELFPID', str(SysMgr.pid))

                # convert EVTNAME #
                cmd = cmd.replace('EVTNAME', event)

                # convert EVTTIME #
                cmd = cmd.replace('EVTTIME', str(long(SysMgr.uptime)))

                SysMgr.printInfo(
                    'executed "%s" by %s event' % (cmd, event))

                # launch Guider #
                if cmd.startswith('GUIDER '):
                    # build command list #
                    cmdList = SysMgr.splitOptionString(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(
                            "fail to launch %s" % __module__, reason=True)
                # launch command #
                else:
                    ret = SysMgr.createProcess(cmd)

                # register the event handling process #
                if ret:
                    self.eventCommandList.setdefault(event, ret)



    def handleThresholdEvents(self):
        if not SysMgr.thresholdEventList and \
            not self.reportData['event']:
            return

        # print events #
        prevList = list(SysMgr.thresholdEventList.keys())
        nowList = list(self.reportData['event'].keys())

        # print finished events #
        endList = set(prevList) - set(nowList)
        if endList:
            SysMgr.printInfo(
                "finished threshold events [ %s ] at %s" % \
                    (', '.join(endList), SysMgr.uptime))

        # print new events #
        newList = set(nowList) - set(prevList)
        if newList:
            SysMgr.printInfo(
                "threshold events [ %s ] occurred at %s" % \
                    (', '.join(newList), SysMgr.uptime))

            # 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.printInfo(
                "continued threshold events [ %s ] at %s" % \
                    (', '.join(contList), SysMgr.uptime))

        # 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

        # check CPU #
        try:
            self.checkThreshold('cpu', 'total', 'CPU', 'big')
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # check memory #
        try:
            self.checkThreshold('mem', 'available', 'MEM', 'less')
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # check swap #
        try:
            self.checkThreshold('swap', 'usagePer', 'SWAP', 'big')
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # check iowait #
        try:
            self.checkThreshold('block', 'ioWait', 'IO', 'big')
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # check storage #
        try:
            # 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

                target = vals['usagePer']
                vals.update({'dev': dev})

                try:
                    # all devices #
                    self.checkThreshold(
                        'storage', 'usagePer', 'STORAGE', 'big',
                        target, 'DEVICE', addval=vals)

                    # a specific device #
                    self.checkThreshold(
                        'storage', 'usagePer', 'STORAGE', 'big',
                        target, dev, addval=vals)
                except SystemExit:
                    sys.exit(0)
                except:
                    continue
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # check network #
        try:
            # total inbound #
            target = self.reportData['net']['inbound']
            intval = self.intervalData['inbound']
            self.checkThreshold(
                'net', 'inbound', 'NETIN', 'big', target, intval=intval)

            # total outbound #
            target = self.reportData['net']['outbound']
            intval = self.intervalData['outbound']
            self.checkThreshold(
                'net', 'outbound', 'NETOUT', 'big', target, intval=intval)

            # each devices #
            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']
                vals.update({'dev': dev})

                # all devices #
                try:
                    # recv #
                    self.checkThreshold(
                        'net', 'recv', 'NETWORK', 'big', recv, 'DEVICE')

                    # send #
                    self.checkThreshold(
                        'net', 'trans', 'NETWORK', 'big', trans, 'DEVICE')
                except SystemExit:
                    sys.exit(0)
                except:
                    pass

                # a specific device #
                try:
                    # recv #
                    self.checkThreshold(
                        'net', 'recv', 'NETWORK', 'big', recv, dev)

                    # send #
                    self.checkThreshold(
                        'net', 'trans', 'NETWORK', 'big', trans, dev)
                except SystemExit:
                    sys.exit(0)
                except:
                    pass
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # check sched #
        try:
            # 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'].keys())
                target = '_'.join(newList)
                self.checkThreshold(
                    'task', 'new', 'NEW', None, target)

            # die status #
            if self.reportData['task']['die']:
                dieList = list(self.reportData['task']['die'].keys())
                target = '_'.join(dieList)
                self.checkThreshold(
                    'task', 'die', 'DIE', None, target)

            # abnormal status #
            if self.reportData['task']['abnormal']:
                dieList = list(self.reportData['task']['abnormal'].keys())
                target = '_'.join(abnormalList)
                self.checkThreshold(
                    'task', 'abnormal', 'ABNORMAL', None, target)
        except SystemExit:
            sys.exit(0)
        except:
            pass

        # check task #
        try:
            self.checkTaskThreshold()
        except SystemExit:
            sys.exit(0)
        except:
            SysMgr.printWarn(
                'fail to check task thresholds', reason=True)

        # handle events #
        self.handleThresholdEvents()



    def setThresholdEvent(
        self, comval, item, event, comp='big', target=None,
        attr='SYSTEM', intval=None, addval=None, oneshot=False):

        value = None

        # check condition #
        if not item in comval:
            return
        elif not comp:
            value = target
        elif intval and 'interval' in comval:
            if comval['interval'] > len(intval):
                return

            average = sum(intval)/len(intval)
            if (comp == 'big' and comval[item] <= average) or \
                (comp == 'less' and comval[item] >= average):
                value = average
        elif (comp == 'big' and comval[item] <= target) or \
            (comp == 'less' and comval[item] >= target):
            value = target

        # check value #
        if value is None:
            return

        # add task info #
        if addval:
            comval.update(addval)

        # set event name #
        ename = '%s_%s_%s' % (event, attr, item)

        # add event #
        if 'task' in comval:
            addinfo = ''
            for pid, data in comval['task'].items():
                addinfo += '_%s_%s' % (data['comm'], pid)
            ename = '%s%s' % (ename, addinfo)
        elif 'dev' in comval:
            ename = '%s%s' % (ename, comval['dev'])

        if item in comval:
            ename = '%s_%s' % (ename, comval[item])

        # replace '/' with '_' for path by event name #
        ename = ename.replace('/', '_')

        # handle oneshot command #
        if 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)



    def checkThreshold(
        self, resource, item, event, comp=None, target=None,
        attr='SYSTEM', intval=None, addval=None):

        def _getOneshotFlag(items):
            if 'oneshot' in items and \
                items ['oneshot'] == 'true':
                return True
            else:
                return False

        if not SysMgr.thresholdData:
            return

        td = SysMgr.thresholdData

        # check attribute #
        if not resource in td or not attr in td[resource]:
            return

        # 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 not target:
            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
            # check except attribute #
            elif attr == 'TASK' and 'except' in comval:
                pid = next(iter(addval['task']))
                comm = addval['task'][pid]['comm']

                if type(comval['except']) is list:
                    for excomm in comval['except']:
                        if comm == excomm:
                            return
                else:
                    if comm == comval['except']:
                        return

            oneshot = _getOneshotFlag(comval)
            self.setThresholdEvent(
                comval, item, event, comp,
                target, attr, intval, addval, oneshot)
        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 attr == 'TASK' and 'except' in comitem:
                    pid = next(iter(addval['task']))
                    comm = addval['task'][pid]['comm']

                    if type(comitem['except']) is list:
                        found = False
                        for excomm in comitem['except']:
                            if comm == excomm:
                                found = True
                                break
                        if found:
                            continue
                    else:
                        if comm == comitem['except']:
                            continue

                oneshot = _getOneshotFlag(comitem)
                self.setThresholdEvent(
                    comitem, item, event, comp,
                    target, attr, intval, addval, oneshot)



    def checkTaskThreshold(self):
        if not SysMgr.thresholdData:
            return

        # mapping table between thresholds and stats #
        ilist = [
            ['cpu', 'total', 'ttime', 'cpuInterval', 'CPU', 'big'],
            ['mem', 'rss', 'rss', 'rssInterval', 'MEM', 'big'],
        ]

        if SysMgr.processEnable:
            mode = 'process'
        else:
            mode = 'thread'

        td = SysMgr.thresholdData
        exceptTaskResource = {}

        # traverse all tasks #
        for pid, data in self.procData.items():
            # skip Guider #
            if data['comm'] == __module__:
                continue

            for item in ilist:
                try:
                    resource, cattr, pattr, intname, event, comp = item

                    if not resource in td:
                        continue

                    value = data[pattr]

                    if intname in data:
                        intval = data[intname]
                    else:
                        intval = None

                    if not value:
                        if not intval:
                            continue
                        if set(intval) == set([0]):
                            continue

                    if False and pid in SysMgr.jsonData[mode]:
                        append = {'task': {pid: SysMgr.jsonData[mode][pid]}}
                    else:
                        append = {'task': {pid: data}}

                    # check all tasks #
                    if not 'TASK' in td[resource]:
                        pass
                    elif not resource in exceptTaskResource:
                        try:
                            self.checkThreshold(
                                resource, cattr, event, comp,
                                    value, 'TASK', intval, append)
                        except SystemExit:
                            sys.exit(0)
                        except:
                            SysMgr.printWarn(
                                'fail to check task thresholds', reason=True)
                    else:
                        exceptTaskResource.setdefault(resource, None)

                    # check a specific task #
                    if data['comm'] in td[resource]:
                        self.checkThreshold(
                            resource, cattr, event, comp,
                                value, data['comm'], intval, append)
                except SystemExit:
                    sys.exit(0)
                except:
                    SysMgr.printWarn(
                        'fail to check task thresholds', reason=True)



    def reportSystemStat(self):
        # initialize report event list #
        '''
        CPU
        MEM
        SWAP
        IO
        STORAGE
        NETIN
        NETOUT
        '''

        self.reportData['event'] = {}

        # check image created #
        if SysMgr.imagePath:
            self.reportData['event']['IMAGE_CREATED'] = SysMgr.imagePath
            SysMgr.imagePath = None

        if SysMgr.rankProcEnable:
            # add CPU status #
            if 'cpu' in self.reportData:
                rank = 1
                self.reportData['cpu']['procs'] = {}
                sortedProcData = sorted(self.procData.items(),
                    key=lambda e: e[1]['ttime'], reverse=True)

                for pid, data in sortedProcData:
                    if not (SysMgr.showAll or data['ttime'] > 0):
                        break

                    evtdata = self.reportData['cpu']['procs']

                    pid = long(pid)
                    evtdata[rank] = {}
                    evtdata[rank]['pid'] = pid
                    evtdata[rank]['rank'] = rank
                    evtdata[rank]['comm'] = data['stat'][self.commIdx][1:-1]
                    evtdata[rank]['total'] = data['ttime']
                    evtdata[rank]['user'] = data['utime']
                    evtdata[rank]['kernel'] = data['stime']
                    evtdata[rank]['runtime'] = \
                        UtilMgr.convTime(data['runtime'])

                    rank += 1

            # add memory & swap status #
            if 'mem' in self.reportData:
                rank = 1
                self.reportData['mem']['procs'] = {}
                sortedProcData = sorted(self.procData.items(),
                    key=lambda e: long(e[1]['stat'][self.rssIdx]), reverse=True)

                for pid, data in sortedProcData:
                    rss = long(data['stat'][self.rssIdx]) >> 8

                    if not (SysMgr.showAll or rank <= SysMgr.nrTopRank):
                        break

                    text = (long(data['stat'][self.ecodeIdx]) - \
                        long(data['stat'][self.scodeIdx])) >> 20

                    evtdata = self.reportData['mem']['procs']

                    pid = long(pid)
                    evtdata[rank] = {}
                    evtdata[rank]['pid'] = pid
                    evtdata[rank]['rank'] = rank
                    evtdata[rank]['comm'] = data['stat'][self.commIdx][1:-1]
                    evtdata[rank]['rss'] = rss
                    evtdata[rank]['text'] = text
                    evtdata[rank]['runtime'] = \
                        UtilMgr.convTime(data['runtime'])

                    # swap #
                    try:
                        self.reportData['mem']['procs'][pid]['swap'] = \
                            long(data['status']['VmSwap'].split()[0]) >> 10
                    except:
                        pass

                    # shared #
                    try:
                        self.reportData['mem']['procs'][pid]['shared'] = \
                            long(data['statm'][self.shrIdx]) >> 8
                    except:
                        pass

                    rank += 1

            # add block status #
            if 'block' in self.reportData:
                rank = 1
                self.reportData['block']['procs'] = {}
                sortedProcData = sorted(self.procData.items(),
                    key=lambda e: e[1]['btime'], reverse=True)

                for pid, data in sortedProcData:
                    if data['btime'] == 0:
                        break

                    evtdata = self.reportData['block']['procs']

                    pid = long(pid)
                    evtdata[rank] = {}
                    evtdata[rank]['pid'] = long(pid)
                    evtdata[rank]['rank'] = rank
                    evtdata[rank]['comm'] = data['stat'][self.commIdx][1:-1]
                    evtdata[rank]['iowait'] = data['btime']
                    evtdata[rank]['runtime'] = \
                        UtilMgr.convTime(data['runtime'])

                    rank += 1

        # check resource threshold #
        self.checkResourceThreshold()

        # print system status to file if condition is met #
        if self.reportData['event'] and \
            SysMgr.reportFileEnable and \
            SysMgr.outPath:

            # submit summarized report and details #
            TaskAnalyzer.printIntervalUsage()

            # sync and close output file #
            if SysMgr.printFd:
                try:
                    SysMgr.printFd.close()
                except:
                    pass
                finally:
                    SysMgr.printFd = None

            # make output path #
            filePath = os.path.dirname(SysMgr.inputFile) + '/guider'
            for event in list(self.reportData['event'].keys()):
                filePath = '%s_%s' % (filePath, event)
            filePath = '%s_%s.out' % \
                (filePath, str(long(SysMgr.uptime)))

            try:
                # rename output file #
                os.rename(SysMgr.inputFile, filePath)

                # get output size #
                fsize = UtilMgr.getFileSize(filePath)
                if fsize and fsize != '0':
                    fsize = ' [%s]' % fsize
                else:
                    fsize = ''

                SysMgr.printStat((
                    "saved results based monitoring into "
                    "'%s'%s successfully") % \
                    (filePath, fsize))
            except SystemExit:
                sys.exit(0)
            except:
                SysMgr.printWarn(
                    "fail to rename %s to %s" % \
                    SysMgr.inputFile, filePath)

        # convert dict data to JSON-type string #
        jsonObj = UtilMgr.convDict2Str(self.reportData, ignore=True)
        if not jsonObj:
            SysMgr.printWarn(
                "fail to convert report data to JSON type")
            return

        # transfer data to file or socket #
        self.tranData(jsonObj)



    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': long(0) },
                    'write' : { 'bytes': long(0) },
                    'used'  : { 'pct': long(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': long(0) },
                        'kernel'    : { 'pct': long(0) },
                        'total'     : { 'pct': long(0) },
                        'runtime'   : ''
                    },
                    'memory': {
                        'rss'   : { 'bytes': long(0) },
                        'text'  : long(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['stat'][self.commIdx][1:-1]
            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 system status to file #
        if SysMgr.reportObject:
            UtilMgr.writeJsonObject(
                data, fd=SysMgr.reportObject,
                trunc=SysMgr.truncEnable)

        # report system status to socket #
        addrlist = dict(SysMgr.addrListForReport)
        for addr, cli in addrlist.items():
            if cli.request != 'REPORT_ALWAYS':
                continue

            if 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 printSystemStat(self, idIndex=False, target='task'):
        title = '[Top Info]'
        nrIndent = len(title)

        # print default stats #
        self.printDefaultUsage(title)

        # 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.printProcUsage(idIndex=idIndex)
        elif target == 'cgroup':
            self.printCgroupUsage()
        else:
            SysMgr.printErr(
                "wrong monitor target for '%s'" % target)
            sys.exit(0)

        # update session #
        SysMgr.updateSession()

        # flush print buffer #
        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)

    # initialize envirnoment #
    SysMgr.initEnvironment()

    # check commands #
    if not SysMgr.isRecordMode():
        SysMgr.checkCmdMode()

    # snapshot system info #
    SysMgr()

    #==================== RECORD PART ====================#

    if SysMgr.isRecordMode():
        SysMgr.setRecordAttr()

        # wait for input #
        if SysMgr.waitEnable:
            SysMgr.waitUserInput(
                0, msg="\npress enter key...", 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()
    # THREAD MODE #
    else:
        if SysMgr.isDrawMode():
            origInputFile = SysMgr.inputFile
            origInterval = SysMgr.intervalEnable

            # check svgwrite object #
            svgwrite = SysMgr.getPkg('svgwrite')

            # prepare for timeline chart #
            SysMgr.graphEnable = False
            SysMgr.intervalEnable = 0
            tobj = TaskAnalyzer(origInputFile)
            outputPath = UtilMgr.prepareForImageFile(
                SysMgr.inputFile, 'timeline')

            # draw timeline chart #
            SysMgr.drawTimeline(
                inputData=tobj.timelineData,
                outputPath=outputPath,
                taskList=list(tobj.threadData.keys()))

            # draw resource graph #
            SysMgr.graphEnable = True
            SysMgr.intervalEnable = origInterval
            TaskAnalyzer(origInputFile).printUsage()
        else:
            TaskAnalyzer(SysMgr.inputFile).printUsage()

    # print event info #
    EventAnalyzer.printEventInfo()



# define line variables #
oneLine = "-" * SysMgr.lineLength
twoLine = "=" * SysMgr.lineLength
splitLine = ">" * 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)
