Пример #1
0
    def setup(self):
        """Initialization done before entering the debugger-command
        loop. In particular we set up the call stack used for local
        variable lookup and frame/up/down commands.

        We return True if we should NOT enter the debugger-command
        loop."""
        self.forget()
        if self.settings('dbg_trepan'):
            self.frame = inspect.currentframe()
            pass
        if self.event in ['exception', 'c_exception']:
            exc_type, exc_value, exc_traceback = self.event_arg
        else:
            _, _, exc_traceback = (None, None, None,)  # NOQA
            pass
        if self.frame or exc_traceback:
            self.stack, self.curindex = \
                get_stack(self.frame, exc_traceback, None, self)
            self.curframe = self.stack[self.curindex][0]
            self.thread_name = Mthread.current_thread_name()

        else:
            self.stack = self.curframe = \
                self.botframe = None
            pass
        if self.curframe:
            self.list_lineno = \
                max(1, inspect.getlineno(self.curframe))
        else:
            self.list_lineno = None
            pass
        # if self.execRcLines()==1: return True
        return False
Пример #2
0
    def event_processor(self, frame, event, event_arg, prompt='trepan2'):
        'command event processor: reading a commands do something with them.'
        self.frame     = frame
        self.event     = event
        self.event_arg = event_arg

        filename = frame.f_code.co_filename
        lineno   = frame.f_lineno
        if sys.version_info[0] == 2 and sys.version_info[1] <= 4:
            line = None
        else:
            line = linecache.getline(filename, lineno, frame.f_globals)
            pass
        if not line:
            opts = {'output': 'plain',
                    'reload_on_change': self.settings('reload'),
                    'strip_nl': False}
            line = pyficache.getline(filename, lineno, opts)
        self.current_source_text = line
        if self.settings('skip') is not None:
            if Mbytecode.is_def_stmt(line, frame):
                return True
            if Mbytecode.is_class_def(line, frame):
                return True
            pass
        self.thread_name = Mthread.current_thread_name()
        self.frame_thread_name = self.thread_name
        self.set_prompt(prompt)
        self.process_commands()
        if filename == '<string>': pyficache.remove_remap_file('<string>')
        return True
Пример #3
0
    def event_processor(self, frame, event, event_arg, prompt='Trepan'):
        'command event processor: reading a commands do something with them.'
        self.frame = frame
        self.event = event
        self.event_arg = event_arg

        filename = frame.f_code.co_filename
        lineno = frame.f_lineno
        line = linecache.getline(filename, lineno, frame.f_globals)
        if not line:
            opts = {
                'output': 'plain',
                'reload_on_change': self.settings('reload'),
                'strip_nl': False
            }
            line = pyficache.getline(filename, lineno, opts)
        self.current_source_text = line
        if self.settings('skip') is not None:
            if Mbytecode.is_def_stmt(line, frame):
                return True
            if Mbytecode.is_class_def(line, frame):
                return True
            pass
        self.thread_name = Mthread.current_thread_name()
        self.frame_thread_name = self.thread_name
        self.process_commands()
        return True
Пример #4
0
 def get_from_thread_name_or_id(self, name_or_id, report_error=True):
     """See if *name_or_id* is either a thread name or a thread id.
     The frame of that id/name is returned, or None if name_or_id is
     invalid."""
     thread_id = self.proc.get_int_noerr(name_or_id)
     if thread_id is None:
         # Must be a "frame" command with frame name, not a frame
         # number (or invalid command).
         name2id = Mthread.map_thread_names()
         if name_or_id == ".":
             name_or_id = Mthread.current_thread_name()
             pass
         thread_id = name2id.get(name_or_id)
         if thread_id is None:
             self.errmsg("I don't know about thread name %s." % name_or_id)
             return None, None
         pass
     # Above we should have set thread_id. Now see if we can
     # find it.
     threads = sys._current_frames()
     frame = threads.get(thread_id)
     if frame is None and report_error:
         self.errmsg(
             "I don't know about thread number %s (%d)." % name_or_id, thread_id
         )
         # self.info_thread_terse()
         return None, None
     return frame, thread_id
Пример #5
0
    def find_and_set_debugged_frame(self, frame, thread_id):
        """The dance we have to do to set debugger frame state to
        *frame*, which is in the thread with id *thread_id*. We may
        need to the hide initial debugger frames.
        """
        thread = threading._active[thread_id]
        thread_name = thread.getName()
        if (
            not self.settings["dbg_trepan"]
            and thread_name == Mthread.current_thread_name()
        ):
            # The frame we came in on ('current_thread_name') is
            # the same as the one we want to switch to. In this case
            # we need to some debugger frames are in this stack so
            # we need to remove them.
            newframe = Mthread.find_debugged_frame(frame)
            if newframe is not None:
                frame = newframe
            pass
        # FIXME: else: we might be blocked on other threads which are
        # about to go into the debugger it not for the fact this one got there
        # first. Possibly in the future we want
        # to hide the blocks into threading of that locking code as well.

        # Set stack to new frame
        self.stack, self.curindex = get_stack(frame, None, self.proc)
        self.proc.stack, self.proc.curindex = self.stack, self.curindex
        self.proc.frame_thread_name = thread_name
        return
Пример #6
0
    def event_processor(self, frame, event, event_arg, prompt='trepan3k'):
        'command event processor: reading a commands do something with them.'
        self.frame = frame
        self.event = event
        self.event_arg = event_arg

        filename = frame.f_code.co_filename
        lineno = frame.f_lineno
        line = linecache.getline(filename, lineno, frame.f_globals)
        if not line:
            opts = {
                'output': 'plain',
                'reload_on_change': self.settings('reload'),
                'strip_nl': False
            }
            m = re.search('^<frozen (.*)>', filename)
            if m and m.group(1):
                filename = pyficache.unmap_file(m.group(1))
            line = pyficache.getline(filename, lineno, opts)
        self.current_source_text = line
        if self.settings('skip') is not None:
            if Mbytecode.is_def_stmt(line, frame):
                return True
            if Mbytecode.is_class_def(line, frame):
                return True
            pass
        self.thread_name = Mthread.current_thread_name()
        self.frame_thread_name = self.thread_name
        self.set_prompt(prompt)
        self.process_commands()
        if filename == '<string>': pyficache.remove_remap_file('<string>')
        return True
Пример #7
0
    def event_processor(self, frame, event, event_arg, prompt="Trepan"):
        "command event processor: reading a commands do something with them."
        self.frame = frame
        self.event = event
        self.event_arg = event_arg

        filename = frame.f_code.co_filename
        lineno = frame.f_lineno
        line = linecache.getline(filename, lineno, frame.f_globals)
        if not line:
            opts = {
                "output": "plain",
                "reload_on_change": self.settings("reload"),
                "strip_nl": False,
            }
            line = pyficache.getline(filename, lineno, opts)
        self.current_source_text = line
        if self.settings("skip") is not None:
            if Mbytecode.is_def_stmt(line, frame):
                return True
            if Mbytecode.is_class_def(line, frame):
                return True
            pass
        self.thread_name = Mthread.current_thread_name()
        self.frame_thread_name = self.thread_name
        self.process_commands()
        return True
Пример #8
0
    def find_and_set_debugged_frame(self, frame, thread_id):
        '''The dance we have to do to set debugger frame state to
        *frame*, which is in the thread with id *thread_id*. We may
        need to the hide initial debugger frames.
        '''
        thread = threading._active[thread_id]
        thread_name = thread.getName()
        if (not self.settings['dbg_trepan'] and
            thread_name == Mthread.current_thread_name()):
            # The frame we came in on ('current_thread_name') is
            # the same as the one we want to switch to. In this case
            # we need to some debugger frames are in this stack so
            # we need to remove them.
            newframe = Mthread.find_debugged_frame(frame)
            if newframe is not None:  frame = newframe
            pass
        # FIXME: else: we might be blocked on other threads which are
        # about to go into the debugger it not for the fact this one got there
        # first. Possibly in the future we want
        # to hide the blocks into threading of that locking code as well.

        # Set stack to new frame
        self.stack, self.curindex = Mcmdproc.get_stack(frame, None,
                                                       self.proc)
        self.proc.stack, self.proc.curindex = self.stack, self.curindex
        self.proc.frame_thread_name = thread_name
        return
