2016-04-27 01:56:16 +08:00
|
|
|
|
#include "stdafx.h"
|
|
|
|
|
|
|
|
|
|
#include <algorithm>
|
|
|
|
|
#include <sstream>
|
2016-10-01 18:12:57 +08:00
|
|
|
|
#include <fstream>
|
2016-04-27 01:56:16 +08:00
|
|
|
|
#include <iomanip>
|
2016-10-01 18:12:57 +08:00
|
|
|
|
#include <regex>
|
2016-04-27 01:56:16 +08:00
|
|
|
|
|
|
|
|
|
#include <DbgEng.h>
|
|
|
|
|
|
|
|
|
|
#include "dbgout.h"
|
|
|
|
|
#include "arglist.h"
|
|
|
|
|
#include "pyinterpret.h"
|
|
|
|
|
#include "pyapi.h"
|
|
|
|
|
#include "pyclass.h"
|
2016-07-01 19:22:59 +08:00
|
|
|
|
#include "version.h"
|
2016-04-27 01:56:16 +08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
void handleException();
|
|
|
|
|
std::string getScriptFileName(const std::string &scriptName);
|
2016-06-24 23:05:43 +08:00
|
|
|
|
void getPythonVersion(int& majorVersion, int& minorVersion);
|
|
|
|
|
void getDefaultPythonVersion(int& majorVersion, int& minorVersion);
|
2016-04-27 01:56:16 +08:00
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
class InterruptWatch
|
|
|
|
|
{
|
|
|
|
|
public:
|
|
|
|
|
|
|
|
|
|
InterruptWatch(PDEBUG_CLIENT client)
|
|
|
|
|
{
|
|
|
|
|
m_control = client;
|
|
|
|
|
m_stopEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
|
|
|
|
|
m_thread = CreateThread(NULL, 0, threadRoutine, this, 0, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~InterruptWatch()
|
|
|
|
|
{
|
|
|
|
|
SetEvent(m_stopEvent);
|
|
|
|
|
WaitForSingleObject(m_thread, INFINITE);
|
|
|
|
|
CloseHandle(m_stopEvent);
|
|
|
|
|
CloseHandle(m_thread);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int quit(void *context)
|
|
|
|
|
{
|
|
|
|
|
HANDLE quitEvent = (HANDLE)context;
|
|
|
|
|
PyErr_SetString(PyExc_SystemExit(), "CTRL+BREAK");
|
|
|
|
|
SetEvent(quitEvent);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
|
|
|
|
|
static DWORD WINAPI threadRoutine(LPVOID lpParameter) {
|
|
|
|
|
return static_cast<InterruptWatch*>(lpParameter)->interruptWatchRoutine();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DWORD InterruptWatch::interruptWatchRoutine()
|
|
|
|
|
{
|
|
|
|
|
while (WAIT_TIMEOUT == WaitForSingleObject(m_stopEvent, 250))
|
|
|
|
|
{
|
|
|
|
|
HRESULT hres = m_control->GetInterrupt();
|
|
|
|
|
if (hres == S_OK)
|
|
|
|
|
{
|
|
|
|
|
HANDLE quitEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
|
|
|
|
|
PyGILState_STATE state = PyGILState_Ensure();
|
|
|
|
|
Py_AddPendingCall(&quit, (void*)quitEvent);
|
|
|
|
|
PyGILState_Release(state);
|
|
|
|
|
WaitForSingleObject(quitEvent, INFINITE);
|
|
|
|
|
CloseHandle(quitEvent);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
HANDLE m_thread;
|
|
|
|
|
|
|
|
|
|
HANDLE m_stopEvent;
|
|
|
|
|
|
|
|
|
|
CComQIPtr<IDebugControl> m_control;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
extern "C"
|
|
|
|
|
HRESULT
|
|
|
|
|
CALLBACK
|
|
|
|
|
DebugExtensionInitialize(
|
|
|
|
|
PULONG Version,
|
|
|
|
|
PULONG Flags
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
return S_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
extern "C"
|
|
|
|
|
VOID
|
|
|
|
|
CALLBACK
|
|
|
|
|
DebugExtensionUninitialize()
|
|
|
|
|
{
|
2016-06-22 03:27:57 +08:00
|
|
|
|
stopAllInterpreter();
|
2016-04-27 01:56:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
std::string make_version(int major, int minor)
|
|
|
|
|
{
|
|
|
|
|
std::stringstream sstr;
|
2016-04-28 06:18:55 +08:00
|
|
|
|
sstr << std::dec << major << '.' << minor;
|
|
|
|
|
|
|
|
|
|
#ifdef _WIN64
|
|
|
|
|
|
|
|
|
|
sstr << " x86-64";
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
|
|
sstr << " x86-32";
|
|
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
2016-04-27 01:56:16 +08:00
|
|
|
|
return sstr.str();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
extern "C"
|
|
|
|
|
HRESULT
|
|
|
|
|
CALLBACK
|
|
|
|
|
info(
|
|
|
|
|
PDEBUG_CLIENT client,
|
|
|
|
|
PCSTR args
|
|
|
|
|
)
|
|
|
|
|
{
|
2016-09-15 18:49:08 +08:00
|
|
|
|
try
|
|
|
|
|
{
|
|
|
|
|
std::stringstream sstr;
|
2016-04-27 01:56:16 +08:00
|
|
|
|
|
2016-09-15 18:49:08 +08:00
|
|
|
|
sstr <<std::endl << "pykd bootstrapper version: " << PYKDEXT_VERSION_MAJOR << '.' << PYKDEXT_VERSION_MINOR << '.'
|
|
|
|
|
<< PYKDEXT_VERSION_SUBVERSION << '.' << PYKDEXT_VERSION_BUILDNO << std::endl;
|
2016-07-01 19:22:59 +08:00
|
|
|
|
|
2016-09-15 18:49:08 +08:00
|
|
|
|
std::list<InterpreterDesc> interpreterList = getInstalledInterpreter();
|
2016-07-01 19:22:59 +08:00
|
|
|
|
|
2016-09-15 18:49:08 +08:00
|
|
|
|
int defaultMajor;
|
|
|
|
|
int defaultMinor;
|
2016-06-24 23:05:43 +08:00
|
|
|
|
|
2016-09-15 18:49:08 +08:00
|
|
|
|
getDefaultPythonVersion(defaultMajor, defaultMinor);
|
2016-06-24 23:05:43 +08:00
|
|
|
|
|
2016-09-15 18:49:08 +08:00
|
|
|
|
sstr << std::endl << "Installed python:" << std::endl << std::endl;
|
|
|
|
|
sstr << std::setw(16) << std::left << "Version:" << std::setw(12) << std::left << "Status: " << std::left << "Image:" << std::endl;
|
|
|
|
|
sstr << "------------------------------------------------------------------------------" << std::endl;
|
|
|
|
|
if (interpreterList.size() > 0)
|
2016-04-27 01:56:16 +08:00
|
|
|
|
{
|
2016-09-15 18:49:08 +08:00
|
|
|
|
for (const InterpreterDesc& desc : interpreterList)
|
|
|
|
|
{
|
|
|
|
|
if ( defaultMajor == desc.majorVersion && defaultMinor == desc.minorVersion)
|
|
|
|
|
sstr << "* ";
|
|
|
|
|
else
|
|
|
|
|
sstr << " ";
|
2016-06-24 23:05:43 +08:00
|
|
|
|
|
2016-09-15 18:49:08 +08:00
|
|
|
|
sstr << std::setw(14) << std::left << make_version(desc.majorVersion, desc.minorVersion);
|
2016-04-28 06:18:55 +08:00
|
|
|
|
|
2016-09-15 18:49:08 +08:00
|
|
|
|
sstr << std::setw(12) << std::left << (isInterpreterLoaded(desc.majorVersion, desc.minorVersion) ? "Loaded" : "Unloaded");
|
2016-04-28 06:18:55 +08:00
|
|
|
|
|
2016-09-15 18:49:08 +08:00
|
|
|
|
sstr << desc.imagePath << std::endl;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
sstr << "No python interpreter found" << std::endl;
|
2016-04-27 01:56:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
2016-09-15 18:49:08 +08:00
|
|
|
|
sstr << std::endl;
|
2016-04-27 01:56:16 +08:00
|
|
|
|
|
2016-09-15 18:49:08 +08:00
|
|
|
|
CComQIPtr<IDebugControl> control = client;
|
2016-04-27 01:56:16 +08:00
|
|
|
|
|
2016-09-15 18:49:08 +08:00
|
|
|
|
control->ControlledOutput(
|
|
|
|
|
DEBUG_OUTCTL_THIS_CLIENT,
|
|
|
|
|
DEBUG_OUTPUT_NORMAL,
|
|
|
|
|
sstr.str().c_str()
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
catch(std::exception &e)
|
|
|
|
|
{
|
|
|
|
|
CComQIPtr<IDebugControl> control = client;
|
|
|
|
|
|
|
|
|
|
control->ControlledOutput(
|
|
|
|
|
DEBUG_OUTCTL_THIS_CLIENT,
|
|
|
|
|
DEBUG_OUTPUT_ERROR,
|
|
|
|
|
e.what()
|
|
|
|
|
);
|
|
|
|
|
}
|
2016-04-27 01:56:16 +08:00
|
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
static const char printUsageMsg[] =
|
2016-06-22 04:44:29 +08:00
|
|
|
|
"\n"
|
2016-04-27 01:56:16 +08:00
|
|
|
|
"usage:\n"
|
2016-06-22 04:44:29 +08:00
|
|
|
|
"\n"
|
|
|
|
|
"!help\n"
|
|
|
|
|
"\tprint this text\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"!info\n"
|
|
|
|
|
"\tlist installed python interpreters\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"!py [version] [options] [file]\n"
|
|
|
|
|
"\trun python script or REPL\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"\tVersion:\n"
|
|
|
|
|
"\t-2 : use Python2\n"
|
|
|
|
|
"\t-2.x : use Python2.x\n"
|
|
|
|
|
"\t-3 : use Python3\n"
|
|
|
|
|
"\t-3.x : use Python3.x\n"
|
|
|
|
|
"\n"
|
2016-04-27 01:56:16 +08:00
|
|
|
|
"\tOptions:\n"
|
|
|
|
|
"\t-g --global : run code in the common namespace\n"
|
2016-06-22 04:44:29 +08:00
|
|
|
|
"\t-l --local : run code in the isolated namespace\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"\tcommand samples:\n"
|
|
|
|
|
"\t\"!py\" : run REPL\n"
|
|
|
|
|
"\t\"!py --local\" : run REPL in the isolated namespace\n"
|
|
|
|
|
"\t\"!py -g script.py 10 \"string\"\" : run script file with argument in the commom namespace\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"!pip [version] [args]\n"
|
|
|
|
|
"\trun pip package manager\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"\tVersion:\n"
|
|
|
|
|
"\t-2 : use Python2\n"
|
|
|
|
|
"\t-2.x : use Python2.x\n"
|
|
|
|
|
"\t-3 : use Python3\n"
|
|
|
|
|
"\t-3.x : use Python3.x\n"
|
|
|
|
|
"\n"
|
|
|
|
|
"\tpip command samples:\n"
|
|
|
|
|
"\t\"pip list\" : show all installed packagies\n"
|
|
|
|
|
"\t\"pip install pykd\" : install pykd\n"
|
|
|
|
|
"\t\"pip install --upgrade pykd\" : upgrade pykd to the latest version\n"
|
|
|
|
|
"\t\"pip show pykd\" : show info about pykd package\n"
|
|
|
|
|
;
|
|
|
|
|
|
2016-04-28 06:18:55 +08:00
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
extern "C"
|
|
|
|
|
HRESULT
|
|
|
|
|
CALLBACK
|
|
|
|
|
help(
|
|
|
|
|
PDEBUG_CLIENT client,
|
|
|
|
|
PCSTR args
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
CComQIPtr<IDebugControl> control = client;
|
|
|
|
|
|
|
|
|
|
control->ControlledOutput(
|
|
|
|
|
DEBUG_OUTCTL_THIS_CLIENT,
|
|
|
|
|
DEBUG_OUTPUT_NORMAL,
|
|
|
|
|
printUsageMsg
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
2016-04-27 01:56:16 +08:00
|
|
|
|
|
2016-10-01 18:12:57 +08:00
|
|
|
|
|
|
|
|
|
static const std::regex shebangRe("^#!\\s*python([2,3])(?:\\.(\\d))?$");
|
|
|
|
|
|
2016-04-27 01:56:16 +08:00
|
|
|
|
extern "C"
|
|
|
|
|
HRESULT
|
|
|
|
|
CALLBACK
|
|
|
|
|
py(
|
|
|
|
|
PDEBUG_CLIENT client,
|
|
|
|
|
PCSTR args
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
ULONG oldMask;
|
|
|
|
|
client->GetOutputMask(&oldMask);
|
|
|
|
|
client->SetOutputMask(DEBUG_OUTPUT_NORMAL | DEBUG_OUTPUT_ERROR);
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
|
2016-10-01 18:12:57 +08:00
|
|
|
|
Options opts(args);
|
2016-04-27 01:56:16 +08:00
|
|
|
|
|
|
|
|
|
if (opts.showHelp)
|
|
|
|
|
throw std::exception(printUsageMsg);
|
|
|
|
|
|
|
|
|
|
int majorVersion = opts.pyMajorVersion;
|
|
|
|
|
int minorVersion = opts.pyMinorVersion;
|
|
|
|
|
|
2016-10-01 18:12:57 +08:00
|
|
|
|
if ( opts.args.size() > 0 && majorVersion == -1 && minorVersion == -1 )
|
|
|
|
|
{
|
|
|
|
|
std::ifstream scriptFile(opts.args[0]);
|
|
|
|
|
|
|
|
|
|
std::string firstline;
|
|
|
|
|
std::getline(scriptFile, firstline);
|
|
|
|
|
|
|
|
|
|
std::smatch mres;
|
|
|
|
|
if (std::regex_match(firstline, mres, shebangRe))
|
|
|
|
|
{
|
|
|
|
|
majorVersion = atol(std::string(mres[1].first, mres[1].second).c_str());
|
|
|
|
|
|
|
|
|
|
if (mres[2].matched)
|
|
|
|
|
{
|
|
|
|
|
minorVersion = atol(std::string(mres[2].first, mres[2].second).c_str());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-27 01:56:16 +08:00
|
|
|
|
getPythonVersion(majorVersion, minorVersion);
|
|
|
|
|
|
|
|
|
|
AutoInterpreter autoInterpreter(opts.global, majorVersion, minorVersion);
|
|
|
|
|
|
2016-12-27 05:24:15 +08:00
|
|
|
|
//PyObjectRef mainName = IsPy3() ? PyUnicode_FromString("__main__") : PyString_FromString("__main__");
|
|
|
|
|
PyObjectRef mainMod = PyImport_ImportModule("__main__");
|
|
|
|
|
PyObjectRef globals = PyObject_GetAttrString(mainMod, "__dict__");
|
|
|
|
|
|
2016-04-27 01:56:16 +08:00
|
|
|
|
PyObjectRef dbgOut = make_pyobject<DbgOut>(client);
|
|
|
|
|
PySys_SetObject("stdout", dbgOut);
|
|
|
|
|
|
|
|
|
|
PyObjectRef dbgErr = make_pyobject<DbgOut>(client);
|
|
|
|
|
PySys_SetObject("stderr", dbgErr);
|
|
|
|
|
|
|
|
|
|
PyObjectRef dbgIn = make_pyobject<DbgIn>(client);
|
|
|
|
|
PySys_SetObject("stdin", dbgIn);
|
|
|
|
|
|
|
|
|
|
InterruptWatch interruptWatch(client);
|
|
|
|
|
|
|
|
|
|
if (opts.args.empty())
|
|
|
|
|
{
|
2016-06-22 04:44:29 +08:00
|
|
|
|
PyObjectRef result = PyRun_String("import pykd\nfrom pykd import *\n", Py_file_input, globals, globals);
|
|
|
|
|
PyErr_Clear();
|
|
|
|
|
result = PyRun_String("import code\ncode.InteractiveConsole(globals()).interact()\n", Py_file_input, globals, globals);
|
2016-04-27 01:56:16 +08:00
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
std::string scriptFileName = getScriptFileName(opts.args[0]);
|
|
|
|
|
if (scriptFileName.empty())
|
|
|
|
|
throw std::invalid_argument("script not found\n");
|
|
|
|
|
|
|
|
|
|
if (IsPy3())
|
|
|
|
|
{
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
std::vector<wchar_t*> pythonArgs(opts.args.size());
|
|
|
|
|
|
|
|
|
|
std::wstring scriptFileNameW = _bstr_t(scriptFileName.c_str());
|
|
|
|
|
|
|
|
|
|
pythonArgs[0] = const_cast<wchar_t*>(scriptFileNameW.c_str());
|
|
|
|
|
|
|
|
|
|
for (size_t i = 1; i < opts.args.size(); ++i)
|
|
|
|
|
{
|
|
|
|
|
std::wstring argw = _bstr_t(opts.args[i].c_str());
|
|
|
|
|
pythonArgs[i] = const_cast<wchar_t*>(argw.c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PySys_SetArgv_Py3((int)opts.args.size(), &pythonArgs[0]);
|
|
|
|
|
|
|
|
|
|
FILE* fs = _Py_fopen(scriptFileName.c_str(), "r");
|
|
|
|
|
if ( !fs )
|
|
|
|
|
throw std::invalid_argument("script not found\n");
|
|
|
|
|
|
|
|
|
|
PyObjectRef result = PyRun_File(fs, scriptFileName.c_str(), Py_file_input, globals, globals);
|
|
|
|
|
}
|
|
|
|
|
else
|
|
|
|
|
{
|
|
|
|
|
std::vector<char*> pythonArgs(opts.args.size());
|
|
|
|
|
|
|
|
|
|
pythonArgs[0] = const_cast<char*>(scriptFileName.c_str());
|
|
|
|
|
|
|
|
|
|
for (size_t i = 1; i < opts.args.size(); ++i)
|
|
|
|
|
pythonArgs[i] = const_cast<char*>(opts.args[i].c_str());
|
|
|
|
|
|
|
|
|
|
PySys_SetArgv((int)opts.args.size(), &pythonArgs[0]);
|
|
|
|
|
|
|
|
|
|
PyObjectRef pyfile = PyFile_FromString(pythonArgs[0], "r");
|
|
|
|
|
if (!pyfile)
|
|
|
|
|
throw std::invalid_argument("script not found\n");
|
|
|
|
|
|
|
|
|
|
FILE *fs = PyFile_AsFile(pyfile);
|
|
|
|
|
|
|
|
|
|
PyObjectRef result = PyRun_File(fs, scriptFileName.c_str(), Py_file_input, globals, globals);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
handleException();
|
2016-12-27 05:24:15 +08:00
|
|
|
|
|
|
|
|
|
if ( !opts.global )
|
|
|
|
|
PyDict_Clear(globals);
|
2016-04-27 01:56:16 +08:00
|
|
|
|
}
|
|
|
|
|
catch (std::exception &e)
|
|
|
|
|
{
|
|
|
|
|
CComQIPtr<IDebugControl> control = client;
|
|
|
|
|
|
|
|
|
|
control->ControlledOutput(
|
|
|
|
|
DEBUG_OUTCTL_THIS_CLIENT,
|
|
|
|
|
DEBUG_OUTPUT_ERROR,
|
|
|
|
|
e.what()
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
client->SetOutputMask(oldMask);
|
|
|
|
|
|
|
|
|
|
return S_OK;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
extern "C"
|
|
|
|
|
HRESULT
|
|
|
|
|
CALLBACK
|
|
|
|
|
pip(
|
|
|
|
|
PDEBUG_CLIENT client,
|
|
|
|
|
PCSTR args
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
|
2016-04-28 06:18:55 +08:00
|
|
|
|
try {
|
|
|
|
|
|
2016-10-01 18:12:57 +08:00
|
|
|
|
Options opts(args);
|
2016-04-28 06:18:55 +08:00
|
|
|
|
|
|
|
|
|
int majorVersion = opts.pyMajorVersion;
|
|
|
|
|
int minorVersion = opts.pyMinorVersion;
|
2016-04-27 01:56:16 +08:00
|
|
|
|
|
2016-04-28 06:18:55 +08:00
|
|
|
|
getPythonVersion(majorVersion, minorVersion);
|
|
|
|
|
|
2016-06-22 04:44:29 +08:00
|
|
|
|
AutoInterpreter autoInterpreter(true, majorVersion, minorVersion);
|
2016-04-28 06:18:55 +08:00
|
|
|
|
|
|
|
|
|
PyObjectRef dbgOut = make_pyobject<DbgOut>(client);
|
|
|
|
|
PySys_SetObject("stdout", dbgOut);
|
|
|
|
|
|
|
|
|
|
PyObjectRef dbgErr = make_pyobject<DbgOut>(client);
|
|
|
|
|
PySys_SetObject("stderr", dbgErr);
|
|
|
|
|
|
|
|
|
|
PyObjectRef dbgIn = make_pyobject<DbgIn>(client);
|
|
|
|
|
PySys_SetObject("stdin", dbgIn);
|
|
|
|
|
|
|
|
|
|
PyObjectRef mainName = IsPy3() ? PyUnicode_FromString("__main__") : PyString_FromString("__main__");
|
|
|
|
|
PyObjectRef mainMod = PyImport_Import(mainName);
|
|
|
|
|
PyObjectRef globals = PyObject_GetAttrString(mainMod, "__dict__");
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
std::stringstream sstr;
|
|
|
|
|
sstr << "pip.main([";
|
|
|
|
|
for (auto arg : opts.args)
|
|
|
|
|
sstr << '\'' << arg << '\'' << ',';
|
|
|
|
|
sstr << "])\n";
|
|
|
|
|
|
|
|
|
|
PyObjectRef result;
|
|
|
|
|
result = PyRun_String("import pip\n", Py_file_input, globals, globals);
|
|
|
|
|
result = PyRun_String("pip.logger.consumers = []\n", Py_file_input, globals, globals);
|
|
|
|
|
result = PyRun_String(sstr.str().c_str(), Py_file_input, globals, globals);
|
|
|
|
|
|
|
|
|
|
handleException();
|
|
|
|
|
}
|
|
|
|
|
catch (std::exception &e)
|
|
|
|
|
{
|
|
|
|
|
CComQIPtr<IDebugControl> control = client;
|
|
|
|
|
|
|
|
|
|
control->ControlledOutput(
|
|
|
|
|
DEBUG_OUTCTL_THIS_CLIENT,
|
|
|
|
|
DEBUG_OUTPUT_ERROR,
|
|
|
|
|
e.what()
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return S_OK;
|
2016-04-27 01:56:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void handleException()
|
|
|
|
|
{
|
|
|
|
|
// <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> <20> <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
|
|
|
PyObject *errtype = NULL, *errvalue = NULL, *traceback = NULL;
|
|
|
|
|
|
|
|
|
|
PyErr_Fetch(&errtype, &errvalue, &traceback);
|
|
|
|
|
|
|
|
|
|
PyErr_NormalizeException(&errtype, &errvalue, &traceback);
|
|
|
|
|
|
2016-04-28 06:18:55 +08:00
|
|
|
|
if (errtype && errtype != PyExc_SystemExit())
|
2016-04-27 01:56:16 +08:00
|
|
|
|
{
|
|
|
|
|
PyObjectRef traceback_module = PyImport_ImportModule("traceback");
|
|
|
|
|
|
|
|
|
|
std::stringstream sstr;
|
|
|
|
|
|
|
|
|
|
PyObjectRef format_exception = PyObject_GetAttrString(traceback_module, "format_exception");
|
|
|
|
|
|
|
|
|
|
PyObjectRef args = PyTuple_New(3);
|
|
|
|
|
PyTuple_SetItem(args, 0, errtype ? errtype : Py_None());
|
|
|
|
|
PyTuple_SetItem(args, 1, errvalue ? errvalue : Py_None());
|
|
|
|
|
PyTuple_SetItem(args, 2, traceback ? traceback : Py_None());
|
|
|
|
|
|
|
|
|
|
PyObjectRef lst = PyObject_Call(format_exception, args, NULL);
|
|
|
|
|
|
|
|
|
|
sstr << std::endl << std::endl;
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < PyList_Size(lst); ++i)
|
|
|
|
|
{
|
|
|
|
|
PyObjectBorrowedRef item = PyList_GetItem(lst, i);
|
|
|
|
|
sstr << std::string(convert_from_python(item)) << std::endl;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
throw std::exception(sstr.str().c_str());
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-28 06:18:55 +08:00
|
|
|
|
if (errtype) Py_DecRef(errtype);
|
2016-04-27 01:56:16 +08:00
|
|
|
|
if (errvalue) Py_DecRef(errvalue);
|
|
|
|
|
if (traceback) Py_DecRef(traceback);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
std::string findScript(const std::string &fullFileName)
|
|
|
|
|
{
|
|
|
|
|
if (GetFileAttributesA(fullFileName.c_str()) != INVALID_FILE_ATTRIBUTES)
|
|
|
|
|
return fullFileName;
|
|
|
|
|
|
|
|
|
|
PyObjectBorrowedRef pathLst = PySys_GetObject("path");
|
|
|
|
|
|
|
|
|
|
size_t pathLstSize = PyList_Size(pathLst);
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < pathLstSize; i++)
|
|
|
|
|
{
|
|
|
|
|
char *path = PyString_AsString(PyList_GetItem(pathLst, i));
|
|
|
|
|
|
|
|
|
|
DWORD bufSize = SearchPathA(
|
|
|
|
|
path,
|
|
|
|
|
fullFileName.c_str(),
|
|
|
|
|
NULL,
|
|
|
|
|
0,
|
|
|
|
|
NULL,
|
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
|
|
if (bufSize > 0)
|
|
|
|
|
{
|
|
|
|
|
bufSize += 1;
|
|
|
|
|
std::vector<char> fullFileNameCStr(bufSize);
|
|
|
|
|
char *partFileNameCStr = NULL;
|
|
|
|
|
|
|
|
|
|
bufSize = SearchPathA(
|
|
|
|
|
path,
|
|
|
|
|
fullFileName.c_str(),
|
|
|
|
|
NULL,
|
|
|
|
|
bufSize,
|
|
|
|
|
&fullFileNameCStr[0],
|
|
|
|
|
&partFileNameCStr);
|
|
|
|
|
|
|
|
|
|
DWORD fileAttr = GetFileAttributesA(&fullFileNameCStr[0]);
|
|
|
|
|
|
|
|
|
|
if ((fileAttr & FILE_ATTRIBUTE_DIRECTORY) == 0)
|
|
|
|
|
return std::string(&fullFileNameCStr[0]);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
|
|
|
|
std::string getScriptFileName(const std::string &scriptName)
|
|
|
|
|
{
|
|
|
|
|
std::string scriptFileName = findScript(scriptName);
|
|
|
|
|
|
|
|
|
|
if (scriptFileName.empty())
|
|
|
|
|
{
|
|
|
|
|
std::string scriptNameLow;
|
|
|
|
|
scriptNameLow.resize(scriptName.size());
|
|
|
|
|
std::transform(
|
|
|
|
|
scriptName.begin(),
|
|
|
|
|
scriptName.end(),
|
|
|
|
|
scriptNameLow.begin(),
|
|
|
|
|
::tolower);
|
|
|
|
|
if (scriptNameLow.rfind(".py") != (scriptNameLow.length() - 3))
|
|
|
|
|
scriptFileName = findScript(scriptName + ".py");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return scriptFileName;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2016-06-24 23:05:43 +08:00
|
|
|
|
void getPythonVersion(int& majorVersion, int& minorVersion)
|
2016-04-27 01:56:16 +08:00
|
|
|
|
{
|
2016-06-24 23:05:43 +08:00
|
|
|
|
if (majorVersion == -1 && minorVersion == -1 )
|
|
|
|
|
return getDefaultPythonVersion(majorVersion, minorVersion);
|
|
|
|
|
|
2016-04-27 01:56:16 +08:00
|
|
|
|
std::list<InterpreterDesc> interpreterList = getInstalledInterpreter();
|
|
|
|
|
|
|
|
|
|
bool found = false;
|
|
|
|
|
bool anyMinorVersion = minorVersion == -1;
|
2016-06-23 07:20:06 +08:00
|
|
|
|
bool anyMajorVersion = majorVersion == -1;
|
2016-06-24 23:05:43 +08:00
|
|
|
|
|
2016-06-23 07:20:06 +08:00
|
|
|
|
if (anyMajorVersion)
|
|
|
|
|
{
|
|
|
|
|
for (auto interpret : interpreterList)
|
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
if (2 == interpret.majorVersion &&
|
|
|
|
|
anyMinorVersion ? (minorVersion <= interpret.minorVersion) : (minorVersion == interpret.minorVersion))
|
|
|
|
|
{
|
|
|
|
|
found = true;
|
|
|
|
|
minorVersion = interpret.minorVersion;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (found)
|
|
|
|
|
{
|
|
|
|
|
majorVersion = 2;
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-04-27 01:56:16 +08:00
|
|
|
|
for (auto interpret : interpreterList)
|
|
|
|
|
{
|
2016-06-23 07:20:06 +08:00
|
|
|
|
if (anyMajorVersion ? (majorVersion <= interpret.majorVersion) : (majorVersion==interpret.majorVersion) &&
|
2016-04-27 01:56:16 +08:00
|
|
|
|
anyMinorVersion ? (minorVersion <= interpret.minorVersion) : (minorVersion == interpret.minorVersion))
|
|
|
|
|
{
|
|
|
|
|
found = true;
|
|
|
|
|
minorVersion = interpret.minorVersion;
|
2016-06-23 07:20:06 +08:00
|
|
|
|
majorVersion = interpret.majorVersion;
|
2016-04-27 01:56:16 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!found)
|
|
|
|
|
throw std::exception("failed to find python interpreter\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
|
|
2016-06-24 23:05:43 +08:00
|
|
|
|
void getDefaultPythonVersion(int& majorVersion, int& minorVersion)
|
2016-04-27 01:56:16 +08:00
|
|
|
|
{
|
2016-06-24 23:05:43 +08:00
|
|
|
|
std::list<InterpreterDesc> interpreterList = getInstalledInterpreter();
|
2016-04-27 01:56:16 +08:00
|
|
|
|
|
2016-06-24 23:05:43 +08:00
|
|
|
|
bool found = false;
|
|
|
|
|
majorVersion = -1;
|
|
|
|
|
minorVersion = -1;
|
|
|
|
|
|
|
|
|
|
for (auto interpret : interpreterList)
|
2016-04-27 01:56:16 +08:00
|
|
|
|
{
|
2016-06-24 23:05:43 +08:00
|
|
|
|
if (2 == interpret.majorVersion && 7 == interpret.minorVersion)
|
2016-04-27 01:56:16 +08:00
|
|
|
|
{
|
2016-06-24 23:05:43 +08:00
|
|
|
|
majorVersion = 2;
|
|
|
|
|
minorVersion = 7;
|
2016-04-27 01:56:16 +08:00
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-24 23:05:43 +08:00
|
|
|
|
for (auto interpret : interpreterList)
|
2016-04-27 01:56:16 +08:00
|
|
|
|
{
|
2016-06-24 23:05:43 +08:00
|
|
|
|
if (3 == interpret.majorVersion && 5 == interpret.minorVersion)
|
2016-04-27 01:56:16 +08:00
|
|
|
|
{
|
2016-06-24 23:05:43 +08:00
|
|
|
|
majorVersion = 3;
|
|
|
|
|
minorVersion = 5;
|
|
|
|
|
return;
|
2016-04-27 01:56:16 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-24 23:05:43 +08:00
|
|
|
|
for (auto interpret : interpreterList)
|
2016-04-27 01:56:16 +08:00
|
|
|
|
{
|
2016-06-24 23:05:43 +08:00
|
|
|
|
if (2 == interpret.majorVersion &&
|
|
|
|
|
minorVersion <= interpret.minorVersion )
|
2016-04-27 01:56:16 +08:00
|
|
|
|
{
|
2016-06-24 23:05:43 +08:00
|
|
|
|
found = true;
|
|
|
|
|
majorVersion = 2;
|
|
|
|
|
minorVersion = interpret.minorVersion;
|
2016-04-27 01:56:16 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-24 23:05:43 +08:00
|
|
|
|
if (found)
|
|
|
|
|
return;
|
2016-04-27 01:56:16 +08:00
|
|
|
|
|
2016-06-24 23:05:43 +08:00
|
|
|
|
for (auto interpret : interpreterList)
|
2016-04-27 01:56:16 +08:00
|
|
|
|
{
|
2016-06-24 23:05:43 +08:00
|
|
|
|
if (3 == interpret.majorVersion &&
|
|
|
|
|
minorVersion <= interpret.minorVersion )
|
2016-04-27 01:56:16 +08:00
|
|
|
|
{
|
2016-06-24 23:05:43 +08:00
|
|
|
|
found = true;
|
|
|
|
|
majorVersion = 3;
|
|
|
|
|
minorVersion = interpret.minorVersion;
|
2016-04-27 01:56:16 +08:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2016-06-24 23:05:43 +08:00
|
|
|
|
if (found)
|
|
|
|
|
return;
|
2016-04-27 01:56:16 +08:00
|
|
|
|
|
2016-06-24 23:05:43 +08:00
|
|
|
|
if (!found)
|
|
|
|
|
throw std::exception("failed to find python interpreter\n");
|
2016-04-27 01:56:16 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|