Spaces:
Running
Running
File size: 5,751 Bytes
ba2f5d6 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
#!/usr/bin/env python
"""
The Cython debugger
The current directory should contain a directory named 'cython_debug', or a
path to the cython project directory should be given (the parent directory of
cython_debug).
Additional gdb args can be provided only if a path to the project directory is
given.
"""
import os
import sys
import glob
import tempfile
import textwrap
import subprocess
import optparse
import logging
logger = logging.getLogger(__name__)
def make_command_file(path_to_debug_info, prefix_code='', no_import=False):
if not no_import:
pattern = os.path.join(path_to_debug_info,
'cython_debug',
'cython_debug_info_*')
debug_files = glob.glob(pattern)
if not debug_files:
sys.exit('%s.\nNo debug files were found in %s. Aborting.' % (
usage, os.path.abspath(path_to_debug_info)))
fd, tempfilename = tempfile.mkstemp()
f = os.fdopen(fd, 'w')
try:
f.write(prefix_code)
f.write(textwrap.dedent('''\
# This is a gdb command file
# See https://sourceware.org/gdb/onlinedocs/gdb/Command-Files.html
set breakpoint pending on
set print pretty on
python
# Activate virtualenv, if we were launched from one
import os
virtualenv = os.getenv('VIRTUAL_ENV')
if virtualenv:
path_to_activate_this_py = os.path.join(virtualenv, 'bin', 'activate_this.py')
print("gdb command file: Activating virtualenv: %s; path_to_activate_this_py: %s" % (
virtualenv, path_to_activate_this_py))
with open(path_to_activate_this_py) as f:
exec(f.read(), dict(__file__=path_to_activate_this_py))
from Cython.Debugger import libcython, libpython
end
'''))
if no_import:
# don't do this, this overrides file command in .gdbinit
# f.write("file %s\n" % sys.executable)
pass
else:
path = os.path.join(path_to_debug_info, "cython_debug", "interpreter")
interpreter_file = open(path)
try:
interpreter = interpreter_file.read()
finally:
interpreter_file.close()
f.write("file %s\n" % interpreter)
f.write('\n'.join('cy import %s\n' % fn for fn in debug_files))
f.write(textwrap.dedent('''\
python
import sys
try:
gdb.lookup_type('PyModuleObject')
except RuntimeError:
sys.stderr.write(
'Python was not compiled with debug symbols (or it was '
'stripped). Some functionality may not work (properly).\\n')
end
source .cygdbinit
'''))
finally:
f.close()
return tempfilename
usage = "Usage: cygdb [options] [PATH [-- GDB_ARGUMENTS]]"
def main(path_to_debug_info=None, gdb_argv=None, no_import=False):
"""
Start the Cython debugger. This tells gdb to import the Cython and Python
extensions (libcython.py and libpython.py) and it enables gdb's pending
breakpoints.
path_to_debug_info is the path to the Cython build directory
gdb_argv is the list of options to gdb
no_import tells cygdb whether it should import debug information
"""
parser = optparse.OptionParser(usage=usage)
parser.add_option("--gdb-executable",
dest="gdb", default='gdb',
help="gdb executable to use [default: gdb]")
parser.add_option("--verbose", "-v",
dest="verbosity", action="count", default=0,
help="Verbose mode. Multiple -v options increase the verbosity")
(options, args) = parser.parse_args()
if path_to_debug_info is None:
if len(args) > 1:
path_to_debug_info = args[0]
else:
path_to_debug_info = os.curdir
if gdb_argv is None:
gdb_argv = args[1:]
if path_to_debug_info == '--':
no_import = True
logging_level = logging.WARN
if options.verbosity == 1:
logging_level = logging.INFO
if options.verbosity >= 2:
logging_level = logging.DEBUG
logging.basicConfig(level=logging_level)
logger.info("verbosity = %r", options.verbosity)
logger.debug("options = %r; args = %r", options, args)
logger.debug("Done parsing command-line options. path_to_debug_info = %r, gdb_argv = %r",
path_to_debug_info, gdb_argv)
tempfilename = make_command_file(path_to_debug_info, no_import=no_import)
logger.info("Launching %s with command file: %s and gdb_argv: %s",
options.gdb, tempfilename, gdb_argv)
with open(tempfilename) as tempfile:
logger.debug('Command file (%s) contains: """\n%s"""', tempfilename, tempfile.read())
logger.info("Spawning %s...", options.gdb)
p = subprocess.Popen([options.gdb, '-command', tempfilename] + gdb_argv)
logger.info("Spawned %s (pid %d)", options.gdb, p.pid)
while True:
try:
logger.debug("Waiting for gdb (pid %d) to exit...", p.pid)
ret = p.wait()
logger.debug("Wait for gdb (pid %d) to exit is done. Returned: %r", p.pid, ret)
except KeyboardInterrupt:
pass
else:
break
logger.debug("Closing temp command file with fd: %s", tempfile.fileno())
logger.debug("Removing temp command file: %s", tempfilename)
os.remove(tempfilename)
logger.debug("Removed temp command file: %s", tempfilename)
|