示例#1
0
def run_eval(expression,
             debug_opts=None,
             start_opts=None,
             globals_=None,
             locals_=None,
             tb_fn=None):
    """Evaluate the expression (given as a string) under debugger
    control starting with the statement subsequent to the place that
    this appears in your program.

    This is a wrapper to Debugger.run_eval(), so see that.

    When run_eval() returns, it returns the value of the expression.
    Otherwise this function is similar to run().
    """

    dbg = Mdebugger.Trepan(opts=debug_opts)
    try:
        return dbg.run_eval(expression,
                            start_opts=start_opts,
                            globals_=globals_,
                            locals_=locals_)
    except:
        dbg.core.trace_hook_suspend = True
        if start_opts and 'tb_fn' in start_opts: tb_fn = start_opts['tb_fn']
        Mpost_mortem.uncaught_exception(dbg, tb_fn)
    finally:
        dbg.core.trace_hook_suspend = False
    return
示例#2
0
def run_exec(statement,
             debug_opts=None,
             start_opts=None,
             globals_=None,
             locals_=None):
    """Execute the statement (given as a string) under debugger
    control starting with the statement subsequent to the place that
    this run_call appears in your program.

    This is a wrapper to Debugger.run_exec(), so see that.

    The debugger prompt appears before any code is executed;
    you can set breakpoints and type 'continue', or you can step
    through the statement using 'step' or 'next'

    The optional globals_ and locals_ arguments specify the environment
    in which the code is executed; by default the dictionary of the
    module __main__ is used."""

    dbg = Mdebugger.Trepan(opts=debug_opts)
    try:
        return dbg.run_exec(statement,
                            start_opts=start_opts,
                            globals_=globals_,
                            locals_=locals_)
    except:
        Mpost_mortem.uncaught_exception(dbg)
        pass
    return
示例#3
0
    def test_list_command(self):
        import inspect
        d = debugger.Trepan()
        cp = d.core.processor
        cp.curframe = inspect.currentframe()
        cp.list_filename = cp.curframe.f_code.co_filename
        self.cmd = Mlist.ListCommand(cp)
        self.cmd.msg = self.msg
        self.cmd.errmsg = self.errmsg
        d.settings['listsize'] = self.listsize
        d.settings['highlight'] = 'plain'
        # from trepan.api import debug; debug()
        # Simple list command.
        self.clear_run_check(['list'], list(range(1, self.listsize + 1)))
        # Check 2nd set of consecutive lines
        self.clear_run_check(['list'],
                             list(
                                 range(self.listsize + 1,
                                       (2 * self.listsize) + 1)))
        # Try going backwards.
        self.clear_run_check(['list', '-'], list(range(1, 1 + self.listsize)))
        # And again. Since we hit the beginning it's the same as before
        self.clear_run_check(['list', '-'], list(range(1, 1 + self.listsize)))

        # BUG Simple arithmetic expression
        # self.clear_run_check(['list', '4+1'], range(4+1, 4+1+listsize))

        # List first last
        self.clear_run_check(['list', '10', ',', '20'], list(range(10, 21)))
        # List first count
        self.clear_run_check(['list', '10', ',', '5'], list(range(10, 16)))

        # Module
        # BUG? without '1' below the default starts with self.listsize+1
        self.clear_run_check(['os.path', '1'],
                             list(range(1, self.listsize + 2)))

        # # Function
        # self.clear_run_checksize(['list', 'os.path.join()'])
        # self.clear_run_checksize(['list', 'self.setUp()'])

        def foo():
            pass

        self.clear_run_checksize(['list', 'foo()'])

        # BUG
        # self.clear_run_check(['os.path:1'], range(1, self.listsize+1))
        self.clear_run_check(['os.path', '10', ',5'], list(range(10, 16)))
        # Use a file name

        if 'APPVEYOR' not in os.environ:
            self.clear_run_check(['list', __file__ + ':3', ',4'],
                                 list(range(3, 5)))

        # BUGS - but possibly the windowing thing is happening?
        # self.clear_run_check(['list', __file__, '3'], list(range(3, 5)))
        # self.clear_run_check(['list', __file__, '20', '4'], list(range(20, 24)))
        # self.clear_run_check(['list', __file__, '3', '4'], list(range(3, 5)))
        return
