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)
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))
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)
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"]
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)
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)
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)
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)