Skip to content

Instantly share code, notes, and snippets.

@syshack
Created August 18, 2012 03:07
Show Gist options
  • Select an option

  • Save syshack/3384085 to your computer and use it in GitHub Desktop.

Select an option

Save syshack/3384085 to your computer and use it in GitHub Desktop.
wingide远程调试
#!/usr/bin/env python
#########################################################################
""" wingdb.py -- Top-level command used internally by Wing IDE to
start a debug process.
Copyright (c) 2000-2012, Archaeopteryx Software, Inc. All rights reserved.
Written by Stephan R.A. Deibel and John P. Ehresman
"""
#########################################################################
# Only import sys at the top-level because sys.path needs to be modified
# in some contexts
import sys
# Start without translation -- this gets changed once netserver is found
_ = lambda x: x
# For trouble-shooting, set environment variable or uncomment line below
def _GetDefaultPrintAllTracebacks():
import os
return os.environ.get('WINGDB_PRINT_ALL_TRACEBACKS', 0)
kPrintAllTracebacks = _GetDefaultPrintAllTracebacks()
if kPrintAllTracebacks:
import os
os.environ['WINGDB_PRINT_ALL_TRACEBACKS'] = '1'
# Wing version & build numbers
kVersion = "4.1.7"
kBuild = "1"
# Utils for dealing w/ Python 2.x vs. 3.x
if sys.hexversion >= 0x03000000:
def has_key(o, key):
return key in o
else:
def has_key(o, key):
return o.has_key(key)
# Set __file__ if not already set; this is an internal value so is kosher
try:
__file__
except NameError:
__file__ = sys.argv[0]
def _GetWingDirs():
""" Gets winghome & usersettings dir if __name__ is __main__. Returns
(None, None) if unable to retrieve the dirs for some reason. """
if __name__ != '__main__':
return None, None
import os
if has_key(os.environ, 'WINGDB_WINGHOME'):
try:
winghome = os.environ['WINGDB_WINGHOME']
del os.environ['WINGDB_WINGHOME']
user_settings = os.environ.get('WINGDB_USERSETTINGS', None)
if user_settings is not None:
del os.environ['WINGDB_USERSETTINGS']
return winghome, user_settings
except:
if kPrintAllTracebacks:
import traceback
traceback.print_exc(file=sys.__stderr__)
try:
winghome = os.path.dirname(os.path.dirname(os.path.abspath(sys.argv[0])))
return winghome, None
except:
if kPrintAllTracebacks:
sys.__stderr__.write('WINGDB ARGS:' + str(sys.argv))
sys.__stderr__.write('\n')
import traceback
traceback.print_exc(file=sys.__stderr__)
return None, None
#########################################################################
# Temporary, in-memory logger; used until we know where to send the messages
#########################################################################
class CTempLog:
""" Temporarily log messages to a list. """
def __init__(self):
self.fEntries = []
def out(self, *args):
""" Save msg in fEntries """
args = map(str, args)
first = 1
for s in args:
if first:
first = 0
else:
self.write(' ')
self.write(s)
def write(self, msg):
""" Save msg in fEntries """
if msg[-1:] == '\n':
msg = msg[:-1]
self.fEntries.append(msg)
def write_entries(self, log):
""" Write fEntries to out object via it's out method. """
for entry in self.fEntries:
log.out(entry)
def clear(self):
""" Clear all entries. """
self.fEntries = []
#########################################################################
# Argument parsing
#########################################################################
def _ParseSingleArg(err, arg_index, func = None, choices = None):
""" Parse a single arg from argv; print usage if arg is incorrect. Applies
func to the value if func is not None and look up value in choices map
if choices is not None. """
try:
value = sys.argv[arg_index]
# Transform value if function is provided
if func != None:
value = func(value)
# Look up value in choices if choices is not None
if choices != None:
value = choices[value]
return value
except:
if kPrintAllTracebacks:
import traceback
traceback.print_exc(file=sys.__stderr__)
sys.exit(2)
def _LogfileTransform(value):
""" Transformation function for logfile arg. """
value = eval(value)
if value == '<none>':
return None
else:
return value
def _HostportTransform(hostport):
""" Transformation function for host:port arg. """
colonpos = hostport.index(':')
host = hostport[0:colonpos]
if host == '':
host = '127.0.0.1'
port = int(hostport[colonpos+1:])
return host, port
def _ParseArgv(err):
""" Parses sys.argv, which contains parameters encoded by position, and
returns dictionary of values.
The parameters allowed are defined as follows by position in sys.argv:
0) This script's name
1) host:port indicates where Wing IDE is listening for reverse connection
from this debug process.
2) attachport, where the debug process will listen for attach requests
when not connected to a debug process.
3) One of --first-stop to stop on the first line of the debug program,
or --no-first-stop to run to first breakpoint or completion.
4) logfile for debug server internals. One of <none> for no logging,
<stderr>, <stdout>, or a file name in which to log extra error output.
The parameter should be encoded as a Python expression that can
be parsed by eval(). This avoids problems with special chars
in file names. For example, "r'mylog'" is a valid value.
5) optional --very-verbose-log to turn on core logging support if it
is present
6) One of --wait-on-exit or --nowait-on-exit. When set to wait-on-exit,
the debugger will wait for user to hit a key before exiting entirely.
7) Optional --stdout-encoding=<encoding>. Sets sys.stdout.encoding &
sys.stderr.encoding to given <encoding> string iff encoding is valid
8) Optional --stdin-encoding=<encoding>. Sets sys.stdin.encoding
to given <encoding> string iff encoding is valid
7) filename, which is a Python expression that can be passed to eval()
that evaluates to the name of the file to debug.
The dictionary returned from this function contains:
host: host to connect back to
port: port to connect back to
attachport: port # to listen far attach requests on
firststop: whether to stop on first line
logfile: <none>, <stderr>, <stdout>, or a file name
veryverboselog: whether very verbose is on
waitonexit: whether to wait for a keystroke when the program exits
stdoutencoding: output encoding if specified or None
stdinencoding: input encoding if specified or None
filename: name of the python file to debug
"""
import os
args = {}
# Parse args and store value in dictionary to return
args['host'], args['port'] = _ParseSingleArg(err, 1, _HostportTransform)
args['attachport'] = _ParseSingleArg(err, 2, int)
args['firststop'] = _ParseSingleArg(err, 3, choices = {"--no-first-stop": 0,
"--first-stop": 1})
args['logfile'] = _ParseSingleArg(err, 4, _LogfileTransform)
args['veryverboselog'] = (sys.argv[5] == '--very-verbose-log')
next = 5
if args['veryverboselog']:
next = next + 1
args['waitonexit'] = _ParseSingleArg(err, next, choices = {"--nowait-on-exit": 0,
"--wait-on-exit": 1})
next = next + 1
if sys.argv[next].find('--stdout-encoding=') == 0:
args['stdoutencoding'] = sys.argv[next][len('--stdout-encoding='):]
next = next + 1
else:
args['stdoutencoding'] = None
if sys.argv[next].find('--stdin-encoding=') == 0:
args['stdinencoding'] = sys.argv[next][len('--stdin-encoding='):]
next = next + 1
else:
args['stdinencoding'] = None
args['filename'] = filename = _ParseSingleArg(err, next, eval)
first_addtl_arg = next + 1
# Check if debug file exists and is a file
if not os.path.exists(filename):
err.write(_('wingdb.py: Error: Debug file does not exist:'))
err.write(filename)
sys.exit(1)
if not os.path.isfile(filename):
err.write(_('wingdb.py: Error: Debug file is not a file:'))
err.write(filename)
sys.exit(1)
# Prune args down to just args for the debugged program
del sys.argv[:first_addtl_arg]
return args
#########################################################################
# Debug server access
#########################################################################
def GetVersionTriple():
""" Return 3 element tuple (major, minor, micro) for the version of
the python interpreter we're running in. """
if sys.hexversion >= 0x02030000 and sys.hexversion < 0x02040000:
ff000000_mask = eval('int("4278190080")')
else:
ff000000_mask = eval('0xff000000')
return ((sys.hexversion & ff000000_mask) >> 24,
(sys.hexversion & 0x00ff0000) >> 16,
(sys.hexversion & 0x0000ff00) >> 8)
def GetPossibleServerLocations(winghome, user_settings=None):
""" Return sequence of locations to look for netserver in. Each location is
either a directory or a zip file. Look in patch dirs first, then in primary
bin dir, and finally in source dir. """
import os
server_pkg = 'tserver'
major, minor, release = GetVersionTriple()
interp_id = '%d.%d' % (major, minor)
# Get patch dirs w/ bin/major.minor
try:
exec_dict = {}
f = open(os.path.join(winghome, 'bin', '_patchsupport.py'))
try:
exec(f.read(), exec_dict)
finally:
f.close()
find_matching = exec_dict['FindMatching']
bin_list = find_matching(interp_id, winghome, user_settings)
except Exception:
if kPrintAllTracebacks:
import traceback
traceback.print_exc(file = sys.__stderr__)
bin_list = []
# Find dirs with debug server dir
dir_list = []
for dirname in bin_list:
server_dir = os.path.join(dirname, 'src', 'debug', server_pkg)
if os.path.isdir(server_dir):
dir_list.append(server_dir)
# Finally append default bin & src dirs
zip_name = os.path.join(winghome, 'bin', interp_id, 'src.zip')
if os.path.isfile(zip_name):
dir_list.append(os.path.join(zip_name, 'debug', server_pkg))
else:
dir_list.append(os.path.join(winghome, 'bin', interp_id, 'src', 'debug', server_pkg))
dir_list.append(os.path.join(winghome, 'src', 'debug', server_pkg))
return dir_list
def FindNetServerModule(winghome, user_settings=None):
""" Finds wing's netserver module given winghome path name. Does not write
to log so it can be called from wingdbstub. """
# Work around win32 path joining problems
if sys.platform == 'win32' and winghome[-1] == '\\':
winghome = winghome[:-1]
if sys.hexversion < 0x03000000:
import copy_reg # cPickle is screwed up if we don't hold onto this
try:
import encodings # encodings needs to be shared if it's available
except ImportError:
encodings = None
prev_mods = list(sys.modules.keys())
orig_path = list(sys.path)
try:
for path in GetPossibleServerLocations(winghome, user_settings):
sys.path = [path] + orig_path
try:
import netserver
global _
_ = netserver.abstract._
except ImportError:
if has_key(sys.modules, 'netserver'):
del sys.modules['netserver']
if kPrintAllTracebacks:
import traceback
sys.__stderr__.write('Trying to import netserver from %s\n' % path)
traceback.print_exc(file = sys.__stderr__)
else:
netserver.abstract._SetWingHome(winghome)
return netserver
# If reach here, all imports have failed
raise ImportError('Could not import netserver')
# Restore sys.path and unload modules we added to sys.modules
finally:
sys.path = orig_path
for key in list(sys.modules.keys()):
if not key in prev_mods:
del sys.modules[key]
def CreateServer(host, port, attachport, firststop, err, netserver,
pwfile_path):
""" Creates server. Writes traceback to err and returns None if creation
fails. """
# Create the server
try:
err.out(_("Network peer is "), host, "port", port)
err.out(_("Attach port = "), attachport)
err.out(_("Initial stop = "), firststop)
# Only listen locally if attachport is an int or doesn't contain ':'
if type(attachport) == type(1) or attachport.find(':') == -1:
attachport = '127.0.0.1:' + str(attachport)
internal_modules = []
mod = sys.modules.get(__name__)
if mod is not None and mod.__dict__ is globals():
internal_modules.append(mod)
return netserver.CNetworkServer(host, port, attachport, err, firststop,
pwfile_path, internal_modules=tuple(internal_modules))
# Cook exceptions for better display
except:
err.out(_("wingdb.py: Could not create debug server"))
raise
def DebugFile(server, filename, err, fs_encoding, sys_path=None):
""" Debug the given file. Writes any exception to err. """
import os
# Run the session
try:
filename = os.path.abspath(filename)
try:
pfilename = unicode(filename, fs_encoding)
except:
pfilename = filename
err.out(_("wingdb.py: Running %s") % pfilename)
os.environ['WINGDB_ACTIVE'] = "1"
if sys_path is not None:
sys.path = sys_path
server.Run(filename, sys.argv)
# Cook exceptions for better display
except:
err.out(_("wingdb.py: Server exiting abnormally on exception"))
raise
def CreateErrStream(netserver, logfile, very_verbose=0):
""" Creates error stream for debugger. """
file_list = []
if logfile != None:
file_list.append(logfile)
err = netserver.abstract.CErrStream(file_list, very_verbose=very_verbose)
return err
def ModifySysPath():
""" Insert std lib directory at the start of sys.path. This is usually
sys.prefix/[Ll]ib but it may not be. Need w/ Python 2.3
and 2.4 on win32 which put current dir in the path before the
std lib -- the bug was fixed in 2.5 """
if sys.platform == 'win32':
libdir = '%s\\Lib' % sys.prefix
else:
libdir = '%s/lib' % sys.prefix
sys.path.insert(0, libdir)
import os
# Adjust sys.path[0] if os is not in sys.prefix\Lib
if os.path.dirname(os.__file__) != libdir:
sys.path[0] = os.path.dirname(os.__file__)
if sys.platform != 'win32':
sys.path.insert(1, '%s/lib-dynload' % os.__file__)
def SetEncodingPython2(encoding, file_list, netserver):
""" Set encoding of all file objects in file_list (Python 2.x only)"""
if sys.hexversion >= 0x03000000:
raise NotImplementedError
if encoding is None or netserver is None:
return
try:
import codecs
codec_info = codecs.lookup(encoding)
except:
return
try:
set_file_encoding = netserver.dbgserver.dbgtracer.PyFile_SetEncoding
except AttributeError:
return
for single_file in file_list:
set_file_encoding(single_file, encoding)
def main():
""" Parse args and then run program. """
# Make sure we always give opportunity to see output when wait-on-exit is true!
waitonexit = 0
server = None
err = None
tmp_log = CTempLog()
try:
# Pick up exceptions
args = {}
try:
# Delete sys.path[0] because it refers to this file's directory then save sys.path
# for future use
del sys.path[0]
orig_sys_path = sys.path[:]
# Modify sys.path on win32 python 2.0, 2.1, 2.3 & 2.4 versions to put stdlib before cwd
interp_version = GetVersionTriple()
if (sys.platform == 'win32' and interp_version[0] == 2
and interp_version[1] in [0, 1, 3, 4]):
ModifySysPath()
# Find directories
winghome, user_settings = _GetWingDirs()
# Parse args
args = _ParseArgv(tmp_log)
waitonexit = args.get('waitonexit', waitonexit)
# Find netserver
try:
netserver = FindNetServerModule(winghome, user_settings)
except:
import traceback
if kPrintAllTracebacks:
traceback.print_exc(file=sys.__stderr__)
traceback.print_exc(file=tmp_log)
tmp_log.out(_("wingdb.py: Error: Failed to start the debug server"))
tmp_log.out(_("wingdb.py: Error: You may be running an unsupported version of Python"))
tmp_log.out(_("wingdb.py: Python version = %s") % sys.version)
tmp_log.out("wingdb.py: WINGHOME=%s" % repr(winghome))
sys.exit(-1)
# Sanity check: Debugging in optimized mode makes no sense
if __debug__ == 0:
tmp_log.out(_("wingdb.py: Error: Cannot run a debug process with optimized python"))
tmp_log.out(_("wingdb.py: Error: You must omit the -O or -OO command line option, or"))
tmp_log.out(_("wingdb.py: Error: undefine environment variable PYTHONOPTIMIZE"))
sys.exit(-1)
out_encoding = args.get('stdoutencoding')
in_encoding = args.get('stdinencoding')
tmp_log.out("Setting stdoutencoding=%s" % str(out_encoding))
tmp_log.out("Setting stdinencoding=%s" % str(in_encoding))
if sys.hexversion < 0x02060000:
SetEncodingPython2(out_encoding, [sys.stdout, sys.stderr], netserver)
SetEncodingPython2(in_encoding, [sys.stdin], netserver)
# Create error log and write tmp entries to it
err = CreateErrStream(netserver, args['logfile'], args['veryverboselog'])
tmp_log.write_entries(err)
tmp_log.clear()
# Create the server and run
err.out("sys.path=%s" % repr(sys.path))
err.out("sys.argv=%s" % repr(sys.argv))
pwfile_path = [netserver.abstract.kPWFilePathUserProfileDir]
server = CreateServer(args['host'], args['port'], args['attachport'],
args['firststop'], err, netserver, pwfile_path)
DebugFile(server, args['filename'], err, netserver.abstract.kFileSystemEncoding,
orig_sys_path)
# Handle any exception that caused debug to fail to start up
except:
if kPrintAllTracebacks:
import traceback
traceback.print_exc(file=sys.__stderr__)
# Find log file, if any was specified
logfile = args.get('logfile')
opened_file = 0
if logfile is None or logfile == '<none>' or logfile == '<stderr>':
file = sys.stderr
elif logfile == '<stdout>':
file = sys.stdout
else:
try:
file = open(logfile, "a")
opened_file = 1
except (IOError, OSError):
file = sys.stderr
# Write log/exception info if we have a log file
if file != None:
# Write any stored up log entries
for entry in tmp_log.fEntries:
file.write(entry + '\n')
# Also print traceback to log file, which can raise exceptions
import traceback
try:
traceback.print_exc(file=file)
except:
file.write('Exception raised while printing exc')
# Close file if we opened it
if opened_file:
file.close()
# Always stop server and wait for user to exit if requested
finally:
if server != None:
try: server.Stop()
except: pass
if waitonexit:
line = raw_input(_("-- Type return or enter to exit --\n"))
#########################################################################
# Execution starts here
#########################################################################
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment