示例#1
0
    def dump_info(self, pinfo, take_dump):
        """Dump info."""
        debugger = "lldb"
        dbg = self._find_debugger(debugger)
        logger = _get_process_logger(self._dbg_output, pinfo.name)

        if dbg is None:
            self._root_logger.warning(
                "Debugger %s not found, skipping dumping of %s", debugger,
                str(pinfo.pidv))
            return

        self._root_logger.info(
            "Debugger %s, analyzing %s processes with PIDs %s", dbg,
            pinfo.name, str(pinfo.pidv))

        lldb_version = callo([dbg, "--version"], logger)

        logger.info(lldb_version)

        # Do we have the XCode or LLVM version of lldb?
        # Old versions of lldb do not work well when taking commands via a file
        # XCode (7.2): lldb-340.4.119
        # LLVM - lldb version 3.7.0 ( revision )

        if 'version' not in lldb_version:
            # We have XCode's lldb
            lldb_version = lldb_version[lldb_version.index("lldb-"):]
            lldb_version = lldb_version.replace('lldb-', '')
            lldb_major_version = int(lldb_version[:lldb_version.index('.')])
            if lldb_major_version < 340:
                logger.warning(
                    "Debugger lldb is too old, please upgrade to XCode 7.2")
                return

        cmds = self._process_specific(pinfo, take_dump) + self._postfix()

        tf = tempfile.NamedTemporaryFile(mode='w', encoding='utf-8')

        for cmd in cmds:
            tf.write(cmd + "\n")

        tf.flush()

        # Works on in MacOS 10.9 & later
        #call([dbg] +  list( itertools.chain.from_iterable([['-o', b] for b in cmds])), logger)
        call(['cat', tf.name], logger)
        call([dbg, '--source', tf.name], logger)

        self._root_logger.info("Done analyzing %s processes with PIDs %s",
                               pinfo.name, str(pinfo.pidv))

        if take_dump:
            need_sigabrt = {}
            files = self._dump_files(pinfo)
            for pid in files:
                if not os.path.exists(files[pid]):
                    need_sigabrt[pid] = files[pid]
            if need_sigabrt:
                raise DumpError(need_sigabrt)
示例#2
0
    def dump_info(self, pinfo, take_dump):
        """Dump info."""
        debugger = "gdb"
        dbg = self._find_debugger(debugger)
        logger = _get_process_logger(self._dbg_output, pinfo.name)

        if dbg is None:
            self._root_logger.warning(
                "Debugger %s not found, skipping dumping of %s", debugger,
                str(pinfo.pidv))
            return

        self._root_logger.info(
            "Debugger %s, analyzing %s processes with PIDs %s", dbg,
            pinfo.name, str(pinfo.pidv))

        call([dbg, "--version"], logger)

        cmds = self._prefix() + self._process_specific(
            pinfo, take_dump, logger) + self._postfix()

        call([dbg, "--quiet", "--nx"] +
             list(itertools.chain.from_iterable([['-ex', b] for b in cmds])),
             logger)

        self._root_logger.info("Done analyzing %s processes with PIDs %s",
                               pinfo.name, str(pinfo.pidv))
示例#3
0
    def dump_info(  # pylint: disable=too-many-arguments
            self, pinfo, take_dump):
        """Dump useful information to the console."""
        debugger = "cdb.exe"
        dbg = self._find_debugger(debugger)

        if dbg is None:
            self._root_logger.warning(
                "Debugger %s not found, skipping dumping of %s", debugger,
                str(pinfo.pidv))
            return

        self._root_logger.info(
            "Debugger %s, analyzing %s processes with PIDs %s", dbg,
            pinfo.name, str(pinfo.pidv))

        # TODO: SERVER-48449
        for pid in pinfo.pidv:
            logger = _get_process_logger(self._dbg_output, pinfo.name, pid=pid)

            process = Pinfo(name=pinfo.name, pidv=pid)
            cmds = self._prefix() + self._process_specific(
                process, take_dump) + self._postfix()

            call([dbg, '-c', ";".join(cmds), '-p', str(pid)], logger)

            self._root_logger.info("Done analyzing %s process with PID %d",
                                   pinfo.name, pid)
