py_settrace.hpp
1 #ifndef _PY_SETTRACE_HPP_ 2 #define _PY_SETTRACE_HPP_ 3 4 #include "ref_utils.hpp" 5 #include "py_utils.hpp" 6 #include "python.h" 7 #include "py_custom_pyeval_settrace.hpp" 8 #include <unordered_set> 9 10 11 #ifdef _WIN32 12 13 typedef HMODULE MODULE_TYPE; 14 #else // LINUX ----------------------------------------------------------------- 15 16 typedef void* MODULE_TYPE; 17 typedef ssize_t SSIZE_T; 18 typedef unsigned int DWORD; 19 20 #endif 21 22 DWORD GetPythonThreadId(PythonVersion version, PyThreadState* curThread) { 23 DWORD threadId = 0; 24 if (PyThreadState_25_27::IsFor(version)) { 25 threadId = (DWORD)((PyThreadState_25_27*)curThread)->thread_id; 26 } else if (PyThreadState_30_33::IsFor(version)) { 27 threadId = (DWORD)((PyThreadState_30_33*)curThread)->thread_id; 28 } else if (PyThreadState_34_36::IsFor(version)) { 29 threadId = (DWORD)((PyThreadState_34_36*)curThread)->thread_id; 30 } else if (PyThreadState_37_38::IsFor(version)) { 31 threadId = (DWORD)((PyThreadState_37_38*)curThread)->thread_id; 32 } else if (PyThreadState_39::IsFor(version)) { 33 threadId = (DWORD)((PyThreadState_39*)curThread)->thread_id; 34 } else if (PyThreadState_310::IsFor(version)) { 35 threadId = (DWORD)((PyThreadState_310*)curThread)->thread_id; 36 } else if (PyThreadState_311::IsFor(version)) { 37 threadId = (DWORD)((PyThreadState_311*)curThread)->thread_id; 38 } 39 return threadId; 40 } 41 42 43 /** 44 * This function may be called to set a tracing function to existing python threads. 45 */ 46 int InternalSetSysTraceFunc( 47 MODULE_TYPE module, 48 bool isDebug, 49 bool showDebugInfo, 50 PyObjectHolder* traceFunc, 51 PyObjectHolder* setTraceFunc, 52 unsigned int threadId, 53 PyObjectHolder* pyNone) 54 { 55 56 if(showDebugInfo){ 57 PRINT("InternalSetSysTraceFunc started."); 58 } 59 60 DEFINE_PROC(isInit, Py_IsInitialized*, "Py_IsInitialized", 100); 61 if (!isInit()) { 62 PRINT("Py_IsInitialized returned false."); 63 return 110; 64 } 65 66 auto version = GetPythonVersion(module); 67 68 // found initialized Python runtime, gather and check the APIs we need. 69 70 DEFINE_PROC(interpHead, PyInterpreterState_Head*, "PyInterpreterState_Head", 120); 71 DEFINE_PROC(gilEnsure, PyGILState_Ensure*, "PyGILState_Ensure", 130); 72 DEFINE_PROC(gilRelease, PyGILState_Release*, "PyGILState_Release", 140); 73 DEFINE_PROC(threadHead, PyInterpreterState_ThreadHead*, "PyInterpreterState_ThreadHead", 150); 74 DEFINE_PROC(threadNext, PyThreadState_Next*, "PyThreadState_Next", 160); 75 DEFINE_PROC(threadSwap, PyThreadState_Swap*, "PyThreadState_Swap", 170); 76 DEFINE_PROC(call, PyObject_CallFunctionObjArgs*, "PyObject_CallFunctionObjArgs", 180); 77 78 PyInt_FromLong* intFromLong; 79 80 if (version >= PythonVersion_30) { 81 DEFINE_PROC(intFromLongPy3, PyInt_FromLong*, "PyLong_FromLong", 190); 82 intFromLong = intFromLongPy3; 83 } else { 84 DEFINE_PROC(intFromLongPy2, PyInt_FromLong*, "PyInt_FromLong", 200); 85 intFromLong = intFromLongPy2; 86 } 87 88 DEFINE_PROC(pyGetAttr, PyObject_GetAttrString*, "PyObject_GetAttrString", 250); 89 DEFINE_PROC(pyHasAttr, PyObject_HasAttrString*, "PyObject_HasAttrString", 260); 90 DEFINE_PROC_NO_CHECK(PyCFrame_Type, PyTypeObject*, "PyCFrame_Type", 300); // optional 91 92 DEFINE_PROC_NO_CHECK(curPythonThread, PyThreadState**, "_PyThreadState_Current", 310); // optional 93 DEFINE_PROC_NO_CHECK(getPythonThread, _PyThreadState_UncheckedGet*, "_PyThreadState_UncheckedGet", 320); // optional 94 95 if (curPythonThread == nullptr && getPythonThread == nullptr) { 96 // we're missing some APIs, we cannot attach. 97 PRINT("Error, missing Python threading API!!"); 98 return 330; 99 } 100 101 auto head = interpHead(); 102 if (head == nullptr) { 103 // this interpreter is loaded but not initialized. 104 PRINT("Interpreter not initialized!"); 105 return 340; 106 } 107 108 GilHolder gilLock(gilEnsure, gilRelease); // acquire and hold the GIL until done... 109 110 int retVal = 0; 111 // find what index is holding onto the thread state... 112 auto curPyThread = getPythonThread ? getPythonThread() : *curPythonThread; 113 114 if(curPyThread == nullptr){ 115 PRINT("Getting the current python thread returned nullptr."); 116 return 345; 117 } 118 119 120 // We do what PyEval_SetTrace does, but for any target thread. 121 PyUnicode_InternFromString* pyUnicode_InternFromString; 122 if (version >= PythonVersion_30) { 123 DEFINE_PROC(unicodeFromString, PyUnicode_InternFromString*, "PyUnicode_InternFromString", 520); 124 pyUnicode_InternFromString = unicodeFromString; 125 } else { 126 DEFINE_PROC(stringFromString, PyUnicode_InternFromString*, "PyString_InternFromString", 525); 127 pyUnicode_InternFromString = stringFromString; 128 } 129 130 DEFINE_PROC_NO_CHECK(pyObject_FastCallDict, _PyObject_FastCallDict*, "_PyObject_FastCallDict", 530); 131 DEFINE_PROC(pyTuple_New, PyTuple_New*, "PyTuple_New", 531); 132 DEFINE_PROC(pyEval_CallObjectWithKeywords, PyEval_CallObjectWithKeywords*, "PyEval_CallObjectWithKeywords", 532); 133 134 if(pyObject_FastCallDict == nullptr) { 135 DEFINE_PROC_NO_CHECK(pyObject_FastCallDict, _PyObject_FastCallDict*, "PyObject_VectorcallDict", 533); 136 } 137 138 if(pyObject_FastCallDict == nullptr) { 139 // we have to use PyObject_FastCallDictCustom for older versions of CPython (pre 3.7). 140 pyObject_FastCallDict = reinterpret_cast<_PyObject_FastCallDict*>(&PyObject_FastCallDictCustom); 141 } 142 143 144 DEFINE_PROC(pyTraceBack_Here, PyTraceBack_Here*, "PyTraceBack_Here", 540); 145 DEFINE_PROC(pyEval_SetTrace, PyEval_SetTrace*, "PyEval_SetTrace", 550); 146 147 // These are defined mostly for printing info while debugging, so, if they're not there, don't bother reporting. 148 DEFINE_PROC_NO_CHECK(pyObject_Repr, PyObject_Repr*, "PyObject_Repr", 551); 149 DEFINE_PROC_NO_CHECK(pyUnicode_AsUTF8, PyUnicode_AsUTF8*, "PyUnicode_AsUTF8", 552); 150 151 152 bool found = false; 153 for (PyThreadState* curThread = threadHead(head); curThread != nullptr; curThread = threadNext(curThread)) { 154 if (GetPythonThreadId(version, curThread) != threadId) { 155 continue; 156 } 157 found = true; 158 159 if(showDebugInfo){ 160 printf("setting trace for thread: %d\n", threadId); 161 } 162 163 if(!InternalIsTraceInitialized()) 164 { 165 InternalInitializeCustomPyEvalSetTrace *internalInitializeCustomPyEvalSetTrace = new InternalInitializeCustomPyEvalSetTrace(); 166 167 IncRef(pyNone->ToPython()); 168 internalInitializeCustomPyEvalSetTrace->pyNone = pyNone->ToPython(); 169 170 internalInitializeCustomPyEvalSetTrace->pyUnicode_InternFromString = pyUnicode_InternFromString; 171 internalInitializeCustomPyEvalSetTrace->pyObject_FastCallDict = pyObject_FastCallDict; 172 internalInitializeCustomPyEvalSetTrace->isDebug = isDebug; 173 internalInitializeCustomPyEvalSetTrace->pyTraceBack_Here = pyTraceBack_Here; 174 internalInitializeCustomPyEvalSetTrace->pyEval_SetTrace = pyEval_SetTrace; 175 internalInitializeCustomPyEvalSetTrace->pyTuple_New = pyTuple_New; 176 internalInitializeCustomPyEvalSetTrace->pyEval_CallObjectWithKeywords = pyEval_CallObjectWithKeywords; 177 internalInitializeCustomPyEvalSetTrace->pyObject_Repr = pyObject_Repr; 178 internalInitializeCustomPyEvalSetTrace->pyUnicode_AsUTF8 = pyUnicode_AsUTF8; 179 180 InternalTraceInit(internalInitializeCustomPyEvalSetTrace); 181 } 182 InternalPySetTrace(curThread, traceFunc, isDebug, version); 183 break; 184 } 185 if(!found) { 186 retVal = 501; 187 } 188 189 return retVal; 190 191 } 192 193 #endif // _PY_SETTRACE_HPP_