Support running code in target process to attach to pid in Linux. Partial fix for #863 (#1525)

This commit is contained in:
Fabio Zadrozny 2019-06-19 09:11:38 -03:00 committed by GitHub
parent 1fce9beeb0
commit daf9206912
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
10 changed files with 299 additions and 109 deletions

3
.gitignore vendored
View file

@ -3,9 +3,6 @@ __pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
env/

View file

@ -350,66 +350,50 @@ def run_code():
def attach_to_pid():
def quoted_str(s):
if s is None:
return s
assert not isinstance(s, bytes)
unescaped = set(chr(ch) for ch in range(32, 127)) - {'"', "'", '\\'}
def escape(ch):
return ch if ch in unescaped else '\\u%04X' % ord(ch)
return 'u"' + ''.join(map(escape, s)) + '"'
ptvsd.log.info('Attaching to process with ID {0}', ptvsd.options.target)
pid = ptvsd.options.target
host = quoted_str(ptvsd.options.host)
host = ptvsd.options.host
port = ptvsd.options.port
client = ptvsd.options.client
log_dir = quoted_str(ptvsd.options.log_dir)
ptvsd_path = os.path.abspath(os.path.join(ptvsd.__file__, '../..'))
if isinstance(ptvsd_path, bytes):
ptvsd_path = ptvsd_path.decode(sys.getfilesystemencoding())
ptvsd_path = quoted_str(ptvsd_path)
# pydevd requires injected code to not contain any single quotes.
code = '''
import os
assert os.getpid() == {pid}
import sys
sys.path.insert(0, {ptvsd_path})
import ptvsd
del sys.path[0]
import ptvsd.options
ptvsd.options.log_dir = {log_dir}
ptvsd.options.client = {client}
ptvsd.options.host = {host}
ptvsd.options.port = {port}
import ptvsd.log
ptvsd.log.to_file()
ptvsd.log.info("Debugger successfully injected")
if ptvsd.options.client:
from ptvsd._remote import attach
attach(({host}, {port}))
else:
ptvsd.enable_attach()
'''.format(**locals())
ptvsd.log.debug('Injecting debugger into target process: \n"""{0}\n"""'.format(code))
assert "'" not in code, 'Injected code should not contain any single quotes'
log_dir = ptvsd.options.log_dir
if log_dir is None:
log_dir = ""
# pydevd requires injected code to not contain any single quotes nor new lines and
# double quotes must be escaped properly.
pydevd_attach_to_process_path = os.path.join(
os.path.dirname(pydevd.__file__),
'pydevd_attach_to_process')
sys.path.insert(0, pydevd_attach_to_process_path)
from add_code_to_python_process import run_python_code
run_python_code(pid, code, connect_debugger_tracing=True)
sys.path.append(pydevd_attach_to_process_path)
import add_code_to_python_process # noqa
show_debug_info_on_target_process = 0 # hard-coded (1 to debug)
ptvsd_dirname = os.path.dirname(os.path.dirname(__file__))
log_dir = log_dir.replace('\\', '/')
setup = {'host': host, 'port': port, 'client': client, 'log_dir': log_dir, 'pid': pid}
if sys.platform == 'win32':
setup['pythonpath'] = ptvsd_dirname.replace('\\', '/')
python_code = '''import sys;
sys.path.append("%(pythonpath)s");
from ptvsd import attach_script_ptvsd_pid;
attach_script_ptvsd_pid.attach(port=%(port)s, host="%(host)s", client=%(client)s, log_dir="%(log_dir)s");
'''.replace('\r\n', '').replace('\r', '').replace('\n', '')
else:
setup['pythonpath'] = ptvsd_dirname
# We have to pass it a bit differently for gdb
python_code = '''import sys;
sys.path.append(\\\"%(pythonpath)s\\\");
from ptvsd import attach_script_ptvsd_pid;
attach_script_ptvsd_pid.attach(port=%(port)s, host=\\\"%(host)s\\\", client=%(client)s, log_dir=\\\"%(log_dir)s\\\");
'''.replace('\r\n', '').replace('\r', '').replace('\n', '')
python_code = python_code % setup
add_code_to_python_process.run_python_code(
setup['pid'], python_code, connect_debugger_tracing=True, show_debug_info=show_debug_info_on_target_process)
def main(argv=sys.argv):