示例#4
0
    def test_parse_break_cmd(self):
        import inspect
        d = debugger.Trepan()
        cp = d.core.processor
        cp.curframe = inspect.currentframe()
        self.cmd = Mbreak.BreakCommand(cp)
        self.cmd.msg = self.msg
        self.cmd.errmsg = self.errmsg

        fn, fi, li, cond = Mcmdbreak.parse_break_cmd(self.cmd, [])
        self.assertEqual((None, True, True),
                         (fn, fi.endswith('test-break.py'), li > 1))

        fn, fi, li, cond = Mcmdbreak.parse_break_cmd(self.cmd, ['11-1'])
        self.assertEqual((None, True, 10),
                         (fn, fi.endswith('test-break.py'), li))

        fn, fi, li, cond = Mcmdbreak.parse_break_cmd(self.cmd,
                                                     [__file__ + ':10'])
        self.assertEqual((None, 10), (fn, li))

        def foo():
            return 'bar'

        fn, fi, li, cond = Mcmdbreak.parse_break_cmd(self.cmd, ['foo'])
        self.assertEqual((foo, True, True),
                         (fn, fi.endswith('test-break.py'), li > 1))

        fn, fi, li, cond = Mcmdbreak.parse_break_cmd(self.cmd, ['food'])
        self.assertEqual((None, None, None, None), (fn, fi, li, cond))

        fn, fi, li, cond = Mcmdbreak.parse_break_cmd(self.cmd, ['os.path'])
        self.assertEqual((None, None), (fn, li))

        fn, fi, li, cond = Mcmdbreak.parse_break_cmd(self.cmd,
                                                     ['os.path', '5+1'])
        self.assertEqual((None, 6), (fn, li))

        fn, fi, li, cond = Mcmdbreak.parse_break_cmd(self.cmd,
                                                     ['os.path.join'])
        self.assertEqual((os.path.join, True), (fn, li > 1))

        fn, fi, li, cond = Mcmdbreak.parse_break_cmd(self.cmd, ['if', 'True'])
        self.assertEqual((None, True, True),
                         (fn, fi.endswith('test-break.py'), li > 1))

        fn, fi, li, cond = Mcmdbreak.parse_break_cmd(self.cmd,
                                                     ['foo', 'if', 'True'])
        self.assertEqual((foo, True, True),
                         (fn, fi.endswith('test-break.py'), li > 1))

        fn, fi, li, cond = Mcmdbreak.parse_break_cmd(
            self.cmd, ['os.path:10', 'if', 'True'])
        self.assertEqual(10, li)

        # FIXME:
        # Try a breakpoint with a symlink in the filename.
        # Also, add a unit test for canonic.

        return
示例#5
0
def strarray_setup(debugger_cmds):
    ''' Common setup to create a debugger with stringio attached '''
    stringin = Mstringarray.StringArrayInput(debugger_cmds)
    stringout = Mstringarray.StringArrayOutput()
    d_opts = {'input': stringin, 'output': stringout}
    d = Mdebugger.Trepan(d_opts)
    d.settings['basename'] = True
    d.settings['different'] = False
    d.settings['autoeval'] = False
    d.settings['highlight'] = 'plain'
    return d
示例#6
0
 def setUp(self):
     self.errors = []
     self.msgs = []
     d = Mdebugger.Trepan()
     self.cmdproc = d.core.processor
     self.cmdproc.curframe = inspect.currentframe()
     cmd = self.cmdproc.commands['alias']
     cmd.msg = self.msg
     cmd.errmsg = self.errmsg
     cmd = self.cmdproc.commands['unalias']
     cmd.msg = self.msg
     cmd.errmsg = self.errmsg
     return
示例#7
0
    def test_complete_identifier(self):
        from trepan.processor.command import base_cmd as mBaseCmd
        from trepan.processor import complete as mComplete
        self.dbgr = Mdebugger.Trepan()

        cmdproc = self.dbgr.core.processor
        cmdproc.curframe = inspect.currentframe()
        cmd = mBaseCmd.DebuggerCommand(cmdproc)

        self.assertEqual(mComplete.complete_id_and_builtins(cmd, 'ma'),
                         ['map', 'max'])
        self.assertEqual(mComplete.complete_identifier(cmd, 'm'),
                         ['mBaseCmd', 'mComplete'])
        return
示例#8
0
 def test_pdef(self):
     import inspect
     d = debugger.Trepan()
     cp = d.core.processor
     cp.curframe = inspect.currentframe()
     cmd = Mp.PrintDefCommand(cp)
     cmd.msg = self.msg
     cmd.errmsg = cp.errmsg = self.errmsg
     cmd.run(['pdef', 'self.test_pdef'])
     self.assertEqual('self.test_pdef(self)', self.msgs[-1])
     cmd.run(['pdef', 'TestPDef'])
     self.assertEqual("TestPDef(self, methodName='runTest')", self.msgs[-1])
     self.assertEqual(0, len(self.errors))
     cmd.run(['pdef', 'FOO'])
     self.assertEqual(1, len(self.errors))
     return
示例#9
0
    def test_info_file(self):
        d = Mdebugger.Trepan()
        d, cp = dbg_setup(d)
        command = Minfo.InfoCommand(cp, 'info')

        sub = MinfoFile.InfoFiles(command)
        self.setup_io(sub)
        sub.run([])
        self.assertEqual([], self.msgs)
        cp.curframe = inspect.currentframe()
        for width in (80, 200):
            # sub.settings['width'] = width
            sub.run(['test-info-file.py', 'lines'])
            sub.run([])
            pass
        pass
示例#10
0
 def test_pr(self):
     import inspect
     d = debugger.Trepan()
     cp = d.core.processor
     cp.curframe = inspect.currentframe()
     cmd = Mp.PrCommand(cp)
     cmd.msg = self.msg
     cmd.errmsg = self.errmsg
     me = 10  # NOQA
     cmd.run([cmd.name, 'me'])
     self.assertEqual('10', self.msgs[-1])
     cmd.run([cmd.name, '/x', 'me'])
     self.assertEqual("'0xa'", self.msgs[-1])
     cmd.run([cmd.name, '/o', 'me'])
     self.assertEqual("'0o12'", self.msgs[-1])
     return
示例#11
0
def run_call(func, debug_opts=None, start_opts=None, *args, **kwds):
    """Call the function (a function or method object, not a string)
    with the given arguments starting with the statement subsequent to
    the place that this appears in your program.

    When run_call() returns, it returns whatever the function call
    returned.  The debugger prompt appears as soon as the function is
    entered."""

    dbg = Mdebugger.Trepan(opts=debug_opts)
    try:
        return dbg.run_call(func, start_opts, *args, **kwds)
    except:
        Mpost_mortem.uncaught_exception(dbg)
        pass
    return
示例#12
0
                text = self.proc.current_source_text.rstrip('\n')
                if '?' == args[0][-1]:
                    text = Meval.extract_expression(text)
                    self.msg("eval: %s" % text)
                    pass
            else:
                self.errmsg("Don't have find program source text")
                return
        else:
            text = self.proc.current_command[len(self.proc.cmd_name):]
            pass
        text = text.strip()
        try:
            self.proc.exec_line(text)
        except:
            pass


if __name__ == '__main__':
    import inspect
    from trepan import debugger
    d = debugger.Trepan()
    cp = d.core.processor
    cp.curframe = inspect.currentframe()
    command = EvalCommand(cp)
    me = 10

    # command.run([command.name, '1+2'])
    # command.run([command.name, 'if 5: x=1'])
    pass
示例#13
0
def main(dbg=None, sys_argv=list(sys.argv)):
    """Routine which gets run if we were invoked directly"""
    global __title__

    # Save the original just for use in the restart that works via exec.
    orig_sys_argv = list(sys_argv)
    opts, dbg_opts, sys_argv  = Moptions.process_options(__title__,
                                                         __version__,
                                                         sys_argv)

    if opts.server is not None:
        if opts.server == 'tcp':
            connection_opts={'IO': 'TCP', 'PORT': opts.port}
        else:
            connection_opts={'IO': 'FIFO'}
        intf = Mserver.ServerInterface(connection_opts=connection_opts)
        dbg_opts['interface'] = intf
        if 'FIFO' == intf.server_type:
            print('Starting FIFO server for process %s.' % os.getpid())
        elif 'TCP' == intf.server_type:
            print('Starting TCP server listening on port %s.' %
                  intf.inout.PORT)
            pass
    elif opts.client:
        Mclient.main(opts, sys_argv)
        return

    dbg_opts['orig_sys_argv'] = orig_sys_argv

    if dbg is None:
        dbg = Mdebugger.Trepan(dbg_opts)
        dbg.core.add_ignore(main)
        pass
    Moptions._postprocess_options(dbg, opts)

    # process_options has munged sys.argv to remove any options that
    # options that belong to this debugger. The original options to
    # invoke the debugger and script are in global sys_argv

    if len(sys_argv) == 0:
        # No program given to debug. Set to go into a command loop
        # anyway
        mainpyfile = None
    else:
        mainpyfile = sys_argv[0]  # Get script filename.
        if not os.path.isfile(mainpyfile):
            mainpyfile=Mclifns.whence_file(mainpyfile)
            is_readable = Mfile.readable(mainpyfile)
            if is_readable is None:
                print("%s: Python script file '%s' does not exist"
                      % (__title__, mainpyfile,))
                sys.exit(1)
            elif not is_readable:
                print("%s: Can't read Python script file '%s'"
                      % (__title__, mainpyfile, ))
                sys.exit(1)
                return

        # If mainpyfile is an optimized Python script try to find and
        # use non-optimized alternative.
        mainpyfile_noopt = Mfile.file_pyc2py(mainpyfile)
        if mainpyfile != mainpyfile_noopt \
               and Mfile.readable(mainpyfile_noopt):
            print("%s: Compiled Python script given and we can't use that."
                  % __title__)
            print("%s: Substituting non-compiled name: %s" % (
                __title__, mainpyfile_noopt,))
            mainpyfile = mainpyfile_noopt
            pass

        # Replace trepan's dir with script's dir in front of
        # module search path.
        sys.path[0] = dbg.main_dirname = os.path.dirname(mainpyfile)

    # XXX If a signal has been received we continue in the loop, otherwise
    # the loop exits for some reason.
    dbg.sig_received = False

    # if not mainpyfile:
    #     print('For now, you need to specify a Python script name!')
    #     sys.exit(2)
    #     pass

    while True:

        # Run the debugged script over and over again until we get it
        # right.

        try:
            if dbg.program_sys_argv and mainpyfile:
                normal_termination = dbg.run_script(mainpyfile)
                if not normal_termination: break
            else:
                dbg.core.execution_status = 'No program'
                dbg.core.processor.process_commands()
                pass

            dbg.core.execution_status = 'Terminated'
            dbg.intf[-1].msg("The program finished - quit or restart")
            dbg.core.processor.process_commands()
        except Mexcept.DebuggerQuit:
            break
        except Mexcept.DebuggerRestart:
            dbg.core.execution_status = 'Restart requested'
            if dbg.program_sys_argv:
                sys.argv = list(dbg.program_sys_argv)
                part1 = ('Restarting %s with arguments:' %
                         dbg.core.filename(mainpyfile))
                args  = ' '.join(dbg.program_sys_argv[1:])
                dbg.intf[-1].msg(
                    Mmisc.wrapped_lines(part1, args,
                                        dbg.settings['width']))
            else: break
        except SystemExit:
            # In most cases SystemExit does not warrant a post-mortem session.
            break
        pass

    # Restore old sys.argv
    sys.argv = orig_sys_argv
    return
示例#14
0
def main(dbg=None, sys_argv=list(sys.argv)):
    """Routine which gets run if we were invoked directly"""
    global __title__

    # Save the original just for use in the restart that works via exec.
    orig_sys_argv = list(sys_argv)
    opts, dbg_opts, sys_argv = process_options(__title__, __version__, sys_argv)
    dbg_opts["orig_sys_argv"] = sys_argv
    dbg_opts["interface"] = BWInterface()
    dbg_opts["processor"] = "bullwinkle"

    if dbg is None:
        dbg = Mdebugger.Trepan(dbg_opts)
        dbg.core.add_ignore(main)
        pass
    _postprocess_options(dbg, opts)

    # process_options has munged sys.argv to remove any options that
    # options that belong to this debugger. The original options to
    # invoke the debugger and script are in global sys_argv
    if len(sys_argv) == 0:
        # No program given to debug. Set to go into a command loop
        # anyway
        mainpyfile = None
    else:
        mainpyfile = sys_argv[0]  # Get script filename.
        if not osp.isfile(mainpyfile):
            mainpyfile = Mclifns.whence_file(mainpyfile)
            is_readable = readable(mainpyfile)
            if is_readable is None:
                print(
                    "%s: Python script file '%s' does not exist"
                    % (
                        __title__,
                        mainpyfile,
                    )
                )
                sys.exit(1)
            elif not is_readable:
                print(
                    "%s: Can't read Python script file '%s'"
                    % (
                        __title__,
                        mainpyfile,
                    )
                )
                sys.exit(1)
                return

        # If mainpyfile is an optimized Python script try to find and
        # use non-optimized alternative.
        mainpyfile_noopt = pyficache.resolve_name_to_file(mainpyfile)
        if mainpyfile != mainpyfile_noopt and readable(mainpyfile_noopt):
            print("%s: Compiled Python script given and we can't use that." % __title__)
            print(
                "%s: Substituting non-compiled name: %s"
                % (
                    __title__,
                    mainpyfile_noopt,
                )
            )
            mainpyfile = mainpyfile_noopt
            pass

        # Replace trepan's dir with script's dir in front of
        # module search path.
        sys.path[0] = dbg.main_dirname = osp.dirname(mainpyfile)

    # XXX If a signal has been received we continue in the loop, otherwise
    # the loop exits for some reason.
    dbg.sig_received = False

    # if not mainpyfile:
    #     print('For now, you need to specify a Python script name!')
    #     sys.exit(2)
    #     pass

    while True:

        # Run the debugged script over and over again until we get it
        # right.

        try:
            if dbg.program_sys_argv and mainpyfile:
                normal_termination = dbg.run_script(mainpyfile)
                if not normal_termination:
                    break
            else:
                dbg.core.execution_status = "No program"
                dbg.core.processor.process_commands()
                pass

            dbg.core.execution_status = "Terminated"
            dbg.intf[-1].msg("The program finished - quit or restart")
            dbg.core.processor.process_commands()
        except Mexcept.DebuggerQuit:
            break
        except Mexcept.DebuggerRestart:
            dbg.core.execution_status = "Restart requested"
            if dbg.program_sys_argv:
                sys.argv = list(dbg.program_sys_argv)
                part1 = "Restarting %s with arguments:" % dbg.core.filename(mainpyfile)
                args = " ".join(dbg.program_sys_argv[1:])
                dbg.intf[-1].msg(
                    Mmisc.wrapped_lines(part1, args, dbg.settings["width"])
                )
            else:
                break
        except SystemExit:
            # In most cases SystemExit does not warrant a post-mortem session.
            break
        pass

    # Restore old sys.argv
    sys.argv = orig_sys_argv
    return
示例#15
0
                    else:
                        val = self.proc.getval(name)
                        pass
                    Mpp.pp(val,
                           self.settings['width'],
                           self.msg_nocr,
                           self.msg,
                           prefix='%s =' % name)
                else:
                    self.errmsg("%s is not a local variable" % name)
                    pass
        return False

    pass


if __name__ == '__main__':
    from trepan.processor.command import mock, info as Minfo
    from trepan import debugger as Mdebugger
    d = Mdebugger.Trepan()
    d, cp = mock.dbg_setup(d)
    i = Minfo.InfoCommand(cp)
    sub = InfoLocals(i)
    l = list(range(30))  # Add a simple array to the local mix printed below.
    import inspect
    cp.curframe = inspect.currentframe()
    sub.run([])
    sub.run(['*'])
    sub.run(['Minfo'])
    pass
