cython

Форк
0
179 строк · 6.8 Кб
1
#!/usr/bin/env python
2

3
"""
4
The Cython debugger
5

6
The current directory should contain a directory named 'cython_debug', or a
7
path to the cython project directory should be given (the parent directory of
8
cython_debug).
9

10
Additional gdb args can be provided only if a path to the project directory is
11
given.
12
"""
13

14
import os
15
import sys
16
import glob
17
import tempfile
18
import textwrap
19
import subprocess
20
import optparse
21
import logging
22

23
logger = logging.getLogger(__name__)
24

25

26
def make_command_file(path_to_debug_info, prefix_code='',
27
                      no_import=False, skip_interpreter=False):
28
    if not no_import:
29
        pattern = os.path.join(path_to_debug_info,
30
                               'cython_debug',
31
                               'cython_debug_info_*')
32
        debug_files = glob.glob(pattern)
33

34
        if not debug_files:
35
            sys.exit('%s.\nNo debug files were found in %s. Aborting.' % (
36
                                   usage, os.path.abspath(path_to_debug_info)))
37

38
    fd, tempfilename = tempfile.mkstemp()
39
    f = os.fdopen(fd, 'w')
40
    try:
41
        f.write(prefix_code)
42
        f.write(textwrap.dedent('''\
43
            # This is a gdb command file
44
            # See https://sourceware.org/gdb/onlinedocs/gdb/Command-Files.html
45

46
            set breakpoint pending on
47
            set print pretty on
48

49
            python
50
            try:
51
                # Activate virtualenv, if we were launched from one
52
                import os
53
                virtualenv = os.getenv('VIRTUAL_ENV')
54
                if virtualenv:
55
                    path_to_activate_this_py = os.path.join(virtualenv, 'bin', 'activate_this.py')
56
                    print("gdb command file: Activating virtualenv: %s; path_to_activate_this_py: %s" % (
57
                        virtualenv, path_to_activate_this_py))
58
                    with open(path_to_activate_this_py) as f:
59
                        exec(f.read(), dict(__file__=path_to_activate_this_py))
60
                from Cython.Debugger import libcython, libpython
61
            except Exception as ex:
62
                from traceback import print_exc
63
                print("There was an error in Python code originating from the file ''' + str(__file__) + '''")
64
                print("It used the Python interpreter " + str(sys.executable))
65
                print_exc()
66
                exit(1)
67
            end
68
            '''))
69

70
        if no_import:
71
            # don't do this, this overrides file command in .gdbinit
72
            # f.write("file %s\n" % sys.executable)
73
            pass
74
        else:
75
            if not skip_interpreter:
76
                # Point Cygdb to the interpreter that was used to generate
77
                # the debugging information.
78
                path = os.path.join(path_to_debug_info, "cython_debug", "interpreter")
79
                interpreter_file = open(path)
80
                try:
81
                    interpreter = interpreter_file.read()
82
                finally:
83
                    interpreter_file.close()
84
                f.write("file %s\n" % interpreter)
85

86
            f.write('\n'.join('cy import %s\n' % fn for fn in debug_files))
87

88
            if not skip_interpreter:
89
                f.write(textwrap.dedent('''\
90
                    python
91
                    import sys
92
                    # Check if the Python executable provides a symbol table.
93
                    if not hasattr(gdb.selected_inferior().progspace, "symbol_file"):
94
                        sys.stderr.write(
95
                            "''' + interpreter + ''' was not compiled with debug symbols (or it was "
96
                            "stripped). Some functionality may not work (properly).\\n")
97
                    end
98
                '''))
99

100
            f.write("source .cygdbinit\n")
101
    finally:
102
        f.close()
103

104
    return tempfilename
105

106
usage = "Usage: cygdb [options] [PATH [-- GDB_ARGUMENTS]]"
107

108
def main(path_to_debug_info=None, gdb_argv=None, no_import=False):
109
    """
110
    Start the Cython debugger. This tells gdb to import the Cython and Python
111
    extensions (libcython.py and libpython.py) and it enables gdb's pending
112
    breakpoints.
113

114
    path_to_debug_info is the path to the Cython build directory
115
    gdb_argv is the list of options to gdb
116
    no_import tells cygdb whether it should import debug information
117
    """
118
    parser = optparse.OptionParser(usage=usage)
119
    parser.add_option("--gdb-executable",
120
        dest="gdb", default='gdb',
121
        help="gdb executable to use [default: gdb]")
122
    parser.add_option("--verbose", "-v",
123
        dest="verbosity", action="count", default=0,
124
        help="Verbose mode. Multiple -v options increase the verbosity")
125
    parser.add_option("--skip-interpreter",
126
                      dest="skip_interpreter", default=False, action="store_true",
127
                      help="Do not automatically point GDB to the same interpreter "
128
                           "used to generate debugging information")
129

130
    (options, args) = parser.parse_args()
131
    if path_to_debug_info is None:
132
        if len(args) > 1:
133
            path_to_debug_info = args[0]
134
        else:
135
            path_to_debug_info = os.curdir
136

137
    if gdb_argv is None:
138
        gdb_argv = args[1:]
139

140
    if path_to_debug_info == '--':
141
        no_import = True
142

143
    logging_level = logging.WARN
144
    if options.verbosity == 1:
145
        logging_level = logging.INFO
146
    if options.verbosity >= 2:
147
        logging_level = logging.DEBUG
148
    logging.basicConfig(level=logging_level)
149

150
    skip_interpreter = options.skip_interpreter
151

152
    logger.info("verbosity = %r", options.verbosity)
153
    logger.debug("options = %r; args = %r", options, args)
154
    logger.debug("Done parsing command-line options. path_to_debug_info = %r, gdb_argv = %r",
155
        path_to_debug_info, gdb_argv)
156

157
    tempfilename = make_command_file(path_to_debug_info,
158
                                     no_import=no_import,
159
                                     skip_interpreter=skip_interpreter)
160
    logger.info("Launching %s with command file: %s and gdb_argv: %s",
161
        options.gdb, tempfilename, gdb_argv)
162
    with open(tempfilename) as tempfile:
163
        logger.debug('Command file (%s) contains: """\n%s"""', tempfilename, tempfile.read())
164
        logger.info("Spawning %s...", options.gdb)
165
        p = subprocess.Popen([options.gdb, '-command', tempfilename] + gdb_argv)
166
        logger.info("Spawned %s (pid %d)", options.gdb, p.pid)
167
        while True:
168
            try:
169
                logger.debug("Waiting for gdb (pid %d) to exit...", p.pid)
170
                ret = p.wait()
171
                logger.debug("Wait for gdb (pid %d) to exit is done. Returned: %r", p.pid, ret)
172
            except KeyboardInterrupt:
173
                pass
174
            else:
175
                break
176
        logger.debug("Closing temp command file with fd: %s", tempfile.fileno())
177
    logger.debug("Removing temp command file: %s", tempfilename)
178
    os.remove(tempfilename)
179
    logger.debug("Removed temp command file: %s", tempfilename)
180

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.