Пример #9
0
 def get_from_thread_name_or_id(self, name_or_id, report_error=True):
     '''See if *name_or_id* is either a thread name or a thread id.
     The frame of that id/name is returned, or None if name_or_id is
     invalid.'''
     thread_id = self.proc.get_int_noerr(name_or_id)
     if thread_id is None:
         # Must be a "frame" command with frame name, not a frame
         # number (or invalid command).
         name2id = Mthread.map_thread_names()
         if name_or_id == '.':
             name_or_id = Mthread.current_thread_name()
             pass
         thread_id = name2id.get(name_or_id)
         if thread_id is None:
             self.errmsg("I don't know about thread name %s." %
                         name_or_id)
             return None, None
         pass
     # Above we should have set thread_id. Now see if we can
     # find it.
     threads   = sys._current_frames()
     frame     = threads.get(thread_id)
     if frame is None and report_error:
         self.errmsg("I don't know about thread number %s (%d)." %
                     name_or_id, thread_id)
         # self.info_thread_terse()
         return None, None
     return frame, thread_id
Пример #10
0
    def event_processor(self, frame, event, event_arg, prompt="trepan2"):
        "command event processor: reading a commands do something with them."
        self.frame = frame
        self.event = event
        self.event_arg = event_arg

        filename = frame.f_code.co_filename
        lineno = frame.f_lineno
        if sys.version_info[0] == 2 and sys.version_info[1] <= 4:
            line = None
        else:
            line = linecache.getline(filename, lineno, frame.f_globals)
            pass
        if not line:
            opts = {
                "output": "plain",
                "reload_on_change": self.settings("reload"),
                "strip_nl": False,
            }
            line = pyficache.getline(filename, lineno, opts)
        self.current_source_text = line
        if self.settings("skip") is not None:
            if Mbytecode.is_def_stmt(line, frame):
                return True
            if Mbytecode.is_class_def(line, frame):
                return True
            pass
        self.thread_name = Mthread.current_thread_name()
        self.frame_thread_name = self.thread_name
        self.set_prompt(prompt)
        self.process_commands()
        if filename == "<string>":
            pyficache.remove_remap_file("<string>")
        return True
Пример #11
0
    def event_processor(self, frame, event, event_arg, prompt='trepan2'):
        'command event processor: reading a commands do something with them.'
        self.frame = frame
        self.event = event
        self.event_arg = event_arg

        filename = frame.f_code.co_filename
        lineno = frame.f_lineno
        if sys.version_info[0] == 2 and sys.version_info[1] <= 4:
            line = None
        else:
            line = linecache.getline(filename, lineno, frame.f_globals)
            pass
        if not line:
            opts = {
                'output': 'plain',
                'reload_on_change': self.settings('reload'),
                'strip_nl': False
            }
            line = pyficache.getline(filename, lineno, opts)
        self.current_source_text = line
        if self.settings('skip') is not None:
            if Mbytecode.is_def_stmt(line, frame):
                return True
            if Mbytecode.is_class_def(line, frame):
                return True
            pass
        self.thread_name = Mthread.current_thread_name()
        self.frame_thread_name = self.thread_name
        self.set_prompt(prompt)
        self.process_commands()
        if filename == '<string>': pyficache.remove_remap_file('<string>')
        return True