示例#16
0
def debug(dbg_opts=None,
          start_opts=None,
          post_mortem=True,
          step_ignore=1,
          level=0):
    """
Enter the debugger.

Parameters
----------

level : how many stack frames go back. Usually it will be
the default 0. But sometimes though there may be calls in setup to the debugger
that you may want to skip.

step_ignore : how many line events to ignore after the
debug() call. 0 means don't even wait for the debug() call to finish.

param dbg_opts : is an optional "options" dictionary that gets fed
trepan.Debugger(); `start_opts' are the optional "options"
dictionary that gets fed to trepan.Debugger.core.start().

Use like this:

.. code-block:: python

    ... # Possibly some Python code
    import trepan.api # Needed only once
    ... # Possibly some more Python code
    trepan.api.debug() # You can wrap inside conditional logic too
    pass  # Stop will be here.
    # Below is code you want to use the debugger to do things.
    ....  # more Python code
    # If you get to a place in the program where you aren't going
    # want to debug any more, but want to remove debugger trace overhead:
    trepan.api.stop()

Parameter "level" specifies how many stack frames go back. Usually it will be
the default 0. But sometimes though there may be calls in setup to the debugger
that you may want to skip.

Parameter "step_ignore" specifies how many line events to ignore after the
debug() call. 0 means don't even wait for the debug() call to finish.

In situations where you want an immediate stop in the "debug" call
rather than the statement following it ("pass" above), add parameter
step_ignore=0 to debug() like this::

    import trepan.api  # Needed only once
    # ... as before
    trepan.api.debug(step_ignore=0)
    # ... as before

Module variable _debugger_obj_ from module trepan.debugger is used as
the debugger instance variable; it can be subsequently used to change
settings or alter behavior. It should be of type Debugger (found in
module trepan). If not, it will get changed to that type::

   $ python
   >>> from trepan.debugger import debugger_obj
   >>> type(debugger_obj)
   <type 'NoneType'>
   >>> import trepan.api
   >>> trepan.api.debug()
   ...
   (Trepan) c
   >>> from trepan.debugger import debugger_obj
   >>> debugger_obj
   <trepan.debugger.Debugger instance at 0x7fbcacd514d0>
   >>>

If however you want your own separate debugger instance, you can
create it from the debugger _class Debugger()_ from module
trepan.debugger::

  $ python
  >>> from trepan.debugger import Debugger
  >>> dbgr = Debugger()  # Add options as desired
  >>> dbgr
  <trepan.debugger.Debugger instance at 0x2e25320>

`dbg_opts' is an optional "options" dictionary that gets fed
trepan.Debugger(); `start_opts' are the optional "options"
dictionary that gets fed to trepan.Debugger.core.start().
"""
    if not isinstance(Mdebugger.debugger_obj, Mdebugger.Trepan):
        Mdebugger.debugger_obj = Mdebugger.Trepan(dbg_opts)
        Mdebugger.debugger_obj.core.add_ignore(debug, stop)
        pass
    core = Mdebugger.debugger_obj.core
    frame = sys._getframe(0 + level)
    core.set_next(frame)
    if start_opts and 'startup-profile' in start_opts and start_opts[
            'startup-profile']:
        dbg_initfiles = start_opts['startup-profile']
        from trepan import options
        options.add_startup_file(dbg_initfiles)
        for init_cmdfile in dbg_initfiles:
            core.processor.queue_startfile(init_cmdfile)

    if not core.is_started():
        core.start(start_opts)
        pass
    if post_mortem:
        debugger_on_post_mortem()
        pass
    if 0 == step_ignore:
        frame = sys._getframe(1 + level)
        core.stop_reason = 'at a debug() call'
        old_trace_hook_suspend = core.trace_hook_suspend
        core.trace_hook_suspend = True
        core.processor.event_processor(frame, 'line', None)
        core.trace_hook_suspend = old_trace_hook_suspend
    else:
        core.step_ignore = step_ignore - 1
        pass
    return
示例#17
0
    for i in (15, -15, 300):
        print("lookup_signame(%d): %s" % (i, lookup_signame(i)))
        pass

    for i in ("term", "TERM", "NotThere"):
        print("lookup_signum(%s): %s" % (i, repr(lookup_signum(i))))
        pass

    for i in ("15", "-15", "term", "sigterm", "TERM", "300", "bogus"):
        print("canonic_signame(%s): %s" % (i, canonic_signame(i)))
        pass

    from trepan import debugger as Mdebugger

    dbgr = Mdebugger.Trepan()
    h = SignalManager(dbgr)
    h.info_signal(["TRAP"])
    # Set to known value
    h.action("SIGUSR1")
    h.action("usr1 print pass stop")
    h.info_signal(["USR1"])
    # noprint implies no stop
    h.action("SIGUSR1 noprint")
    h.info_signal(["USR1"])
    h.action("foo nostop")
    # stop keyword implies print
    h.action("SIGUSR1 stop")
    h.info_signal(["SIGUSR1"])
    h.action("SIGUSR1 noprint")
    h.info_signal(["SIGUSR1"])
示例#18
0
def main(dbg=None, sys_argv=list(sys.argv)):
    """Routine which gets run if we were invoked directly"""
    global __title__

    # Save the original just for use in the restart that works via exec.
    orig_sys_argv = list(sys_argv)
    opts, dbg_opts, sys_argv = Moptions.process_options(
        __title__, VERSION, sys_argv)

    if opts.server is not None:
        if opts.server == 'tcp':
            connection_opts = {'IO': 'TCP', 'PORT': opts.port}
        else:
            connection_opts = {'IO': 'FIFO'}
        intf = Mserver.ServerInterface(connection_opts=connection_opts)
        dbg_opts['interface'] = intf
        if 'FIFO' == intf.server_type:
            print('Starting FIFO server for process %s.' % os.getpid())
        elif 'TCP' == intf.server_type:
            print('Starting TCP server listening on port %s.' %
                  intf.inout.PORT)
            pass
    elif opts.client:
        Mclient.main(opts, sys_argv)
        return

    dbg_opts['orig_sys_argv'] = orig_sys_argv

    if dbg is None:
        dbg = Mdebugger.Trepan(dbg_opts)
        dbg.core.add_ignore(main)
        pass
    Moptions._postprocess_options(dbg, opts)

    # process_options has munged sys.argv to remove any options that
    # options that belong to this debugger. The original options to
    # invoke the debugger and script are in global sys_argv

    if len(sys_argv) == 0:
        # No program given to debug. Set to go into a command loop
        # anyway
        mainpyfile = None
    else:
        mainpyfile = sys_argv[0]  # Get script filename.
        if not osp.isfile(mainpyfile):
            mainpyfile = Mclifns.whence_file(mainpyfile)
            is_readable = Mfile.readable(mainpyfile)
            if is_readable is None:
                print("%s: Python script file '%s' does not exist" % (
                    __title__,
                    mainpyfile,
                ))
                sys.exit(1)
            elif not is_readable:
                print("%s: Can't read Python script file '%s'" % (
                    __title__,
                    mainpyfile,
                ))
                sys.exit(1)
                return

        if Mfile.is_compiled_py(mainpyfile):
            try:
                from xdis import load_module, PYTHON_VERSION, IS_PYPY
                (python_version, timestamp, magic_int, co, is_pypy,
                 source_size) = load_module(mainpyfile,
                                            code_objects=None,
                                            fast_load=True)
                assert is_pypy == IS_PYPY
                assert python_version == PYTHON_VERSION, \
                    "bytecode is for version %s but we are version %s" % (
                        python_version, PYTHON_VERSION)
                # We should we check version magic_int

                py_file = co.co_filename
                if osp.isabs(py_file):
                    try_file = py_file
                else:
                    mainpydir = osp.dirname(mainpyfile)
                    tag = sys.implementation.cache_tag
                    dirnames = [
                        osp.join(mainpydir, tag), mainpydir
                    ] + os.environ['PATH'].split(osp.pathsep) + ['.']
                    try_file = Mclifns.whence_file(py_file, dirnames)

                if osp.isfile(try_file):
                    mainpyfile = try_file
                    pass
                else:
                    # Move onto the except branch
                    raise IOError(
                        "Python file name embedded in code %s not found" %
                        try_file)
            except IOError:
                try:
                    from uncompyle6 import decompile_file
                except ImportError:
                    print(
                        "%s: Compiled python file '%s', but uncompyle6 not found"
                        % (__title__, mainpyfile),
                        file=sys.stderr)
                    sys.exit(1)
                    return

                short_name = osp.basename(mainpyfile).strip('.pyc')
                fd = tempfile.NamedTemporaryFile(suffix='.py',
                                                 prefix=short_name + "_",
                                                 delete=False)
                old_write = fd.file.write

                def write_wrapper(*args, **kwargs):
                    if isinstance(args[0], str):
                        new_args = list(args)
                        new_args[0] = args[0].encode('utf-8')
                        old_write(*new_args, **kwargs)
                    else:
                        old_write(*args, **kwargs)

                fd.file.write = write_wrapper

                # from io import StringIO
                # linemap_io = StringIO()
                try:
                    decompile_file(mainpyfile, fd.file, mapstream=fd)
                except:
                    print("%s: error decompiling '%s'" %
                          (__title__, mainpyfile),
                          file=sys.stderr)
                    sys.exit(1)
                    return

                # # Get the line associations between the original and
                # # decompiled program
                # mapline = linemap_io.getvalue()
                # fd.write(mapline + "\n\n")
                # linemap = eval(mapline[3:])
                mainpyfile = fd.name
                fd.close()

                # Since we are actually running the recreated source,
                # there is little no need to remap line numbers.
                # The mapping is given at the end of the file.
                # However we should consider adding this information
                # and original file name.

                print(
                    "%s: couldn't find Python source so we recreated it at '%s'"
                    % (__title__, mainpyfile),
                    file=sys.stderr)

                pass

        # If mainpyfile is an optimized Python script try to find and
        # use non-optimized alternative.
        mainpyfile_noopt = pyficache.pyc2py(mainpyfile)
        if mainpyfile != mainpyfile_noopt \
               and Mfile.readable(mainpyfile_noopt):
            print("%s: Compiled Python script given and we can't use that." %
                  __title__)
            print("%s: Substituting non-compiled name: %s" % (
                __title__,
                mainpyfile_noopt,
            ))
            mainpyfile = mainpyfile_noopt
            pass

        # Replace trepan's dir with script's dir in front of
        # module search path.
        sys.path[0] = dbg.main_dirname = osp.dirname(mainpyfile)

    # XXX If a signal has been received we continue in the loop, otherwise
    # the loop exits for some reason.
    dbg.sig_received = False

    # if not mainpyfile:
    #     print('For now, you need to specify a Python script name!')
    #     sys.exit(2)
    #     pass

    while True:

        # Run the debugged script over and over again until we get it
        # right.

        try:
            if dbg.program_sys_argv and mainpyfile:
                normal_termination = dbg.run_script(mainpyfile)
                if not normal_termination: break
            else:
                dbg.core.execution_status = 'No program'
                dbg.core.processor.process_commands()
                pass

            dbg.core.execution_status = 'Terminated'
            dbg.intf[-1].msg("The program finished - quit or restart")
            dbg.core.processor.process_commands()
        except Mexcept.DebuggerQuit:
            break
        except Mexcept.DebuggerRestart:
            dbg.core.execution_status = 'Restart requested'
            if dbg.program_sys_argv:
                sys.argv = list(dbg.program_sys_argv)
                part1 = ('Restarting %s with arguments:' %
                         dbg.core.filename(mainpyfile))
                args = ' '.join(dbg.program_sys_argv[1:])
                dbg.intf[-1].msg(
                    Mmisc.wrapped_lines(part1, args, dbg.settings['width']))
            else:
                break
        except SystemExit:
            # In most cases SystemExit does not warrant a post-mortem session.
            break
        pass

    # Restore old sys.argv
    sys.argv = orig_sys_argv
    return
示例#19
0
def post_mortem(exc=None, frameno=1, dbg=None):
    """Enter debugger read loop after your program has crashed.

    exc is a triple like you get back from sys.exc_info.  If no exc
    parameter, is supplied, the values from sys.last_type,
    sys.last_value, sys.last_traceback are used. And if these don't
    exist either we'll assume that sys.exc_info() contains what we
    want and frameno is the index location of where we want to start.

    'frameno' specifies how many frames to ignore in the traceback.
    The default is 1, that is, we don't need to show the immediate
    call into post_mortem. If you have wrapper functions that call
    this one, you may want to increase frameno.
    """

    if dbg is None:
        # Check for a global debugger object
        if Mdebugger.debugger_obj is None:
            Mdebugger.debugger_obj = Mdebugger.Trepan()
            pass
        dbg = Mdebugger.debugger_obj
        pass
    re_bogus_file = re.compile("^<.+>$")

    if exc[0] is None:
        # frameno+1 because we are about to add one more level of call
        # in get_last_or_frame_exception
        exc = get_last_or_frame_exception()
        if exc[0] is None:
            print("Can't find traceback for post_mortem "
                  "in sys.last_traceback or sys.exec_info()")
            return
        pass
    exc_type, exc_value, exc_tb = exc
    dbg.core.execution_status = ('Terminated with unhandled exception %s' %
                                 exc_type)

    # tb has least-recent traceback entry first. We want the most-recent
    # entry. Also we'll pick out a mainpyfile name if it hasn't previously
    # been set.
    if exc_tb is not None:
        while exc_tb.tb_next is not None:
            filename = exc_tb.tb_frame.f_code.co_filename
            if (dbg.mainpyfile and 0 == len(dbg.mainpyfile)
                    and not re_bogus_file.match(filename)):
                dbg.mainpyfile = filename
                pass
            exc_tb = exc_tb.tb_next
            pass
        dbg.core.processor.curframe = exc_tb.tb_frame
        pass

    if 0 == len(dbg.program_sys_argv):
        # Fake program (run command) args since we weren't called with any
        dbg.program_sys_argv = list(sys.argv[1:])
        dbg.program_sys_argv[:0] = [dbg.mainpyfile]

    # if 0 == len(dbg._sys_argv):
    #     # Fake script invocation (restart) args since we don't have any
    #     dbg._sys_argv = list(dbg.program_sys_argv)
    #     dbg._sys_argv[:0] = [__title__]

    try:
        # # FIXME: This can be called from except hook in which case we
        # # need this. Dunno why though.
        # try:
        #     _pydb_trace.set_trace(t.tb_frame)
        # except:
        #     pass

        # Possibly a bug in Python 2.5. Why f.f_lineno is
        # not always equal to t.tb_lineno, I don't know.
        f = exc_tb.tb_frame
        if f and f.f_lineno != exc_tb.tb_lineno: f = f.f_back
        dbg.core.processor.event_processor(f, 'exception', exc, 'Trepan3k:pm')
    except DebuggerRestart:
        while True:
            sys.argv = list(dbg._program_sys_argv)
            dbg.msg("Restarting %s with arguments:\n\t%s" % (dbg.filename(
                dbg.mainpyfile), " ".join(dbg._program_sys_argv[1:])))
            try:
                dbg.run_script(dbg.mainpyfile)
            except DebuggerRestart:
                pass
            pass
    except DebuggerQuit:
        pass
    return
示例#20
0
    def test_parse_break_cmd(self):
        import inspect
        d = debugger.Trepan()
        cp = d.core.processor
        cp.curframe = inspect.currentframe()
        self.cmd = Mbreak.BreakCommand(cp)
        self.cmd.msg = self.msg
        self.cmd.errmsg = self.errmsg
        proc = self.cmd.proc

        fn, fi, li, cond = self.parse_break_cmd(proc, 'break')
        self.assertEqual((None, True, True),
                         (fn, fi.endswith('test-break.py'), li > 1))

        fn, fi, li, cond = self.parse_break_cmd(proc, 'break 11')
        self.assertEqual((None, True, 11),
                         (fn, fi.endswith('test-break.py'), li))

        if 'APPVEYOR' not in os.environ:
            if platform.system() == 'Windows':
                brk_cmd = 'b """%s""":8' % __file__
            else:
                brk_cmd = 'b %s:8' % __file__

                fn, fi, li, cond = self.parse_break_cmd(proc, brk_cmd)
                self.assertEqual((None, True, 8),
                                 (fn, isinstance(fi, str), li))

        def foo():
            return 'bar'

        fn, fi, li, cond = self.parse_break_cmd(proc, 'break foo()')
        self.assertEqual((foo, True, True),
                         (fn, fi.endswith('test-break.py'), li > 1))

        fn, fi, li, cond = self.parse_break_cmd(proc, 'break food()')
        self.assertEqual((None, None, None, None), (fn, fi, li, cond))

        fn, fi, li, cond = self.parse_break_cmd(proc, 'b os.path:5')
        self.assertEqual((os.path, True, 5), (fn, isinstance(fi, str), li))

        fn, fi, li, cond = self.parse_break_cmd(proc, 'b os.path.join()')
        self.assertEqual((os.path.join, True, True),
                         (fn, isinstance(fi, str), li > 1))

        fn, fi, li, cond = self.parse_break_cmd(proc, 'break if True')
        self.assertEqual((None, True, True),
                         (fn, fi.endswith('test-break.py'), li > 1))

        fn, fi, li, cond = self.parse_break_cmd(proc, 'b foo() if True')
        self.assertEqual((foo, True, True),
                         (fn, fi.endswith('test-break.py'), li > 1))

        fn, fi, li, cond = self.parse_break_cmd(proc, 'br os.path:10 if True')
        self.assertEqual((True, 10), (isinstance(fi, str), li))

        # FIXME:
        # Try:
        #  a breakpoint with a symlink in the filename.
        #  breakpoint with a single quotes and embedded black
        #  breakpoint with a double quotes and embedded \,
        #  Triple quote things
        #
        # Also, add a unit test for canonic.

        return
示例#21
0
        def test_completion(self):

            self.dbgr = Mdebugger.Trepan()

            for line, expect_completion in [
                    ['set basename ', ['off', 'on']],
                    ['where', ['where ']],  # Single alias completion
                    ['sho', ['show']],  # Simple single completion
                    ['un', ['unalias', 'undisplay']],  # Simple multiple completion
                    ['python ', []],        # Don't add anything - no more
                    ['set basename o', ['off', 'on']],
                    ['set basename of', ['off']],

                    # Multiple completion on two words
                    ['set auto', ['autoeval', 'autolist', 'autopc', 'autopython']],

                    # Completion when word is complete, without space.
                    ['show', ['show ']],

                    # Completion when word is complete with space.
                    ['info ',
                     ['args', 'break', 'builtins', 'code',
                      'display', 'files', 'frame', 'globals', 'line', "lines",
                      'locals', 'macro', "offsets", 'pc', 'program', 'return', 'signals', 'source',
                      'threads']],

                    ['help sta', ['stack', 'status']],
                    [' unalias c',  ['c', 'chdir', 'cond']],


                    # Any set style completion
                    ['set style def', ['default']],

                    # ['set auto eval ', '', ['off', 'on']],
                                              # Many 3-word completions
                    # ['set auto ', ['eval', 'irb', 'list']],
                                              # Many two-word completions
                    # ['set auto e', ['eval']],
                    # ['disas', ['disassemble']], # Another single completion
                    # ['help syn', ['syntax']],
                    # ## FIXME:
                    # ## ['help syntax co', ['command']],
                    # ['help br', ['break', 'breakpoints']],
                ]:
                got = self.run_complete(line)
                self.assertEqual(expect_completion, got,
                                 "Completion of '%s', expecting %s, got %s" %
                                 (line, expect_completion, got))
                pass

            got = self.run_complete('')
            self.assertTrue(len(got) > 30,
                            'Initial completion should return more '
                            'than 30 commands')
            got = self.run_complete('info files ')
            self.assertTrue(len(got) > 0,
                            'info files completion should return a file')
            got = self.run_complete('unalias ')
            self.assertTrue(len(got) > 0,
                            'unalias should return lots of aliases')
            return