From 16ebf54df7e6a7de5469c06fe173b771be3e1a52 Mon Sep 17 00:00:00 2001 From: "SND\\ussrhero_cp" Date: Sun, 22 Mar 2015 17:29:38 +0000 Subject: [PATCH] [0.3.x] added : pykd.dll ( bootstrapper for windbg ) git-svn-id: https://pykd.svn.codeplex.com/svn@90068 9b283d60-5439-405e-af05-b73fd8c4d996 --- pykd-0.3-2013.sln | 30 ++ pykd/pykd_vc120.vcxproj | 4 + pykd_bootstrapper/dllmain.cpp | 19 + pykd_bootstrapper/export.def | 4 + .../packages.pykd_bootstrapper_vc120.config | 6 + .../pykd_bootstrapper_vc120.vcxproj | 220 +++++++++ .../pykd_bootstrapper_vc120.vcxproj.filters | 130 +++++ pykd_bootstrapper/stdafx.cpp | 8 + pykd_bootstrapper/stdafx.h | 16 + pykd_bootstrapper/targetver.h | 8 + pykd_bootstrapper/windbgext.cpp | 459 ++++++++++++++++++ 11 files changed, 904 insertions(+) create mode 100644 pykd_bootstrapper/dllmain.cpp create mode 100644 pykd_bootstrapper/export.def create mode 100644 pykd_bootstrapper/packages.pykd_bootstrapper_vc120.config create mode 100644 pykd_bootstrapper/pykd_bootstrapper_vc120.vcxproj create mode 100644 pykd_bootstrapper/pykd_bootstrapper_vc120.vcxproj.filters create mode 100644 pykd_bootstrapper/stdafx.cpp create mode 100644 pykd_bootstrapper/stdafx.h create mode 100644 pykd_bootstrapper/targetver.h create mode 100644 pykd_bootstrapper/windbgext.cpp diff --git a/pykd-0.3-2013.sln b/pykd-0.3-2013.sln index d6975e3..b9e471d 100644 --- a/pykd-0.3-2013.sln +++ b/pykd-0.3-2013.sln @@ -45,6 +45,8 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{D1F122 EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "targetapp", "kdlibcpp\tests\targetapp\targetapp_vc120.vcxproj", "{0E4CC688-F2F5-499F-9C07-0F2CAEE0D3EF}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pykd_bootstrapper", "pykd_bootstrapper\pykd_bootstrapper_vc120.vcxproj", "{CA0252CE-EF81-4DD8-A96F-A0E0E3644B7B}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug_2.7|Any CPU = Debug_2.7|Any CPU @@ -222,6 +224,34 @@ Global {0E4CC688-F2F5-499F-9C07-0F2CAEE0D3EF}.Release|Win32.Build.0 = Release|Win32 {0E4CC688-F2F5-499F-9C07-0F2CAEE0D3EF}.Release|x64.ActiveCfg = Release|x64 {0E4CC688-F2F5-499F-9C07-0F2CAEE0D3EF}.Release|x64.Build.0 = Release|x64 + {CA0252CE-EF81-4DD8-A96F-A0E0E3644B7B}.Debug_2.7|Any CPU.ActiveCfg = Debug_2.7|Win32 + {CA0252CE-EF81-4DD8-A96F-A0E0E3644B7B}.Debug_2.7|Mixed Platforms.ActiveCfg = Debug_2.7|Win32 + {CA0252CE-EF81-4DD8-A96F-A0E0E3644B7B}.Debug_2.7|Mixed Platforms.Build.0 = Debug_2.7|Win32 + {CA0252CE-EF81-4DD8-A96F-A0E0E3644B7B}.Debug_2.7|Win32.ActiveCfg = Debug_2.7|Win32 + {CA0252CE-EF81-4DD8-A96F-A0E0E3644B7B}.Debug_2.7|Win32.Build.0 = Debug_2.7|Win32 + {CA0252CE-EF81-4DD8-A96F-A0E0E3644B7B}.Debug_2.7|x64.ActiveCfg = Debug_2.7|x64 + {CA0252CE-EF81-4DD8-A96F-A0E0E3644B7B}.Debug_2.7|x64.Build.0 = Debug_2.7|x64 + {CA0252CE-EF81-4DD8-A96F-A0E0E3644B7B}.Debug|Any CPU.ActiveCfg = Debug_2.7|Win32 + {CA0252CE-EF81-4DD8-A96F-A0E0E3644B7B}.Debug|Mixed Platforms.ActiveCfg = Debug_2.7|Win32 + {CA0252CE-EF81-4DD8-A96F-A0E0E3644B7B}.Debug|Mixed Platforms.Build.0 = Debug_2.7|Win32 + {CA0252CE-EF81-4DD8-A96F-A0E0E3644B7B}.Debug|Win32.ActiveCfg = Debug_2.7|Win32 + {CA0252CE-EF81-4DD8-A96F-A0E0E3644B7B}.Debug|Win32.Build.0 = Debug_2.7|Win32 + {CA0252CE-EF81-4DD8-A96F-A0E0E3644B7B}.Debug|x64.ActiveCfg = Debug_2.7|x64 + {CA0252CE-EF81-4DD8-A96F-A0E0E3644B7B}.Debug|x64.Build.0 = Debug_2.7|x64 + {CA0252CE-EF81-4DD8-A96F-A0E0E3644B7B}.Release_2.7|Any CPU.ActiveCfg = Release_2.7|Win32 + {CA0252CE-EF81-4DD8-A96F-A0E0E3644B7B}.Release_2.7|Mixed Platforms.ActiveCfg = Release_2.7|Win32 + {CA0252CE-EF81-4DD8-A96F-A0E0E3644B7B}.Release_2.7|Mixed Platforms.Build.0 = Release_2.7|Win32 + {CA0252CE-EF81-4DD8-A96F-A0E0E3644B7B}.Release_2.7|Win32.ActiveCfg = Release_2.7|Win32 + {CA0252CE-EF81-4DD8-A96F-A0E0E3644B7B}.Release_2.7|Win32.Build.0 = Release_2.7|Win32 + {CA0252CE-EF81-4DD8-A96F-A0E0E3644B7B}.Release_2.7|x64.ActiveCfg = Debug_2.7|x64 + {CA0252CE-EF81-4DD8-A96F-A0E0E3644B7B}.Release_2.7|x64.Build.0 = Debug_2.7|x64 + {CA0252CE-EF81-4DD8-A96F-A0E0E3644B7B}.Release|Any CPU.ActiveCfg = Release_2.7|Win32 + {CA0252CE-EF81-4DD8-A96F-A0E0E3644B7B}.Release|Mixed Platforms.ActiveCfg = Release_2.7|Win32 + {CA0252CE-EF81-4DD8-A96F-A0E0E3644B7B}.Release|Mixed Platforms.Build.0 = Release_2.7|Win32 + {CA0252CE-EF81-4DD8-A96F-A0E0E3644B7B}.Release|Win32.ActiveCfg = Release_2.7|Win32 + {CA0252CE-EF81-4DD8-A96F-A0E0E3644B7B}.Release|Win32.Build.0 = Release_2.7|Win32 + {CA0252CE-EF81-4DD8-A96F-A0E0E3644B7B}.Release|x64.ActiveCfg = Release_2.7|x64 + {CA0252CE-EF81-4DD8-A96F-A0E0E3644B7B}.Release|x64.Build.0 = Release_2.7|x64 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/pykd/pykd_vc120.vcxproj b/pykd/pykd_vc120.vcxproj index c94a038..75d2284 100644 --- a/pykd/pykd_vc120.vcxproj +++ b/pykd/pykd_vc120.vcxproj @@ -75,19 +75,23 @@ true .pyd true + $(ProjectName) true .pyd true + $(ProjectName) false .pyd + $(ProjectName) false .pyd + $(ProjectName) diff --git a/pykd_bootstrapper/dllmain.cpp b/pykd_bootstrapper/dllmain.cpp new file mode 100644 index 0000000..8a4edd3 --- /dev/null +++ b/pykd_bootstrapper/dllmain.cpp @@ -0,0 +1,19 @@ +// dllmain.cpp : Defines the entry point for the DLL application. +#include "stdafx.h" + +BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + diff --git a/pykd_bootstrapper/export.def b/pykd_bootstrapper/export.def new file mode 100644 index 0000000..49bb1e9 --- /dev/null +++ b/pykd_bootstrapper/export.def @@ -0,0 +1,4 @@ +EXPORTS + DebugExtensionInitialize + DebugExtensionUninitialize + py diff --git a/pykd_bootstrapper/packages.pykd_bootstrapper_vc120.config b/pykd_bootstrapper/packages.pykd_bootstrapper_vc120.config new file mode 100644 index 0000000..26eab34 --- /dev/null +++ b/pykd_bootstrapper/packages.pykd_bootstrapper_vc120.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/pykd_bootstrapper/pykd_bootstrapper_vc120.vcxproj b/pykd_bootstrapper/pykd_bootstrapper_vc120.vcxproj new file mode 100644 index 0000000..49e44c1 --- /dev/null +++ b/pykd_bootstrapper/pykd_bootstrapper_vc120.vcxproj @@ -0,0 +1,220 @@ + + + + + Debug_2.7 + Win32 + + + Debug_2.7 + x64 + + + Release_2.7 + Win32 + + + Release_2.7 + x64 + + + + {CA0252CE-EF81-4DD8-A96F-A0E0E3644B7B} + Win32Proj + pykd_bootstrapper + pykd_ext + ..\ + true + + + + DynamicLibrary + true + v120 + Unicode + + + DynamicLibrary + true + v120 + Unicode + + + DynamicLibrary + false + v120 + true + Unicode + + + DynamicLibrary + false + v120 + true + Unicode + + + + + + + + + + + + + + + + + + 7f4aed3e + + + true + pykd + + + true + pykd + + + false + pykd + + + false + pykd + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;PYKD_BOOTSTRAPPER_EXPORTS;%(PreprocessorDefinitions) + true + $(ProjectDir)..\kdlibcpp\include; + + + Windows + true + export.def + $(OutDir)$(TargetName)$(TargetExt) + + + + + Use + Level3 + Disabled + WIN32;_DEBUG;_WINDOWS;_USRDLL;PYKD_BOOTSTRAPPER_EXPORTS;%(PreprocessorDefinitions) + true + $(ProjectDir)..\kdlibcpp\include; + + + Windows + true + export.def + $(OutDir)$(TargetName)$(TargetExt) + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;PYKD_BOOTSTRAPPER_EXPORTS;%(PreprocessorDefinitions) + true + $(ProjectDir)..\kdlibcpp\include; + MultiThreaded + + + Windows + true + true + true + export.def + $(OutDir)$(TargetName)$(TargetExt) + + + + + Level3 + Use + MaxSpeed + true + true + WIN32;NDEBUG;_WINDOWS;_USRDLL;PYKD_BOOTSTRAPPER_EXPORTS;%(PreprocessorDefinitions) + true + $(ProjectDir)..\kdlibcpp\include; + MultiThreaded + + + Windows + true + true + true + export.def + $(OutDir)$(TargetName)$(TargetExt) + + + + + + + + + + + + false + false + + + + + false + false + + + + + + + Create + Create + Create + Create + + + + + + + + + + + {3e9c538f-f060-4e86-ab7d-d44439615b63} + + + + + + + + + + + + This project references NuGet package(s) that are missing on this computer. Enable NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. + + + + + + + \ No newline at end of file diff --git a/pykd_bootstrapper/pykd_bootstrapper_vc120.vcxproj.filters b/pykd_bootstrapper/pykd_bootstrapper_vc120.vcxproj.filters new file mode 100644 index 0000000..f1936f5 --- /dev/null +++ b/pykd_bootstrapper/pykd_bootstrapper_vc120.vcxproj.filters @@ -0,0 +1,130 @@ + + + + + {4FC737F1-C7A5-4376-A066-2A32D752A2FF} + cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx + + + {93995380-89BD-4b04-88EB-625FBE52EBFB} + h;hh;hpp;hxx;hm;inl;inc;xsd + + + {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} + rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms + + + + + + + + Header Files + + + Header Files + + + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + Source Files + + + + + Source Files + + + + + \ No newline at end of file diff --git a/pykd_bootstrapper/stdafx.cpp b/pykd_bootstrapper/stdafx.cpp new file mode 100644 index 0000000..75c83a9 --- /dev/null +++ b/pykd_bootstrapper/stdafx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// pykd_bootstrapper.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/pykd_bootstrapper/stdafx.h b/pykd_bootstrapper/stdafx.h new file mode 100644 index 0000000..677e68a --- /dev/null +++ b/pykd_bootstrapper/stdafx.h @@ -0,0 +1,16 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#pragma once + +#include "targetver.h" + +#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers +// Windows Header Files: +#include + + + +// TODO: reference additional headers your program requires here diff --git a/pykd_bootstrapper/targetver.h b/pykd_bootstrapper/targetver.h new file mode 100644 index 0000000..90e767b --- /dev/null +++ b/pykd_bootstrapper/targetver.h @@ -0,0 +1,8 @@ +#pragma once + +// Including SDKDDKVer.h defines the highest available Windows platform. + +// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and +// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. + +#include diff --git a/pykd_bootstrapper/windbgext.cpp b/pykd_bootstrapper/windbgext.cpp new file mode 100644 index 0000000..e5c91e9 --- /dev/null +++ b/pykd_bootstrapper/windbgext.cpp @@ -0,0 +1,459 @@ +#include "stdafx.h" + +#include + +namespace python = boost::python; + +#include "kdlib/windbg.h" + +using namespace kdlib; + +/////////////////////////////////////////////////////////////////////////////// + +class PykdBootsTrapper: public windbg::WindbgExtension +{ +public: + + KDLIB_EXT_COMMAND_METHOD(py); + + virtual void setUp(); + + virtual void tearDown(); + +private: + + void startConsole(); + + void printUsage(); + + void printException(); + + std::string getScriptFileName(const std::string &scriptName); + + std::string findScript(const std::string &fullFileName); + + PyThreadState *m_pyState; + +}; + +/////////////////////////////////////////////////////////////////////////////// + +class AutoRestorePyState +{ +public: + + AutoRestorePyState() + { + m_state = PyEval_SaveThread(); + } + + explicit AutoRestorePyState(PyThreadState **state) + { + *state = PyEval_SaveThread(); + m_state = *state; + } + + ~AutoRestorePyState() + { + PyEval_RestoreThread(m_state); + } + +private: + + PyThreadState* m_state; +}; + +/////////////////////////////////////////////////////////////////////////////// + +class DbgOut : public windbg::WindbgOut +{ +public: + + virtual void write(const std::wstring& str) { + AutoRestorePyState pystate; + windbg::WindbgOut::write(str); + } + + virtual void writedml(const std::wstring& str) { + AutoRestorePyState pystate; + windbg::WindbgOut::writedml(str); + } + + void flush() { + } + + std::wstring encoding() { + return L"ascii"; + } +}; + +/////////////////////////////////////////////////////////////////////////////// + +class DbgIn : public windbg::WindbgIn +{ +public: + + std::wstring readline() { + AutoRestorePyState pystate; + return kdlib::windbg::WindbgIn::readline(); + } + + std::wstring encoding() { + return L"ascii"; + } +}; + +/////////////////////////////////////////////////////////////////////////////// + +class InterruptWatch : public windbg::InterruptWatch +{ + virtual bool onInterrupt() + { + 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 true; + } + + static int quit(void *context) + { + HANDLE quitEvent = (HANDLE)context; + kdlib::eprintln(L"User Interrupt: CTRL+BREAK"); + PyErr_SetString(PyExc_SystemExit, "CTRL+BREAK"); + SetEvent(quitEvent); + return -1; + } +}; + +/////////////////////////////////////////////////////////////////////////////// + +KDLIB_WINDBG_EXTENSION_INIT(PykdBootsTrapper); + +KDLIB_EXT_COMMAND_METHOD_IMPL(PykdBootsTrapper, py) +{ + ArgsList args = getArgs(); + + bool global = false; + bool local = false; + bool clean = false; + + ArgsList::iterator foundArg; + + if (!args.empty()) + { + if (args[0] == "-h" || args[0] == "--help") + { + printUsage(); + return; + } + else + if (args[0] == "-g" || args[0] == "--global") + { + global = true; + args.erase(args.begin()); + } + else + if (args[0] == "-l" || args[0] == "--local") + { + local = true; + args.erase(args.begin()); + } + } + + PyThreadState *localState = NULL; + PyThreadState *globalState = NULL; + + PyEval_RestoreThread(m_pyState); + + std::string scriptFileName; + if (args.size() > 0) + { + scriptFileName = getScriptFileName(args[0]); + + if (scriptFileName.empty()) + { + kdlib::eprintln(L"script file not found"); + return; + } + + global = !(global || local) ? false : global; //set local by default + } + else + { + global = !(global || local) ? true : global; //set global by default + } + + if (!global) + { + globalState = PyThreadState_Swap(NULL); + + Py_NewInterpreter(); + + localState = PyThreadState_Get(); + + python::object sys = python::import("sys"); + + sys.attr("stdout") = python::object(::DbgOut()); + sys.attr("stderr") = python::object(::DbgOut()); + sys.attr("stdin") = python::object(::DbgIn()); + } + + if (args.size() == 0) + { + startConsole(); + } + else + { + std::string scriptFileName = getScriptFileName(args[0]); + + // óñòàíàâèëèâàåì ïèòîíîâñêèå àðãóìåíòû + char **pythonArgs = new char*[args.size()]; + + pythonArgs[0] = const_cast(scriptFileName.c_str()); + + for (size_t i = 1; i < args.size(); ++i) + pythonArgs[i] = const_cast(args[i].c_str()); + + PySys_SetArgv((int)args.size(), pythonArgs); + + delete[] pythonArgs; + + // ïîëó÷àåì äîñòïó ê ãëîáàëüíîìó ìàïó ( íóæåí äëÿ âûçîâà exec_file ) + python::object main = python::import("__main__"); + + python::object global(main.attr("__dict__")); + + try { + InterruptWatch interruptWatch; + + python::exec_file(scriptFileName.c_str(), global); + } + catch (python::error_already_set const &) + { + printException(); + } + } + + if (!global) + { + PyInterpreterState *interpreter = localState->interp; + + while (interpreter->tstate_head != NULL) + { + PyThreadState *threadState = (PyThreadState*)(interpreter->tstate_head); + + PyThreadState_Clear(threadState); + + PyThreadState_Swap(NULL); + + PyThreadState_Delete(threadState); + } + + PyInterpreterState_Clear(interpreter); + + PyInterpreterState_Delete(interpreter); + + PyThreadState_Swap(globalState); + } + + m_pyState = PyEval_SaveThread(); +} + +/////////////////////////////////////////////////////////////////////////////// + +void PykdBootsTrapper::setUp() +{ + WindbgExtension::setUp(); + + PyEval_InitThreads(); + + Py_Initialize(); + + python::object main = boost::python::import("__main__"); + + python::object main_namespace = main.attr("__dict__"); + + python::object pykd = python::import("pykd"); + + // äåëàåì àíàëîã from pykd import * + python::dict pykd_namespace(pykd.attr("__dict__")); + + python::list iterkeys(pykd_namespace.iterkeys()); + + for (int i = 0; i < boost::python::len(iterkeys); i++) + { + std::string key = boost::python::extract(iterkeys[i]); + + main_namespace[key] = pykd_namespace[key]; + } + + // Python debug output console helper classes + python::class_<::DbgOut>("dout", "dout", python::no_init) + .def("write", &::DbgOut::write) + .def("flush", &::DbgOut::flush) + .add_property("encoding", &::DbgOut::encoding); + + python::class_<::DbgIn>("din", "din", python::no_init) + .def("readline", &::DbgIn::readline) + .add_property("encoding", &::DbgIn::encoding); + + python::object sys = python::import("sys"); + + sys.attr("stdout") = python::object(::DbgOut()); + sys.attr("stderr") = python::object(::DbgOut()); + sys.attr("stdin") = python::object(::DbgIn()); + + m_pyState = PyEval_SaveThread(); +} + +/////////////////////////////////////////////////////////////////////////////// + +void PykdBootsTrapper::tearDown() +{ + PyEval_RestoreThread(m_pyState); + + Py_Finalize(); + + WindbgExtension::tearDown(); +} + +/////////////////////////////////////////////////////////////////////////////// + +void PykdBootsTrapper::startConsole() +{ + + // ïîëó÷àåì äîñòóï ê ãëîáàëüíîìó ìàïó ( íóæåí äëÿ âûçîâà exec_file ) + python::object main = python::import("__main__"); + + python::object global(main.attr("__dict__")); + + try { + InterruptWatch interruptWatch; + + python::exec("__import__('code').InteractiveConsole(__import__('__main__').__dict__).interact()\n", global); + } + catch (python::error_already_set const &) + { + printException(); + } +} + +/////////////////////////////////////////////////////////////////////////////// + +void PykdBootsTrapper::printUsage() +{ + kdlib::dprintln(L"usage: !py [options] [file]"); + kdlib::dprintln(L"Options:"); + kdlib::dprintln(L"-g --global : run code in the common namespace"); + kdlib::dprintln(L"-l --local : run code in the isolate namespace"); +} + +////////////////////////////////////////////////////////////////////////////// + +std::string PykdBootsTrapper::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; +} + +/////////////////////////////////////////////////////////////////////////////// + +std::string PykdBootsTrapper::findScript(const std::string &fullFileName) +{ + if (GetFileAttributesA(fullFileName.c_str()) != INVALID_FILE_ATTRIBUTES) + return fullFileName; + + python::object sys = python::import("sys"); + + python::list pathList(sys.attr("path")); + + python::ssize_t n = python::len(pathList); + + for (python::ssize_t i = 0; i < n; i++) + { + std::string path = boost::python::extract(pathList[i]); + + DWORD bufSize = SearchPathA( + path.c_str(), + fullFileName.c_str(), + NULL, + 0, + NULL, + NULL); + + if (bufSize > 0) + { + bufSize += 1; + std::vector fullFileNameCStr(bufSize); + char *partFileNameCStr = NULL; + + bufSize = SearchPathA( + path.c_str(), + fullFileName.c_str(), + NULL, + bufSize, + &fullFileNameCStr[0], + &partFileNameCStr); + + if (bufSize > 0) + { + return std::string(&fullFileNameCStr[0]); + } + } + } + + return ""; +} + +/////////////////////////////////////////////////////////////////////////////// + + +void PykdBootsTrapper::printException() +{ + // îøèáêà â ñêðèïòå + PyObject *errtype = NULL, *errvalue = NULL, *traceback = NULL; + + PyErr_Fetch(&errtype, &errvalue, &traceback); + + PyErr_NormalizeException(&errtype, &errvalue, &traceback); + + if (errtype == PyExc_SystemExit) + return; + + python::object tracebackModule = python::import("traceback"); + + std::wstringstream sstr; + + python::object lst = + python::object(tracebackModule.attr("format_exception"))( + python::handle<>(errtype), + python::handle<>(python::allow_null(errvalue)), + python::handle<>(python::allow_null(traceback))); + + sstr << std::endl << std::endl; + + for (long i = 0; i < python::len(lst); ++i) + sstr << std::wstring(python::extract(lst[i])) << std::endl; + + kdlib::eprintln(sstr.str()); +} + +/////////////////////////////////////////////////////////////////////////////// +