Пример #12
0
    def event_processor(self, frame, event, event_arg, prompt='Trepan'):
        'command event processor: reading a commands do something with them.'
        self.frame     = frame
        self.event     = event
        self.event_arg = event_arg

        filename = frame.f_code.co_filename
        lineno   = frame.f_lineno
        line     = linecache.getline(filename, lineno, frame.f_globals)
        if not line:
            opts = {'output': 'plain',
                    'reload_on_change': self.settings('reload'),
                    'strip_nl': False}
            line = pyficache.getline(filename, lineno, opts)
        self.current_source_text = line
        if self.settings('skip') is not None:
            if Mbytecode.is_def_stmt(line, frame):
                return True
            if Mbytecode.is_class_def(line, frame):
                return True
            pass
        self.thread_name = Mthread.current_thread_name()
        self.frame_thread_name = self.thread_name
        self.process_commands()
        return True
Пример #13
0
    def setup(self):
        """Initialization done before entering the debugger-command
        loop. In particular we set up the call stack used for local
        variable lookup and frame/up/down commands.

        We return True if we should NOT enter the debugger-command
        loop."""
        self.forget()
        if self.settings("dbg_trepan"):
            self.frame = inspect.currentframe()
            pass
        if self.event in ["exception", "c_exception"]:
            exc_type, exc_value, exc_traceback = self.event_arg
        else:
            _, _, exc_traceback = (
                None,
                None,
                None,
            )  # NOQA
            pass
        if self.frame or exc_traceback:
            self.stack, self.curindex = get_stack(self.frame, exc_traceback,
                                                  None, self)
            self.curframe = self.stack[self.curindex][0]
            self.thread_name = Mthread.current_thread_name()
            if exc_traceback:
                self.list_lineno = traceback.extract_tb(exc_traceback, 1)[0][1]
                self.list_offset = self.curframe.f_lasti
                self.list_object = self.curframe
        else:
            self.stack = self.curframe = self.botframe = None
            pass
        if self.curframe:
            self.list_lineno = (max(
                1,
                inspect.getlineno(self.curframe) -
                int(self.settings("listsize") / 2),
            ) - 1)
            self.list_offset = self.curframe.f_lasti
            self.list_filename = self.curframe.f_code.co_filename
            self.list_object = self.curframe
        else:
            self.list_object = None
            if not exc_traceback:
                self.list_lineno = None
            pass
        # if self.execRcLines()==1: return True

        # FIXME:  do we want to save self.list_lineno a second place
        # so that we can do 'list .' and go back to the first place we listed?
        return False
Пример #14
0
    def event_processor(self, frame, event, event_arg, prompt="trepan3k"):
        """
        command event processor: reading a commands do something with them.

        See https://docs.python.org/3/library/sys.html#sys.settrace
        for how this protocol works and what the events means.

        Of particular note those is what we return:

            The local trace function should return a reference to
            itself (or to another function for further tracing in that
            scope), or None to turn off tracing in that scope.

            If there is any error occurred in the trace function, it
            will be unset, just like settrace(None) is called.
        """

        self.frame = frame
        self.event = event
        self.event_arg = event_arg

        filename = frame.f_code.co_filename
        lineno = frame.f_lineno
        line = linecache.getline(filename, lineno, frame.f_globals)
        if not line:
            opts = {
                "output": "plain",
                "reload_on_change": self.settings("reload"),
                "strip_nl": False,
            }
            m = re.search("^<frozen (.*)>", filename)
            if m and m.group(1):
                filename = pyficache.unmap_file(m.group(1))
            line = pyficache.getline(filename, lineno, opts)
        self.current_source_text = line
        if self.settings("skip") is not None:
            if is_def_stmt(line, frame):
                return self.event_processor
            if is_class_def(line, frame):
                return self.event_processor
            pass
        self.thread_name = Mthread.current_thread_name()
        self.frame_thread_name = self.thread_name
        self.set_prompt(prompt)
        self.process_commands()
        if filename == "<string>":
            pyficache.remove_remap_file("<string>")
        return self.event_processor
Пример #15
0
    def setup(self):
        """Initialization done before entering the debugger-command
        loop. In particular we set up the call stack used for local
        variable lookup and frame/up/down commands.

        We return True if we should NOT enter the debugger-command
        loop."""
        self.forget()
        if self.settings('dbg_trepan'):
            self.frame = inspect.currentframe()
            pass
        if self.event in ['exception', 'c_exception']:
            exc_type, exc_value, exc_traceback = self.event_arg
        else:
            _, _, exc_traceback = (None, None, None,)  # NOQA
            pass
        if self.frame or exc_traceback:
            self.stack, self.curindex = \
                get_stack(self.frame, exc_traceback, None, self)
            self.curframe = self.stack[self.curindex][0]
            self.thread_name = Mthread.current_thread_name()
            if exc_traceback:
                self.list_lineno = traceback.extract_tb(exc_traceback, 1)[0][1]
                self.list_offset = self.curframe.f_lasti
                self.list_object = self.curframe
        else:
            self.stack = self.curframe = \
                self.botframe = None
            pass
        if self.curframe:
            self.list_lineno = \
                max(1, inspect.getlineno(self.curframe)
                    - int(self.settings('listsize') / 2)) - 1
            self.list_offset   = self.curframe.f_lasti
            self.list_filename = self.curframe.f_code.co_filename
            self.list_object   = self.curframe
        else:
            if not exc_traceback: self.list_lineno = None
            pass
        # if self.execRcLines()==1: return True

        # FIXME:  do we want to save self.list_lineno a second place
        # so that we can do 'list .' and go back to the first place we listed?
        return False
Пример #16
0
    def setup(self):
        """Initialization done before entering the debugger-command
        loop. In particular we set up the call stack used for local
        variable lookup and frame/up/down commands.

        We return True if we should NOT enter the debugger-command
        loop."""
        self.forget()
        if self.settings('dbg_trepan'):
            self.frame = inspect.currentframe()
            pass
        if self.event in ['exception', 'c_exception']:
            exc_type, exc_value, exc_traceback = self.event_arg
        else:
            _, _, exc_traceback = (
                None,
                None,
                None,
            )  # NOQA
            pass
        if self.frame or exc_traceback:
            self.stack, self.curindex = \
                get_stack(self.frame, exc_traceback, None, self)
            self.curframe = self.stack[self.curindex][0]
            self.thread_name = Mthread.current_thread_name()
            if exc_traceback:
                self.list_lineno = traceback.extract_tb(exc_traceback, 1)[0][1]

        else:
            self.stack = self.curframe = \
                self.botframe = None
            pass
        if self.curframe:
            self.list_lineno = \
                max(1, inspect.getlineno(self.curframe)
                    - int(self.settings('listsize') / 2)) - 1
            self.list_filename = self.curframe.f_code.co_filename
        else:
            if not exc_traceback: self.list_lineno = None
            pass
        # if self.execRcLines()==1: return True
        return False
Пример #17
0
    def setup(self):
        """Initialization done before entering the debugger-command
        loop. In particular we set up the call stack used for local
        variable lookup and frame/up/down commands.

        We return True if we should NOT enter the debugger-command
        loop."""
        self.forget()
        if self.settings("dbg_trepan"):
            self.frame = inspect.currentframe()
            pass
        if self.event in ["exception", "c_exception"]:
            exc_type, exc_value, exc_traceback = self.event_arg
        else:
            _, _, exc_traceback = (
                None,
                None,
                None,
            )  # NOQA
            pass
        if self.frame or exc_traceback:
            self.stack, self.curindex = get_stack(self.frame, exc_traceback,
                                                  None, self)
            self.curframe = self.stack[self.curindex][0]
            self.thread_name = Mthread.current_thread_name()

        else:
            self.stack = self.curframe = self.botframe = None
            pass
        if self.curframe:
            self.list_lineno = max(1, inspect.getlineno(self.curframe))
        else:
            self.list_lineno = None
            pass
        # if self.execRcLines()==1: return True
        return False
Пример #18
0
 def test_current_thread_name(self):
     self.assertEqual('MainThread', Mthread.current_thread_name())
     return
 def test_current_thread_name(self):
     self.assertEqual('MainThread', Mthread.current_thread_name())
     return
Пример #20
0
    def run(self, args):
        # FIXME: add thread locking here?

        self.thread_name = Mthread.current_thread_name()

        name2id = Mthread.map_thread_names()
        # invert threading._active
        for thread_id in list(threading._active.keys()):
            thread = threading._active[thread_id]
            name = thread.getName()
            if name not in list(self.name2id.keys()):
                self.name2id[name] = thread_id
                pass
            pass

        all_verbose = False
        if len(args) == 1:
            if args[0].startswith('verbose'):
                all_verbose = True
            elif args[0].startswith('terse'):
                self.info_thread_terse(name2id)
                return
            pass

        if len(args) > 0 and not all_verbose:
            thread_name = args[0]
            if thread_name == '.':
                thread_name = self.thread_name
            try:
                thread_id = int(thread_name)
                if thread_id not in list(threading._active.keys()):
                    self.errmsg("Don't know about thread number %s" %
                                thread_name)
                    self.info_thread_terse(name2id)
                    return
            except ValueError:
                if thread_name not in list(self.name2id.keys()):
                    self.errmsg("Don't know about thread %s" % thread_name)
                    self.info_thread_terse(name2id)
                    return
                thread_id = self.name2id[thread_name]
                pass

            frame = sys._current_frames()[thread_id]
            self.stack_trace(frame)
            return

        # Show info about *all* threads
        thread_key_list = list(self.name2id.keys())
        thread_key_list.sort()
        for thread_name in thread_key_list:
            thread_id = self.name2id[thread_name]
            frame = sys._current_frames()[thread_id]
            s = ''
            # Print location where thread was created and line number
            if thread_id in threading._active:
                thread = threading._active[thread_id]
                thread_name = thread.getName()
                if thread_name == self.proc.frame_thread_name:
                    prefix = '-> '
                    if not self.settings['dbg_trepan']:
                        frame = Mthread.find_debugged_frame(frame)
                        pass
                    pass
                elif thread_name == self.proc.thread_name:
                    prefix = '=> '
                else:
                    prefix='   '
                    pass
                s += "%s%s" % (prefix, str(thread))
                if all_verbose:
                    s += ": %d" % thread_id
                    pass
            else:
                s += "    thread id: %d" % thread_id
                pass
            s += "\n    "
            s += Mstack.format_stack_entry(self, (frame, frame.f_lineno),
                                           color=self.settings['highlight'])
            self.section('-' * 40)
            self.msg(s)
            frame = frame.f_back
            if all_verbose and frame:
                self.stack_trace(frame)
                pass
        return
Пример #21
0
    def event_hook(
        self,
        event: str,
        offset: int,
        byteName: str,
        byteCode: int,
        line_number: int,
        intArg: Optional[int],
        event_arg: Any,
        vm: Any,
        prompt="trepan-xpy",
    ):
        "command event processor: reading a commands do something with them."

        def frame_setup(frame):
            filename = frame.f_code.co_filename
            lineno = frame.f_lineno
            line = linecache.getline(filename, lineno, frame.f_globals)
            if not line:
                opts = {
                    "output": "plain",
                    "reload_on_change": self.settings("reload"),
                    "strip_nl": False,
                }
                m = re.search("^<frozen (.*)>", filename)
                if m and m.group(1):
                    filename = pyficache.unmap_file(m.group(1))
                line = pyficache.getline(filename, lineno, opts)
            self.current_source_text = line
            return line, filename

        self.vm = vm
        self.frame = vm.frame
        self.event = event
        self.event_arg = event_arg

        # In order to follow Python's sys.settrace()'s convention:
        # returning "None" turns off tracing for the scope.
        # However we do not need to return a reference to ourself,
        # a callable (this may be allowed in the future though).
        # Instead for now a string status is returned
        # * "skip" for skip next instruction, and
        # * "return" for immediate return
        # * "finish" for "step out"

        self.return_status = True

        if event == "fatal":
            self.core.execution_status = "Terminated"
            # One last hurrah!

            tb = vm.last_traceback
            if tb:
                frame_setup(tb.tb_frame)
                self.vm.frames = []
                while tb:
                    self.vm.frames.insert(0, tb.tb_frame)
                    tb = tb.tb_next
                self.curframe = self.frame = self.vm.frames[0]
                self.setup()
                self.curindex = len(vm.frames) - 1
                print_location(self)

            self.set_prompt("trepan-xpy:pm")
            self.process_commands()
            return None

        if self.vm.frame:
            self.core.execution_status = "Running"
        else:
            self.core.execution_status = "Terminated"
            return

        line, filename = frame_setup(self.frame)
        if self.settings("skip"):
            # Note that in contrast to skipping intructions
            # when return_status is set to "skip", here
            # we are execution the instruction but just skipping
            # any handling this instruction the debugger.
            if Mbytecode.is_def_stmt(line, self.frame):
                return self
            if Mbytecode.is_class_def(line, self.frame):
                return
            pass
        self.thread_name = current_thread_name()
        self.frame_thread_name = self.thread_name

        self.setup()
        print_location(self)
        if offset >= 0 and event not in ('call', 'return'):
            self.msg("%s" % format_instruction_with_highlight(
                vm.frame,
                vm.opc,
                byteName,
                intArg,
                event_arg,
                offset,
                line_number,
                extra_debug=False,
                settings=self.debugger.settings,
                show_line=
                False,  # We show the line number in our location reporting
                vm=self.vm,
                repr=self._repr.repr))

        self.set_prompt(prompt)
        self.process_commands()
        if filename == "<string>":
            pyficache.remove_remap_file("<string>")
        return self.return_status
Пример #22
0
    def run(self, args):
        # FIXME: add thread locking here?

        self.thread_name = Mthread.current_thread_name()

        name2id = Mthread.map_thread_names()
        # invert threading._active
        for thread_id in list(threading._active.keys()):
            thread = threading._active[thread_id]
            name = thread.getName()
            if name not in list(self.name2id.keys()):
                self.name2id[name] = thread_id
                pass
            pass

        all_verbose = False
        if len(args) == 1:
            if args[0].startswith('verbose'):
                all_verbose = True
            elif args[0].startswith('terse'):
                self.info_thread_terse(name2id)
                return
            pass

        if len(args) > 0 and not all_verbose:
            thread_name = args[0]
            if thread_name == '.':
                thread_name = self.thread_name
            try:
                thread_id = int(thread_name)
                if thread_id not in list(threading._active.keys()):
                    self.errmsg("Don't know about thread number %s" %
                                thread_name)
                    self.info_thread_terse(name2id)
                    return
            except ValueError:
                if thread_name not in list(self.name2id.keys()):
                    self.errmsg("Don't know about thread %s" % thread_name)
                    self.info_thread_terse(name2id)
                    return
                thread_id = self.name2id[thread_name]
                pass

            frame = sys._current_frames()[thread_id]
            self.stack_trace(frame)
            return

        # Show info about *all* threads
        thread_key_list = list(self.name2id.keys())
        thread_key_list.sort()
        for thread_name in thread_key_list:
            thread_id = self.name2id[thread_name]
            frame = sys._current_frames()[thread_id]
            s = ''
            # Print location where thread was created and line number
            if thread_id in threading._active:
                thread = threading._active[thread_id]
                thread_name = thread.getName()
                if thread_name == self.proc.frame_thread_name:
                    prefix = '-> '
                    if not self.settings['dbg_trepan']:
                        frame = Mthread.find_debugged_frame(frame)
                        pass
                    pass
                elif thread_name == self.proc.thread_name:
                    prefix = '=> '
                else:
                    prefix = '   '
                    pass
                s += "%s%s" % (prefix, str(thread))
                if all_verbose:
                    s += ": %d" % thread_id
                    pass
            else:
                s += "    thread id: %d" % thread_id
                pass
            s += "\n    "
            s += Mstack.format_stack_entry(self, (frame, frame.f_lineno),
                                           color=self.settings['highlight'])
            self.section('-' * 40)
            self.msg(s)
            frame = frame.f_back
            if all_verbose and frame:
                self.stack_trace(frame)
                pass
        return