View file

@ -912,6 +912,7 @@ class PyDB(object):
self._finish_debugging_session = True
def initialize_network(self, sock, terminate_on_socket_close=True):
assert sock is not None
try:
sock.settimeout(None) # infinite, no timeouts from now on - jython does not have it
except:

View file

@ -60,6 +60,7 @@ typedef int (*PyEval_ThreadsInitialized)();
typedef unsigned long (*_PyEval_GetSwitchInterval)(void);
typedef void (*_PyEval_SetSwitchInterval)(unsigned long microseconds);
typedef int (*PyRun_SimpleString)(const char *command);
typedef int (*PyObject_Not) (PyObject *o);
// Helper so that we get a PyObject where we can access its fields (in debug or release).
PyObject* GetPyObjectPointerNoDebugInfo(bool isDebug, PyObject* object) {
@ -121,7 +122,7 @@ public:
};
# define CHECK_NULL(ptr, msg, returnVal) if(ptr == NULL){if(showDebugInfo){printf(msg);} return returnVal;}
# define CHECK_NULL(ptr, msg, returnVal) if(ptr == NULL){printf(msg); return returnVal;}
int DoAttach(bool isDebug, const char *command, bool showDebugInfo)
{
@ -161,7 +162,7 @@ int DoAttach(bool isDebug, const char *command, bool showDebugInfo)
PyRun_SimpleString pyRun_SimpleString;
*(void**)(&pyRun_SimpleString) = dlsym(main_hndl, "PyRun_SimpleString");
CHECK_NULL(pyRun_SimpleString, "PyRun_SimpleString not found.\n", 6);
CHECK_NULL(pyRun_SimpleString, "PyRun_SimpleString not found.\n", 7);
PyGILState_STATE pyGILState = pyGilStateEnsureFunc();
pyRun_SimpleString(command);
@ -171,7 +172,7 @@ int DoAttach(bool isDebug, const char *command, bool showDebugInfo)
// All of the code below is the same as:
// sys.settrace(pydevd.GetGlobalDebugger().trace_dispatch)
// sys.settrace(pydevd.get_global_debugger().trace_dispatch)
//
// (with error checking)
int SetSysTraceFunc(bool showDebugInfo, bool isDebug)
@ -188,25 +189,25 @@ int SetSysTraceFunc(bool showDebugInfo, bool isDebug)
if(showDebugInfo){
printf("Py_IsInitialized returned false.\n");
}
return 2;
return 20;
}
PythonVersion version = GetPythonVersion();
PyInterpreterState_Head interpHeadFunc;
*(void**)(&interpHeadFunc) = dlsym(main_hndl, "PyInterpreterState_Head");
CHECK_NULL(interpHeadFunc, "PyInterpreterState_Head not found.\n", 3);
CHECK_NULL(interpHeadFunc, "PyInterpreterState_Head not found.\n", 21);
PyInterpreterState* head = interpHeadFunc();
CHECK_NULL(head, "Interpreter not initialized.\n", 4);
CHECK_NULL(head, "Interpreter not initialized.\n", 22);
PyGILState_Ensure pyGilStateEnsureFunc;
*(void**)(&pyGilStateEnsureFunc) = dlsym(main_hndl, "PyGILState_Ensure");
CHECK_NULL(pyGilStateEnsureFunc, "PyGILState_Ensure not found.\n", 5);
CHECK_NULL(pyGilStateEnsureFunc, "PyGILState_Ensure not found.\n", 23);
PyGILState_Release pyGilStateReleaseFunc;
*(void**)(&pyGilStateReleaseFunc) = dlsym(main_hndl, "PyGILState_Release");
CHECK_NULL(pyGilStateReleaseFunc, "PyGILState_Release not found.\n", 6);
CHECK_NULL(pyGilStateReleaseFunc, "PyGILState_Release not found.\n", 24);
PyGILState_STATE pyGILState = pyGilStateEnsureFunc();
int ret = _PYDEVD_ExecWithGILSetSysStrace(showDebugInfo, isDebug);
@ -221,63 +222,91 @@ int _PYDEVD_ExecWithGILSetSysStrace(bool showDebugInfo, bool isDebug){
void *main_hndl = dlopen(NULL, 0x2);
*(void**)(&boolFromLongFunc) = dlsym(main_hndl, "PyBool_FromLong");
CHECK_NULL(boolFromLongFunc, "PyBool_FromLong not found.\n", 7);
CHECK_NULL(boolFromLongFunc, "PyBool_FromLong not found.\n", 41);
PyObject_HasAttrString pyHasAttrFunc;
*(void**)(&pyHasAttrFunc) = dlsym(main_hndl, "PyObject_HasAttrString");
CHECK_NULL(pyHasAttrFunc, "PyObject_HasAttrString not found.\n", 7);
CHECK_NULL(pyHasAttrFunc, "PyObject_HasAttrString not found.\n", 42);
//Important: we need a non-blocking import here: PyImport_ImportModule
//could end up crashing (this makes us work only from 2.6 onwards).
PyImport_ImportModuleNoBlock pyImportModFunc;
*(void**)(&pyImportModFunc) = dlsym(main_hndl, "PyImport_ImportModuleNoBlock");
CHECK_NULL(pyImportModFunc, "PyImport_ImportModuleNoBlock not found.\n", 8);
CHECK_NULL(pyImportModFunc, "PyImport_ImportModuleNoBlock not found.\n", 43);
PyObject_Not pyObjectNot;
*(void**)(&pyObjectNot) = dlsym(main_hndl, "PyObject_Not");
CHECK_NULL(pyObjectNot, "PyObject_Not not found.\n", 44);
PyObjectHolder pydevdTracingMod = PyObjectHolder(isDebug, pyImportModFunc("pydevd_tracing"));
CHECK_NULL(pydevdTracingMod.ToPython(), "pydevd_tracing module null.\n", 9);
CHECK_NULL(pydevdTracingMod.ToPython(), "pydevd_tracing module null.\n", 45);
if(!pyHasAttrFunc(pydevdTracingMod.ToPython(), "_original_settrace")){
if(showDebugInfo){
printf("pydevd_tracing module has no _original_settrace!\n");
}
return 8;
return 46;
}
PyObject_GetAttrString pyGetAttr;
*(void**)(&pyGetAttr) = dlsym(main_hndl, "PyObject_GetAttrString");
CHECK_NULL(pyGetAttr, "PyObject_GetAttrString not found.\n", 8);
CHECK_NULL(pyGetAttr, "PyObject_GetAttrString not found.\n", 47);
PyObjectHolder settrace = PyObjectHolder(isDebug, pyGetAttr(pydevdTracingMod.ToPython(), "_original_settrace"));
CHECK_NULL(settrace.ToPython(), "pydevd_tracing._original_settrace null!\n", 10);
CHECK_NULL(settrace.ToPython(), "pydevd_tracing._original_settrace null!\n", 48);
if(pyObjectNot(settrace.ToPython())){
printf("_original_settrace is None.");
return 49;
}
PyObjectHolder pydevdMod = PyObjectHolder(isDebug, pyImportModFunc("pydevd"));
CHECK_NULL(pydevdMod.ToPython(), "pydevd module null.\n", 10);
CHECK_NULL(pydevdMod.ToPython(), "pydevd module null.\n", 50);
PyObjectHolder getGlobalDebugger = PyObjectHolder(isDebug, pyGetAttr(pydevdMod.ToPython(), "GetGlobalDebugger"));
CHECK_NULL(getGlobalDebugger.ToPython(), "pydevd.GetGlobalDebugger null.\n", 11);
if(pyObjectNot(pydevdMod.ToPython())){
printf("pydevdMod is None.");
return 51;
}
if(!pyHasAttrFunc(pydevdMod.ToPython(), "get_global_debugger")){
printf("pydevd module has no attribute get_global_debugger!\n");
return 52;
}
PyObjectHolder getGlobalDebugger = PyObjectHolder(isDebug, pyGetAttr(pydevdMod.ToPython(), "get_global_debugger"));
CHECK_NULL(getGlobalDebugger.ToPython(), "pydevd.get_global_debugger is null.\n", 53);
if(pyObjectNot(getGlobalDebugger.ToPython())){
printf("getGlobalDebugger returned None.");
return 54;
}
PyObject_CallFunctionObjArgs call;
*(void**)(&call) = dlsym(main_hndl, "PyObject_CallFunctionObjArgs");
CHECK_NULL(call, "PyObject_CallFunctionObjArgs not found.\n", 11);
CHECK_NULL(call, "PyObject_CallFunctionObjArgs not found.\n", 55);
PyObjectHolder globalDbg = PyObjectHolder(isDebug, call(getGlobalDebugger.ToPython(), NULL));
CHECK_NULL(globalDbg.ToPython(), "pydevd.GetGlobalDebugger() returned null.\n", 12);
CHECK_NULL(globalDbg.ToPython(), "pydevd.get_global_debugger() returned null.\n", 56);
if(!pyHasAttrFunc(globalDbg.ToPython(), "trace_dispatch")){
if(showDebugInfo){
printf("pydevd.GetGlobalDebugger() has no attribute trace_dispatch!\n");
}
return 13;
printf("pydevd.get_global_debugger() has no attribute trace_dispatch!\n");
return 57;
}
PyObjectHolder traceFunc = PyObjectHolder(isDebug, pyGetAttr(globalDbg.ToPython(), "trace_dispatch"));
CHECK_NULL(traceFunc.ToPython(), "pydevd.GetGlobalDebugger().trace_dispatch returned null!\n", 14);
CHECK_NULL(traceFunc.ToPython(), "pydevd.get_global_debugger().trace_dispatch returned null!\n", 58);
if(pyObjectNot(traceFunc.ToPython())){
printf("pydevd.get_global_debugger().trace_dispatch is None.");
return 59;
}
DecRef(call(settrace.ToPython(), traceFunc.ToPython(), NULL), isDebug);
if(showDebugInfo){
printf("sys.settrace(pydevd.GetGlobalDebugger().trace_dispatch) worked.\n");
printf("sys.settrace(pydevd.get_global_debugger().trace_dispatch) worked.\n");
}
return 0;

View file

@ -26,7 +26,10 @@ enum PythonVersion {
PythonVersion_31 = 0x0301,
PythonVersion_32 = 0x0302,
PythonVersion_33 = 0x0303,
PythonVersion_34 = 0x0304
PythonVersion_34 = 0x0304,
PythonVersion_35 = 0x0305,
PythonVersion_36 = 0x0306,
PythonVersion_37 = 0x0307
};
@ -111,8 +114,8 @@ public:
}
};
// 3.3-3.4
class PyCodeObject33_34 : public PyObject {
// 3.3-3.5
class PyCodeObject33_35 : public PyObject {
public:
int co_argcount; /* #arguments, except *args */
int co_kwonlyargcount; /* #keyword only arguments */
@ -134,15 +137,77 @@ public:
void *co_zombieframe; /* for optimization only (see frameobject.c) */
static bool IsFor(int majorVersion, int minorVersion) {
return majorVersion == 3 && (minorVersion >= 3 && minorVersion <= 4);
return majorVersion == 3 && (minorVersion >= 3 && minorVersion <= 5);
}
static bool IsFor(PythonVersion version) {
return version >= PythonVersion_33 && version <= PythonVersion_34;
return version >= PythonVersion_33 && version <= PythonVersion_35;
}
};
// 2.5 - 3.1
// 3.6
class PyCodeObject36 : public PyObject {
public:
int co_argcount; /* #arguments, except *args */
int co_kwonlyargcount; /* #keyword only arguments */
int co_nlocals; /* #local variables */
int co_stacksize; /* #entries needed for evaluation stack */
int co_flags; /* CO_..., see below */
int co_firstlineno; /* first source line number */
PyObject *co_code; /* instruction opcodes */
PyObject *co_consts; /* list (constants used) */
PyObject *co_names; /* list of strings (names used) */
PyObject *co_varnames; /* tuple of strings (local variable names) */
PyObject *co_freevars; /* tuple of strings (free variable names) */
PyObject *co_cellvars; /* tuple of strings (cell variable names) */
/* The rest doesn't count for hash or comparisons */
unsigned char *co_cell2arg; /* Maps cell vars which are arguments. */
PyObject *co_filename; /* unicode (where it was loaded from) */
PyObject *co_name; /* unicode (name, for reference) */
PyObject *co_lnotab; /* string (encoding addr<->lineno mapping) */
void *co_zombieframe; /* for optimization only (see frameobject.c) */
static bool IsFor(int majorVersion, int minorVersion) {
return majorVersion == 3 && minorVersion == 6;
}
static bool IsFor(PythonVersion version) {
return version == PythonVersion_36;
}
};
// 3.7
class PyCodeObject37 : public PyObject {
public:
int co_argcount; /* #arguments, except *args */
int co_kwonlyargcount; /* #keyword only arguments */
int co_nlocals; /* #local variables */
int co_stacksize; /* #entries needed for evaluation stack */
int co_flags; /* CO_..., see below */
int co_firstlineno; /* first source line number */
PyObject *co_code; /* instruction opcodes */
PyObject *co_consts; /* list (constants used) */
PyObject *co_names; /* list of strings (names used) */
PyObject *co_varnames; /* tuple of strings (local variable names) */
PyObject *co_freevars; /* tuple of strings (free variable names) */
PyObject *co_cellvars; /* tuple of strings (cell variable names) */
/* The rest doesn't count for hash or comparisons */
ssize_t *co_cell2arg; /* Maps cell vars which are arguments. */
PyObject *co_filename; /* unicode (where it was loaded from) */
PyObject *co_name; /* unicode (name, for reference) */
PyObject *co_lnotab; /* string (encoding addr<->lineno mapping) */
void *co_zombieframe; /* for optimization only (see frameobject.c) */
static bool IsFor(int majorVersion, int minorVersion) {
return majorVersion == 3 && minorVersion >= 7;
}
static bool IsFor(PythonVersion version) {
return version >= PythonVersion_37;
}
};
// 2.5 - 3.7
class PyFunctionObject : public PyObject {
public:
PyObject *func_code; /* A code object */
@ -165,7 +230,7 @@ public:
*/
};
// 2.4 - 3.2 compatible
// 2.4 - 3.7 compatible
typedef struct {
PyObject_HEAD
size_t length; /* Length of raw Unicode data in buffer */
@ -173,7 +238,7 @@ typedef struct {
long hash; /* Hash value; -1 if not set */
} PyUnicodeObject;
// 2.4 - 3.4 compatible
// 2.4 - 3.7 compatible
class PyFrameObject : public PyVarObject {
public:
PyFrameObject *f_back; /* previous frame, or NULL */
@ -187,7 +252,6 @@ public:
to the current stack top. */
PyObject **f_stacktop;
PyObject *f_trace; /* Trace function */
PyObject *f_exc_type, *f_exc_value, *f_exc_traceback;
};
#define CO_MAXBLOCKS 20
@ -199,6 +263,7 @@ typedef struct {
class PyFrameObject25_33 : public PyFrameObject {
public:
PyObject * f_exc_type, *f_exc_value, *f_exc_traceback;
PyThreadState* f_tstate;
int f_lasti; /* Last instruction if called */
/* As of 2.3 f_lineno is only valid when tracing is active (i.e. when
@ -214,8 +279,9 @@ public:
}
};
class PyFrameObject34 : public PyFrameObject {
class PyFrameObject34_36 : public PyFrameObject {
public:
PyObject * f_exc_type, *f_exc_value, *f_exc_traceback;
/* Borrowed reference to a generator, or NULL */
PyObject *f_gen;
@ -229,22 +295,43 @@ public:
PyObject *f_localsplus[1]; /* locals+stack, dynamically sized */
static bool IsFor(int majorVersion, int minorVersion) {
return majorVersion == 3 && minorVersion == 4;
return majorVersion == 3 && minorVersion >= 4 && minorVersion <= 6;
}
};
class PyFrameObject37 : public PyFrameObject {
public:
char f_trace_lines; /* Emit per-line trace events? */
char f_trace_opcodes; /* Emit per-opcode trace events? */
/* Borrowed reference to a generator, or NULL */
PyObject *f_gen;
int f_lasti; /* Last instruction if called */
/* As of 2.3 f_lineno is only valid when tracing is active (i.e. when
f_trace is set) -- at other times use PyCode_Addr2Line instead. */
int f_lineno; /* Current line number */
int f_iblock; /* index in f_blockstack */
char f_executing; /* whether the frame is still executing */
PyTryBlock f_blockstack[CO_MAXBLOCKS]; /* for try and loop blocks */
PyObject *f_localsplus[1]; /* locals+stack, dynamically sized */
static bool IsFor(int majorVersion, int minorVersion) {
return majorVersion == 3 && minorVersion >= 7;
}
};
typedef void (*destructor)(PyObject *);
// 2.4 - 3.4
// 2.4 - 3.7
class PyMethodDef {
public:
char *ml_name; /* The name of the built-in function/method */
};
//
// 2.4 - 3.4, 2.4 has different compat in 64-bit but we don't support any of the released 64-bit platforms (which includes only IA-64)
//
// 2.5 - 3.7
// While these are compatible there are fields only available on later versions.
class PyTypeObject : public PyVarObject {
public:
@ -257,7 +344,10 @@ public:
void* tp_print;
void* tp_getattr;
void* tp_setattr;
void* tp_compare;
union {
void* tp_compare; /* 2.4 - 3.4 */
void *tp_as_async; /* 3.5 - 3.7 */
};
void* tp_repr;
/* Method suites for standard classes */
@ -326,7 +416,7 @@ public:
unsigned int tp_version_tag;
};
// 2.4 - 3.4
// 2.4 - 3.7
class PyTupleObject : public PyVarObject {
public:
PyObject *ob_item[1];
@ -337,7 +427,7 @@ public:
*/
};
// 2.4 - 3.4
// 2.4 - 3.7
class PyCFunctionObject : public PyObject {
public:
PyMethodDef *m_ml; /* Description of the C function to call */
@ -422,7 +512,7 @@ public:
int recursion_depth;
char overflowed; /* The stack has overflowed. Allow 50 more calls
to handle the runtime error. */
char recursion_critical; /* The current calls must not cause
char recursion_critical; /* The current calls must not cause
a stack overflow. */
/* 'tracing' keeps track of the execution depth when tracing/profiling.
This is to prevent the actual trace/profile code from being recorded in
@ -468,7 +558,7 @@ public:
}
};
class PyThreadState_34 : public PyThreadState {
class PyThreadState_34_36 : public PyThreadState {
public:
PyThreadState *prev;
PyThreadState *next;
@ -478,7 +568,7 @@ public:
int recursion_depth;
char overflowed; /* The stack has overflowed. Allow 50 more calls
to handle the runtime error. */
char recursion_critical; /* The current calls must not cause
char recursion_critical; /* The current calls must not cause
a stack overflow. */
/* 'tracing' keeps track of the execution depth when tracing/profiling.
This is to prevent the actual trace/profile code from being recorded in
@ -504,15 +594,70 @@ public:
int gilstate_counter;
PyObject *async_exc; /* Asynchronous exception to raise */
long thread_id; /* Thread id where this tstate was created */
long thread_id; /* Thread id where this tstate was created */
/* XXX signal handlers should also be here */
static bool IsFor(int majorVersion, int minorVersion) {
return majorVersion == 3 && minorVersion == 4;
return majorVersion == 3 && minorVersion >= 4 && minorVersion <= 6;
}
static bool IsFor(PythonVersion version) {
return version == PythonVersion_34;
return version >= PythonVersion_34 && version <= PythonVersion_36;
}
};
struct _PyErr_StackItem {
PyObject *exc_type, *exc_value, *exc_traceback;
struct _PyErr_StackItem *previous_item;
};
class PyThreadState_37 : public PyThreadState {
public:
PyThreadState * prev;
PyThreadState *next;
PyInterpreterState *interp;
PyFrameObject *frame;
int recursion_depth;
char overflowed; /* The stack has overflowed. Allow 50 more calls
to handle the runtime error. */
char recursion_critical; /* The current calls must not cause
a stack overflow. */
/* 'tracing' keeps track of the execution depth when tracing/profiling.
This is to prevent the actual trace/profile code from being recorded in
the trace/profile. */
int stackcheck_counter;
int tracing;
int use_tracing;
Py_tracefunc c_profilefunc;
Py_tracefunc c_tracefunc;
PyObject *c_profileobj;
PyObject *c_traceobj;
PyObject *curexc_type;
PyObject *curexc_value;
PyObject *curexc_traceback;
_PyErr_StackItem exc_state;
_PyErr_StackItem *exc_info;
PyObject *dict; /* Stores per-thread state */
int gilstate_counter;
PyObject *async_exc; /* Asynchronous exception to raise */
unsigned long thread_id; /* Thread id where this tstate was created */
static bool IsFor(int majorVersion, int minorVersion) {
return majorVersion == 3 && minorVersion >= 7;
}
static bool IsFor(PythonVersion version) {
return version >= PythonVersion_37;
}
};
@ -553,19 +698,23 @@ static PythonVersion GetPythonVersion() {
if(versionFunc != NULL) {
const char* version = versionFunc();
if(version != NULL && strlen(version) >= 3 && version[1] == '.') {
if(version[0] == '2') {
switch(version[2]) {
if (version[0] == '2') {
switch (version[2]) {
case '5': return PythonVersion_25;
case '6': return PythonVersion_26;
case '7': return PythonVersion_27;
}
} else if(version[0] == '3') {
switch(version[2]) {
}
else if (version[0] == '3') {
switch (version[2]) {
case '0': return PythonVersion_30;
case '1': return PythonVersion_31;
case '2': return PythonVersion_32;
case '3': return PythonVersion_33;
case '4': return PythonVersion_34;
case '5': return PythonVersion_35;
case '6': return PythonVersion_36;
case '7': return PythonVersion_37;
}
}
}

View file

@ -0,0 +1,24 @@
def attach(port, host, client, log_dir):
try:
if not log_dir:
log_dir = None
import ptvsd.options
ptvsd.options.log_dir = log_dir
ptvsd.options.client = client
ptvsd.options.host = host
ptvsd.options.port = port
import ptvsd.log
ptvsd.log.to_file()
ptvsd.log.info("Debugger successfully injected")
if ptvsd.options.client:
from ptvsd._remote import attach
attach((host, port))
else:
ptvsd.enable_attach((host, port))
except:
import traceback
traceback.print_exc()

View file

@ -127,9 +127,15 @@ def install(pydevd_module, address,
addr = Address.from_raw(address)
daemon = Daemon(**kwargs)
_start_server = (lambda p: start_server(daemon, addr.host, p))
def _start_server(p):
ptvsd.log.debug('ptvsd: install._start_server.')
return start_server(daemon, addr.host, p)
def _start_client(h, p):
ptvsd.log.debug('ptvsd: install._start_client.')
return start_client(daemon, h, p)
_start_server.orig = start_server
_start_client = (lambda h, p: start_client(daemon, h, p))
_start_client.orig = start_client
# These are the functions pydevd invokes to get a socket to the client.