示例#4
0
    def dump_processes(self, logger):
        """Get list of [Pid, Process Name]."""
        ps = self.__find_ps()

        logger.info("Getting list of processes using %s", ps)

        call([ps, "--version"], logger)

        ret = callo([ps, "-eo", "pid,args"], logger)

        buff = io.StringIO(ret)
        csv_reader = csv.reader(buff, delimiter=' ', quoting=csv.QUOTE_NONE, skipinitialspace=True)

        return [[int(row[0]), os.path.split(row[1])[1]] for row in csv_reader if row[0] != "PID"]
示例#5
0
    def dump_info(self, root_logger, logger, pid, process_name):
        """Dump java thread stack traces to the console."""
        debugger = "jstack"
        jstack = self.__find_debugger(debugger)

        if jstack is None:
            logger.warning("Debugger %s not found, skipping dumping of %d", debugger, pid)
            return

        root_logger.info("Debugger %s, analyzing %s process with PID %d", jstack, process_name, pid)

        call([jstack, "-l", str(pid)], logger)

        root_logger.info("Done analyzing %s process with PID %d", process_name, pid)
示例#6
0
    def dump_info(  # pylint: disable=too-many-arguments
            self, root_logger, logger, pinfo, take_dump):
        """Dump useful information to the console."""
        debugger = "cdb.exe"
        dbg = self.__find_debugger(root_logger, debugger)

        if dbg is None:
            root_logger.warning("Debugger %s not found, skipping dumping of %d", debugger,
                                pinfo.pid)
            return

        root_logger.info("Debugger %s, analyzing %s process with PID %d", dbg, pinfo.name,
                         pinfo.pid)

        dump_command = ""
        if take_dump:
            # Dump to file, dump_<process name>.<pid>.mdmp
            dump_file = "dump_%s.%d.%s" % (os.path.splitext(pinfo.name)[0], pinfo.pid,
                                           self.get_dump_ext())
            dump_command = ".dump /ma %s" % dump_file
            root_logger.info("Dumping core to %s", dump_file)

        cmds = [
            ".symfix",  # Fixup symbol path
            "!sym noisy",  # Enable noisy symbol loading
            ".symopt +0x10",  # Enable line loading (off by default in CDB, on by default in WinDBG)
            ".reload",  # Reload symbols
            "!peb",  # Dump current exe, & environment variables
            "lm",  # Dump loaded modules
            dump_command,
            "!uniqstack -pn",  # Dump All unique Threads with function arguments
            "!cs -l",  # Dump all locked critical sections
            ".detach",  # Detach
            "q"  # Quit
        ]

        call([dbg, '-c', ";".join(cmds), '-p', str(pinfo.pid)], logger)

        root_logger.info("Done analyzing %s process with PID %d", pinfo.name, pinfo.pid)
