mirror of
https://github.com/microsoft/debugpy.git
synced 2025-12-23 08:48:12 +00:00
This commit is contained in:
parent
1fce9beeb0
commit
daf9206912
10 changed files with 299 additions and 109 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -3,9 +3,6 @@ __pycache__/
|
|||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
env/
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
BIN
src/ptvsd/_vendored/pydevd/pydevd_attach_to_process/attach_linux_amd64.so
Executable file
BIN
src/ptvsd/_vendored/pydevd/pydevd_attach_to_process/attach_linux_amd64.so
Executable file
Binary file not shown.
BIN
src/ptvsd/_vendored/pydevd/pydevd_attach_to_process/attach_linux_x86.so
Executable file
BIN
src/ptvsd/_vendored/pydevd/pydevd_attach_to_process/attach_linux_x86.so
Executable file
Binary file not shown.
|
|
@ -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;
|
||||
|
|
|
|||
0
src/ptvsd/_vendored/pydevd/pydevd_attach_to_process/linux/compile_so.sh
Normal file → Executable file
0
src/ptvsd/_vendored/pydevd/pydevd_attach_to_process/linux/compile_so.sh
Normal file → Executable 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
24
src/ptvsd/attach_script_ptvsd_pid.py
Normal file
24
src/ptvsd/attach_script_ptvsd_pid.py
Normal 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()
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue