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
GetPythonThreadId(PythonVersion version,PyThreadState * curThread)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 }
35 return threadId;
36 }
37
38
39 /**
40 * This function may be called to set a tracing function to existing python threads.
41 */
InternalSetSysTraceFunc(MODULE_TYPE module,bool isDebug,bool showDebugInfo,PyObjectHolder * traceFunc,PyObjectHolder * setTraceFunc,unsigned int threadId,PyObjectHolder * pyNone)42 int InternalSetSysTraceFunc(
43 MODULE_TYPE module,
44 bool isDebug,
45 bool showDebugInfo,
46 PyObjectHolder* traceFunc,
47 PyObjectHolder* setTraceFunc,
48 unsigned int threadId,
49 PyObjectHolder* pyNone)
50 {
51
52 if(showDebugInfo){
53 PRINT("InternalSetSysTraceFunc started.");
54 }
55
56 DEFINE_PROC(isInit, Py_IsInitialized*, "Py_IsInitialized", 100);
57 if (!isInit()) {
58 PRINT("Py_IsInitialized returned false.");
59 return 110;
60 }
61
62 auto version = GetPythonVersion(module);
63
64 // found initialized Python runtime, gather and check the APIs we need.
65
66 DEFINE_PROC(interpHead, PyInterpreterState_Head*, "PyInterpreterState_Head", 120);
67 DEFINE_PROC(gilEnsure, PyGILState_Ensure*, "PyGILState_Ensure", 130);
68 DEFINE_PROC(gilRelease, PyGILState_Release*, "PyGILState_Release", 140);
69 DEFINE_PROC(threadHead, PyInterpreterState_ThreadHead*, "PyInterpreterState_ThreadHead", 150);
70 DEFINE_PROC(threadNext, PyThreadState_Next*, "PyThreadState_Next", 160);
71 DEFINE_PROC(threadSwap, PyThreadState_Swap*, "PyThreadState_Swap", 170);
72 DEFINE_PROC(call, PyObject_CallFunctionObjArgs*, "PyObject_CallFunctionObjArgs", 180);
73
74 PyInt_FromLong* intFromLong;
75
76 if (version >= PythonVersion_30) {
77 DEFINE_PROC(intFromLongPy3, PyInt_FromLong*, "PyLong_FromLong", 190);
78 intFromLong = intFromLongPy3;
79 } else {
80 DEFINE_PROC(intFromLongPy2, PyInt_FromLong*, "PyInt_FromLong", 200);
81 intFromLong = intFromLongPy2;
82 }
83
84 DEFINE_PROC(pyGetAttr, PyObject_GetAttrString*, "PyObject_GetAttrString", 250);
85 DEFINE_PROC(pyHasAttr, PyObject_HasAttrString*, "PyObject_HasAttrString", 260);
86 DEFINE_PROC_NO_CHECK(PyCFrame_Type, PyTypeObject*, "PyCFrame_Type", 300); // optional
87
88 DEFINE_PROC_NO_CHECK(curPythonThread, PyThreadState**, "_PyThreadState_Current", 310); // optional
89 DEFINE_PROC_NO_CHECK(getPythonThread, _PyThreadState_UncheckedGet*, "_PyThreadState_UncheckedGet", 320); // optional
90
91 if (curPythonThread == nullptr && getPythonThread == nullptr) {
92 // we're missing some APIs, we cannot attach.
93 PRINT("Error, missing Python threading API!!");
94 return 330;
95 }
96
97 auto head = interpHead();
98 if (head == nullptr) {
99 // this interpreter is loaded but not initialized.
100 PRINT("Interpreter not initialized!");
101 return 340;
102 }
103
104 GilHolder gilLock(gilEnsure, gilRelease); // acquire and hold the GIL until done...
105
106 int retVal = 0;
107 // find what index is holding onto the thread state...
108 auto curPyThread = getPythonThread ? getPythonThread() : *curPythonThread;
109
110 if(curPyThread == nullptr){
111 PRINT("Getting the current python thread returned nullptr.");
112 return 345;
113 }
114
115
116 // We do what PyEval_SetTrace does, but for any target thread.
117 PyUnicode_InternFromString* pyUnicode_InternFromString;
118 if (version >= PythonVersion_30) {
119 DEFINE_PROC(unicodeFromString, PyUnicode_InternFromString*, "PyUnicode_InternFromString", 520);
120 pyUnicode_InternFromString = unicodeFromString;
121 } else {
122 DEFINE_PROC(stringFromString, PyUnicode_InternFromString*, "PyString_InternFromString", 525);
123 pyUnicode_InternFromString = stringFromString;
124 }
125
126 DEFINE_PROC_NO_CHECK(pyObject_FastCallDict, _PyObject_FastCallDict*, "_PyObject_FastCallDict", 530);
127 DEFINE_PROC(pyTuple_New, PyTuple_New*, "PyTuple_New", 531);
128 DEFINE_PROC(pyEval_CallObjectWithKeywords, PyEval_CallObjectWithKeywords*, "PyEval_CallObjectWithKeywords", 532);
129
130 if(pyObject_FastCallDict == nullptr) {
131 // we have to use PyObject_FastCallDictCustom for older versions of CPython (pre 3.7).
132 pyObject_FastCallDict = reinterpret_cast<_PyObject_FastCallDict*>(&PyObject_FastCallDictCustom);
133 }
134
135
136 DEFINE_PROC(pyTraceBack_Here, PyTraceBack_Here*, "PyTraceBack_Here", 540);
137 DEFINE_PROC(pyEval_SetTrace, PyEval_SetTrace*, "PyEval_SetTrace", 550);
138
139 bool found = false;
140 for (PyThreadState* curThread = threadHead(head); curThread != nullptr; curThread = threadNext(curThread)) {
141 if (GetPythonThreadId(version, curThread) != threadId) {
142 continue;
143 }
144 found = true;
145
146 if(showDebugInfo){
147 printf("setting trace for thread: %d\n", threadId);
148 }
149
150 if(!InternalIsTraceInitialized())
151 {
152 InternalInitializeCustomPyEvalSetTrace *internalInitializeCustomPyEvalSetTrace = new InternalInitializeCustomPyEvalSetTrace();
153
154 IncRef(pyNone->ToPython());
155 internalInitializeCustomPyEvalSetTrace->pyNone = pyNone->ToPython();
156
157 internalInitializeCustomPyEvalSetTrace->pyUnicode_InternFromString = pyUnicode_InternFromString;
158 internalInitializeCustomPyEvalSetTrace->pyObject_FastCallDict = pyObject_FastCallDict;
159 internalInitializeCustomPyEvalSetTrace->isDebug = isDebug;
160 internalInitializeCustomPyEvalSetTrace->pyTraceBack_Here = pyTraceBack_Here;
161 internalInitializeCustomPyEvalSetTrace->pyEval_SetTrace = pyEval_SetTrace;
162 internalInitializeCustomPyEvalSetTrace->pyTuple_New = pyTuple_New;
163 internalInitializeCustomPyEvalSetTrace->pyEval_CallObjectWithKeywords = pyEval_CallObjectWithKeywords;
164
165 InternalTraceInit(internalInitializeCustomPyEvalSetTrace);
166 }
167 InternalPySetTrace(curThread, traceFunc, isDebug, version);
168 break;
169 }
170 if(!found) {
171 retVal = 501;
172 }
173
174 return retVal;
175
176 }
177
178 #endif // _PY_SETTRACE_HPP_
179