示例#7
0
    def dump_info(  # pylint: disable=too-many-arguments,too-many-locals
            self, root_logger, logger, pinfo, take_dump):
        """Dump info."""
        debugger = "gdb"
        dbg = self.__find_debugger(debugger)

        if dbg is None:
            logger.warning("Debugger %s not found, skipping dumping of %d", debugger, pinfo.pid)
            return

        root_logger.info("Debugger %s, analyzing %s process with PID %d", dbg, pinfo.name,
                         pinfo.pid)

        dump_command = ""
        if take_dump:
            # Dump to file, dump_<process name>.<pid>.core
            dump_file = "dump_%s.%d.%s" % (pinfo.name, pinfo.pid, self.get_dump_ext())
            dump_command = "gcore %s" % dump_file
            root_logger.info("Dumping core to %s", dump_file)

        call([dbg, "--version"], logger)

        script_dir = "buildscripts"
        root_logger.info("dir %s", script_dir)
        gdb_dir = os.path.join(script_dir, "gdb")
        mongo_script = os.path.join(gdb_dir, "mongo.py")
        mongo_printers_script = os.path.join(gdb_dir, "mongo_printers.py")
        mongo_lock_script = os.path.join(gdb_dir, "mongo_lock.py")

        source_mongo = "source %s" % mongo_script
        source_mongo_printers = "source %s" % mongo_printers_script
        source_mongo_lock = "source %s" % mongo_lock_script
        mongodb_dump_locks = "mongodb-dump-locks"
        mongodb_show_locks = "mongodb-show-locks"
        mongodb_uniqstack = "mongodb-uniqstack mongodb-bt-if-active"
        mongodb_waitsfor_graph = "mongodb-waitsfor-graph debugger_waitsfor_%s_%d.gv" % \
            (pinfo.name, pinfo.pid)
        mongodb_javascript_stack = "mongodb-javascript-stack"
        mongod_dump_sessions = "mongod-dump-sessions"
        mongodb_dump_mutexes = "mongodb-dump-mutexes"
        mongodb_dump_recovery_units = "mongodb-dump-recovery-units"

        if not logger.mongo_process_filename:
            raw_stacks_commands = []
        else:
            base, ext = os.path.splitext(logger.mongo_process_filename)
            raw_stacks_filename = base + '_raw_stacks' + ext
            raw_stacks_commands = [
                'echo \\nWriting raw stacks to %s.\\n' % raw_stacks_filename,
                # This sends output to log file rather than stdout until we turn logging off.
                'set logging redirect on',
                'set logging file ' + raw_stacks_filename,
                'set logging on',
                'thread apply all bt',
                'set logging off',
            ]

        cmds = [
            "set interactive-mode off",
            "set print thread-events off",  # Suppress GDB messages of threads starting/finishing.
            "attach %d" % pinfo.pid,
            "info sharedlibrary",
            "info threads",  # Dump a simple list of commands to get the thread name
            "set python print-stack full",
        ] + raw_stacks_commands + [
            source_mongo,
            source_mongo_printers,
            source_mongo_lock,
            mongodb_uniqstack,
            # Lock the scheduler, before running commands, which execute code in the attached process.
            "set scheduler-locking on",
            dump_command,
            mongodb_dump_locks,
            mongodb_show_locks,
            mongodb_waitsfor_graph,
            mongodb_javascript_stack,
            mongod_dump_sessions,
            mongodb_dump_mutexes,
            mongodb_dump_recovery_units,
            "set confirm off",
            "quit",
        ]

        call([dbg, "--quiet", "--nx"] + list(
            itertools.chain.from_iterable([['-ex', b] for b in cmds])), logger)

        root_logger.info("Done analyzing %s process with PID %d", pinfo.name, pinfo.pid)
示例#8
0
    def dump_info(  # pylint: disable=too-many-arguments,too-many-locals
            self, root_logger, logger, pinfo, take_dump):
        """Dump info."""
        debugger = "lldb"
        dbg = self.__find_debugger(debugger)

        if dbg is None:
            root_logger.warning("Debugger %s not found, skipping dumping of %d", debugger,
                                pinfo.pid)
            return

        root_logger.info("Debugger %s, analyzing %s process with PID %d", dbg, pinfo.name,
                         pinfo.pid)

        lldb_version = callo([dbg, "--version"], logger)

        logger.info(lldb_version)

        # Do we have the XCode or LLVM version of lldb?
        # Old versions of lldb do not work well when taking commands via a file
        # XCode (7.2): lldb-340.4.119
        # LLVM - lldb version 3.7.0 ( revision )

        if 'version' not in lldb_version:
            # We have XCode's lldb
            lldb_version = lldb_version[lldb_version.index("lldb-"):]
            lldb_version = lldb_version.replace('lldb-', '')
            lldb_major_version = int(lldb_version[:lldb_version.index('.')])
            if lldb_major_version < 340:
                logger.warning("Debugger lldb is too old, please upgrade to XCode 7.2")
                return

        dump_command = ""
        if take_dump:
            # Dump to file, dump_<process name>.<pid>.core
            dump_file = "dump_%s.%d.%s" % (pinfo.name, pinfo.pid, self.get_dump_ext())
            dump_command = "process save-core %s" % dump_file
            root_logger.info("Dumping core to %s", dump_file)

        cmds = [
            "attach -p %d" % pinfo.pid,
            "target modules list",
            "thread backtrace all",
            dump_command,
            "settings set interpreter.prompt-on-quit false",
            "quit",
        ]

        tf = tempfile.NamedTemporaryFile(mode='w', encoding='utf-8')

        for cmd in cmds:
            tf.write(cmd + "\n")

        tf.flush()

        # Works on in MacOS 10.9 & later
        #call([dbg] +  list( itertools.chain.from_iterable([['-o', b] for b in cmds])), logger)
        call(['cat', tf.name], logger)
        call([dbg, '--source', tf.name], logger)

        root_logger.info("Done analyzing %s process with PID %d", pinfo.name, pinfo.pid)