1 /* ****************************************************************************
2 *
3 * Copyright (c) Microsoft Corporation.
4 *
5 * This source code is subject to terms and conditions of the Apache License, Version 2.0. A
6 * copy of the license can be found in the License.html file at the root of this distribution. If
7 * you cannot locate the Apache License, Version 2.0, please send an email to
8 * vspython@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
9 * by the terms of the Apache License, Version 2.0.
10 *
11 * You must not remove this notice, or any other, from this software.
12 *
13 * Contributor: Fabio Zadrozny
14 *
15 * Based on PyDebugAttach.cpp from PVTS. Windows only.
16 * Initially we did an attach completely based on shellcode which got the
17 * GIL called PyRun_SimpleString with the needed code and was done with it
18 * (so, none of this code was needed).
19 * Now, newer version of Python don't initialize threading by default, so,
20 * most of this code is done only to overcome this limitation (and as a plus,
21 * if there's no code running, we also pause the threads to make our code run).
22 *
23 * On Linux the approach is still the simpler one (using gdb), so, on newer
24 * versions of Python it may not work unless the user has some code running
25 * and threads are initialized.
26 * I.e.:
27 *
28 * The user may have to add the code below in the start of its script for
29 * a successful attach (if he doesn't already use threads).
30 *
31 * from threading import Thread
32 * Thread(target=str).start()
33 *
34 * -- this is the workaround for the fact that we can't get the gil
35 * if there aren't any threads (PyGILState_Ensure gives an error).
36 * ***************************************************************************/
37 
38 
39 // Access to std::cout and std::endl
40 #include <iostream>
41 
42 // DECLDIR will perform an export for us
43 #define DLL_EXPORT
44 
45 #include "attach.h"
46 #include "stdafx.h"
47 #include "python.h"
48 
49 #pragma comment(lib, "kernel32.lib")
50 #pragma comment(lib, "user32.lib")
51 #pragma comment(lib, "advapi32.lib")
52 #pragma comment(lib, "psapi.lib")
53 
54 // _Always_ is not defined for all versions, so make it a no-op if missing.
55 #ifndef _Always_
56 #define _Always_(x) x
57 #endif
58 
59 using namespace std;
60 
61 typedef int (Py_IsInitialized)();
62 typedef void (PyEval_Lock)(); // Acquire/Release lock
63 typedef void (PyThreadState_API)(PyThreadState *); // Acquire/Release lock
64 typedef PyInterpreterState* (PyInterpreterState_Head)();
65 typedef PyThreadState* (PyInterpreterState_ThreadHead)(PyInterpreterState* interp);
66 typedef PyThreadState* (PyThreadState_Next)(PyThreadState *tstate);
67 typedef PyThreadState* (PyThreadState_Swap)(PyThreadState *tstate);
68 typedef int (PyRun_SimpleString)(const char *command);
69 typedef PyObject* (PyDict_New)();
70 typedef PyObject* (PyModule_New)(const char *name);
71 typedef PyObject* (PyModule_GetDict)(PyObject *module);
72 typedef PyObject* (Py_CompileString)(const char *str, const char *filename, int start);
73 typedef PyObject* (PyEval_EvalCode)(PyObject *co, PyObject *globals, PyObject *locals);
74 typedef PyObject* (PyDict_GetItemString)(PyObject *p, const char *key);
75 typedef PyObject* (PyObject_CallFunctionObjArgs)(PyObject *callable, ...);    // call w/ varargs, last arg should be NULL
76 typedef void (PyErr_Fetch)(PyObject **, PyObject **, PyObject **);
77 typedef PyObject* (PyEval_GetBuiltins)();
78 typedef int (PyDict_SetItemString)(PyObject *dp, const char *key, PyObject *item);
79 typedef int (PyEval_ThreadsInitialized)();
80 typedef void (Py_AddPendingCall)(int (*func)(void *), void*);
81 typedef PyObject* (PyInt_FromLong)(long);
82 typedef PyObject* (PyString_FromString)(const char* s);
83 typedef void PyEval_SetTrace(Py_tracefunc func, PyObject *obj);
84 typedef void (PyErr_Restore)(PyObject *type, PyObject *value, PyObject *traceback);
85 typedef void (PyErr_Fetch)(PyObject **ptype, PyObject **pvalue, PyObject **ptraceback);
86 typedef PyObject* (PyErr_Occurred)();
87 typedef PyObject* (PyErr_Print)();
88 typedef PyObject* (PyImport_ImportModule) (const char *name);
89 typedef PyObject* (PyObject_GetAttrString)(PyObject *o, const char *attr_name);
90 typedef PyObject* (PyObject_HasAttrString)(PyObject *o, const char *attr_name);
91 typedef PyObject* (PyObject_SetAttrString)(PyObject *o, const char *attr_name, PyObject* value);
92 typedef PyObject* (PyBool_FromLong)(long v);
93 typedef enum { PyGILState_LOCKED, PyGILState_UNLOCKED } PyGILState_STATE;
94 typedef PyGILState_STATE(PyGILState_Ensure)();
95 typedef void (PyGILState_Release)(PyGILState_STATE);
96 typedef unsigned long (_PyEval_GetSwitchInterval)(void);
97 typedef void (_PyEval_SetSwitchInterval)(unsigned long microseconds);
98 typedef void* (PyThread_get_key_value)(int);
99 typedef int (PyThread_set_key_value)(int, void*);
100 typedef void (PyThread_delete_key_value)(int);
101 typedef PyGILState_STATE PyGILState_EnsureFunc(void);
102 typedef void PyGILState_ReleaseFunc(PyGILState_STATE);
103 typedef PyObject* PyInt_FromSize_t(size_t ival);
104 typedef PyThreadState *PyThreadState_NewFunc(PyInterpreterState *interp);
105 
106 class PyObjectHolder;
107 PyObject* GetPyObjectPointerNoDebugInfo(bool isDebug, PyObject* object);
108 void DecRef(PyObject* object, bool isDebug);
109 void IncRef(PyObject* object, bool isDebug);
110 
111 #define MAX_INTERPRETERS 10
112 
113 // Helper class so we can use RAII for freeing python objects when they go out of scope
114 class PyObjectHolder {
115 private:
116     PyObject* _object;
117 public:
118     bool _isDebug;
119 
PyObjectHolder(bool isDebug)120     PyObjectHolder(bool isDebug) {
121         _object = nullptr;
122         _isDebug = isDebug;
123     }
124 
PyObjectHolder(bool isDebug,PyObject * object)125     PyObjectHolder(bool isDebug, PyObject *object) {
126         _object = object;
127         _isDebug = isDebug;
128     };
129 
PyObjectHolder(bool isDebug,PyObject * object,bool addRef)130     PyObjectHolder(bool isDebug, PyObject *object, bool addRef) {
131         _object = object;
132         _isDebug = isDebug;
133         if (_object != nullptr && addRef) {
134             GetPyObjectPointerNoDebugInfo(_isDebug, _object)->ob_refcnt++;
135         }
136     };
137 
ToPython()138     PyObject* ToPython() {
139         return _object;
140     }
141 
~PyObjectHolder()142     ~PyObjectHolder() {
143         DecRef(_object, _isDebug);
144     }
145 
operator *()146     PyObject* operator* () {
147         return GetPyObjectPointerNoDebugInfo(_isDebug, _object);
148     }
149 };
150 
151 class InterpreterInfo {
152 public:
InterpreterInfo(HMODULE module,bool debug)153     InterpreterInfo(HMODULE module, bool debug) :
154         Interpreter(module),
155         CurrentThread(nullptr),
156         NewThreadFunction(nullptr),
157         PyGILState_Ensure(nullptr),
158         Version(PythonVersion_Unknown),
159         Call(nullptr),
160         IsDebug(debug),
161         SetTrace(nullptr),
162         PyThreadState_New(nullptr),
163         ThreadState_Swap(nullptr) {
164     }
165 
~InterpreterInfo()166     ~InterpreterInfo() {
167         if (NewThreadFunction != nullptr) {
168             delete NewThreadFunction;
169         }
170     }
171 
172     PyObjectHolder* NewThreadFunction;
173     PyThreadState** CurrentThread;
174 
175     HMODULE Interpreter;
176     PyGILState_EnsureFunc* PyGILState_Ensure;
177     PyEval_SetTrace* SetTrace;
178     PyThreadState_NewFunc* PyThreadState_New;
179     PyThreadState_Swap* ThreadState_Swap;
180 
GetVersion()181     PythonVersion GetVersion() {
182         if (Version == PythonVersion_Unknown) {
183             Version = ::GetPythonVersion(Interpreter);
184         }
185         return Version;
186     }
187 
GetCall()188     PyObject_CallFunctionObjArgs* GetCall() {
189         if (Call == nullptr) {
190             Call = (PyObject_CallFunctionObjArgs*)GetProcAddress(Interpreter, "PyObject_CallFunctionObjArgs");
191         }
192 
193         return Call;
194     }
195 
EnsureSetTrace()196     bool EnsureSetTrace() {
197         if (SetTrace == nullptr) {
198             auto setTrace = (PyEval_SetTrace*)(void*)GetProcAddress(Interpreter, "PyEval_SetTrace");
199             SetTrace = setTrace;
200         }
201         return SetTrace != nullptr;
202     }
203 
EnsureThreadStateSwap()204     bool EnsureThreadStateSwap() {
205         if (ThreadState_Swap == nullptr) {
206             auto swap = (PyThreadState_Swap*)(void*)GetProcAddress(Interpreter, "PyThreadState_Swap");
207             ThreadState_Swap = swap;
208         }
209         return ThreadState_Swap != nullptr;
210     }
211 
EnsureCurrentThread()212     bool EnsureCurrentThread() {
213         if (CurrentThread == nullptr) {
214             auto curPythonThread = (PyThreadState**)(void*)GetProcAddress(
215                 Interpreter, "_PyThreadState_Current");
216             CurrentThread = curPythonThread;
217         }
218 
219         return CurrentThread != nullptr;
220     }
221 
222 private:
223     PythonVersion Version;
224     PyObject_CallFunctionObjArgs* Call;
225     bool IsDebug;
226 };
227 
228 DWORD _interpreterCount = 0;
229 InterpreterInfo* _interpreterInfo[MAX_INTERPRETERS];
230 
PatchIAT(PIMAGE_DOS_HEADER dosHeader,PVOID replacingFunc,LPSTR exportingDll,LPVOID newFunction)231 void PatchIAT(PIMAGE_DOS_HEADER dosHeader, PVOID replacingFunc, LPSTR exportingDll, LPVOID newFunction) {
232     if (dosHeader->e_magic != IMAGE_DOS_SIGNATURE) {
233         return;
234     }
235 
236     auto ntHeader = (IMAGE_NT_HEADERS*)(((BYTE*)dosHeader) + dosHeader->e_lfanew);
237     if (ntHeader->Signature != IMAGE_NT_SIGNATURE) {
238         return;
239     }
240 
241     auto importAddr = ntHeader->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_IMPORT].VirtualAddress;
242     if (importAddr == 0) {
243         return;
244     }
245 
246     auto import = (PIMAGE_IMPORT_DESCRIPTOR)(importAddr + ((BYTE*)dosHeader));
247 
248     while (import->Name) {
249         char* name = (char*)(import->Name + ((BYTE*)dosHeader));
250         if (_stricmp(name, exportingDll) == 0) {
251             auto thunkData = (PIMAGE_THUNK_DATA)((import->FirstThunk) + ((BYTE*)dosHeader));
252 
253             while (thunkData->u1.Function) {
254                 PVOID funcAddr = (char*)(thunkData->u1.Function);
255 
256                 if (funcAddr == replacingFunc) {
257                     DWORD flOldProtect;
258                     if (VirtualProtect(&thunkData->u1, sizeof(SIZE_T), PAGE_READWRITE, &flOldProtect)) {
259                         thunkData->u1.Function = (SIZE_T)newFunction;
260                         VirtualProtect(&thunkData->u1, sizeof(SIZE_T), flOldProtect, &flOldProtect);
261                     }
262                 }
263                 thunkData++;
264             }
265         }
266 
267         import++;
268     }
269 }
270 
271 typedef BOOL WINAPI EnumProcessModulesFunc(
272     __in   HANDLE hProcess,
273     __out  HMODULE *lphModule,
274     __in   DWORD cb,
275     __out  LPDWORD lpcbNeeded
276     );
277 
278 typedef __kernel_entry NTSTATUS NTAPI
279     NtQueryInformationProcessFunc(
280     IN HANDLE ProcessHandle,
281     IN PROCESSINFOCLASS ProcessInformationClass,
282     OUT PVOID ProcessInformation,
283     IN ULONG ProcessInformationLength,
284     OUT PULONG ReturnLength OPTIONAL
285     );
286 
287 
288 // A helper version of EnumProcessModules.  On Win7 uses the real EnumProcessModules which
289 // lives in kernel32, and so is safe to use in DLLMain.  Pre-Win7 we use NtQueryInformationProcess
290 // (http://msdn.microsoft.com/en-us/library/windows/desktop/ms684280(v=vs.85).aspx) and walk the
291 // LDR_DATA_TABLE_ENTRY data structures http://msdn.microsoft.com/en-us/library/windows/desktop/aa813708(v=vs.85).aspx
292 // which have changed in Windows 7, and may change more in the future, so we can't use them there.
__success(return)293 __success(return) BOOL EnumProcessModulesHelper(
294     __in   HANDLE hProcess,
295     __out  HMODULE *lphModule,
296     __in   DWORD cb,
297     _Always_(__out) LPDWORD lpcbNeeded
298     ) {
299         if (lpcbNeeded == nullptr) {
300             return FALSE;
301         }
302         *lpcbNeeded = 0;
303 
304         auto kernel32 = GetModuleHandle(L"kernel32.dll");
305         if (kernel32 == nullptr) {
306             return FALSE;
307         }
308 
309         auto enumProc = (EnumProcessModulesFunc*)GetProcAddress(kernel32, "K32EnumProcessModules");
310         if (enumProc == nullptr) {
311             // Fallback to pre-Win7 method
312             PROCESS_BASIC_INFORMATION basicInfo;
313             auto ntdll = GetModuleHandle(L"ntdll.dll");
314             if (ntdll == nullptr) {
315                 return FALSE;
316             }
317 
318             // http://msdn.microsoft.com/en-us/library/windows/desktop/ms684280(v=vs.85).aspx
319             NtQueryInformationProcessFunc* queryInfo = (NtQueryInformationProcessFunc*)GetProcAddress(ntdll, "NtQueryInformationProcess");
320             if (queryInfo == nullptr) {
321                 return FALSE;
322             }
323 
324             auto result = queryInfo(
325                 GetCurrentProcess(),
326                 ProcessBasicInformation,
327                 &basicInfo,
328                 sizeof(PROCESS_BASIC_INFORMATION),
329                 NULL
330                 );
331 
332             if (FAILED(result)) {
333                 return FALSE;
334             }
335 
336             // http://msdn.microsoft.com/en-us/library/windows/desktop/aa813708(v=vs.85).aspx
337             PEB* peb = basicInfo.PebBaseAddress;
338             auto start = (LDR_DATA_TABLE_ENTRY*)(peb->Ldr->InMemoryOrderModuleList.Flink);
339 
340             auto cur = start;
341             *lpcbNeeded = 0;
342 
343             do {
344                 if ((*lpcbNeeded + sizeof(SIZE_T)) <= cb) {
345                     PVOID *curLink = (PVOID*)cur;
346                     curLink -= 2;
347                     LDR_DATA_TABLE_ENTRY* curTable = (LDR_DATA_TABLE_ENTRY*)curLink;
348                     if (curTable->DllBase == nullptr) {
349                         break;
350                     }
351                     lphModule[(*lpcbNeeded) / sizeof(SIZE_T)] = (HMODULE)curTable->DllBase;
352                 }
353 
354                 (*lpcbNeeded) += sizeof(SIZE_T);
355                 cur = (LDR_DATA_TABLE_ENTRY*)((LIST_ENTRY*)cur)->Flink;
356             } while (cur != start && cur != 0);
357 
358             return *lpcbNeeded <= cb;
359         }
360 
361         return enumProc(hProcess, lphModule, cb, lpcbNeeded);
362 }
363 
364 // This function will work with Win7 and later versions of the OS and is safe to call under
365 // the loader lock (all APIs used are in kernel32).
PatchFunction(LPSTR exportingDll,PVOID replacingFunc,LPVOID newFunction)366 BOOL PatchFunction(LPSTR exportingDll, PVOID replacingFunc, LPVOID newFunction) {
367     HANDLE hProcess = GetCurrentProcess();
368     DWORD modSize = sizeof(HMODULE) * 1024;
369     HMODULE* hMods = (HMODULE*)_malloca(modSize);
370     DWORD modsNeeded = 0;
371     if (hMods == nullptr) {
372         modsNeeded = 0;
373         return FALSE;
374     }
375 
376     while (!EnumProcessModulesHelper(hProcess, hMods, modSize, &modsNeeded)) {
377         // try again w/ more space...
378         _freea(hMods);
379         hMods = (HMODULE*)_malloca(modsNeeded);
380         if (hMods == nullptr) {
381             modsNeeded = 0;
382             break;
383         }
384         modSize = modsNeeded;
385     }
386 
387     for (DWORD tmp = 0; tmp < modsNeeded / sizeof(HMODULE); tmp++) {
388         PIMAGE_DOS_HEADER dosHeader = (PIMAGE_DOS_HEADER)hMods[tmp];
389 
390         PatchIAT(dosHeader, replacingFunc, exportingDll, newFunction);
391     }
392 
393     return TRUE;
394 }
395 
GetCurrentModuleFilename()396 wstring GetCurrentModuleFilename() {
397     HMODULE hModule = NULL;
398     if (GetModuleHandleEx(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, (LPCTSTR)GetCurrentModuleFilename, &hModule) != 0) {
399         wchar_t filename[MAX_PATH];
400         GetModuleFileName(hModule, filename, MAX_PATH);
401         return filename;
402     }
403     return wstring();
404 }
405 
406 struct AttachInfo {
407     PyEval_Lock* InitThreads;
408     HANDLE Event;
409 };
410 
411 HANDLE g_initedEvent;
AttachCallback(void * initThreads)412 int AttachCallback(void *initThreads) {
413     // initialize us for threading, this will acquire the GIL if not already created, and is a nop if the GIL is created.
414     // This leaves us in the proper state when we return back to the runtime whether the GIL was created or not before
415     // we were called.
416     ((PyEval_Lock*)initThreads)();
417     SetEvent(g_initedEvent);
418     return 0;
419 }
420 
ReadCodeFromFile(wchar_t * filePath)421 char* ReadCodeFromFile(wchar_t* filePath) {
422     ifstream filestr;
423     filestr.open(filePath, ios::binary);
424     if (filestr.fail()) {
425         return nullptr;
426     }
427 
428     // get length of file:
429     filestr.seekg(0, ios::end);
430     auto length = filestr.tellg();
431     filestr.seekg(0, ios::beg);
432 
433     int len = (int)length;
434     char* buffer = new char[len + 1];
435     filestr.read(buffer, len);
436     buffer[len] = 0;
437 
438     // remove carriage returns, copy zero byte
439     for (int read = 0, write = 0; read <= len; read++) {
440         if (buffer[read] == '\r') {
441             continue;
442         } else if (write != read) {
443             buffer[write] = buffer[read];
444         }
445         write++;
446     }
447 
448     return buffer;
449 }
450 
451 // create a custom heap for our unordered map.  This is necessary because if we suspend a thread while in a heap function
452 // then we could deadlock here.  We need to be VERY careful about what we do while the threads are suspended.
453 static HANDLE g_heap = 0;
454 
455 template<typename T>
456 class PrivateHeapAllocator {
457 public:
458     typedef size_t    size_type;
459     typedef ptrdiff_t difference_type;
460     typedef T*        pointer;
461     typedef const T*  const_pointer;
462     typedef T&        reference;
463     typedef const T&  const_reference;
464     typedef T         value_type;
465 
466     template<class U>
467     struct rebind {
468         typedef PrivateHeapAllocator<U> other;
469     };
470 
PrivateHeapAllocator()471     explicit PrivateHeapAllocator() {}
472 
PrivateHeapAllocator(PrivateHeapAllocator const &)473     PrivateHeapAllocator(PrivateHeapAllocator const&) {}
474 
~PrivateHeapAllocator()475     ~PrivateHeapAllocator() {}
476 
477     template<typename U>
PrivateHeapAllocator(PrivateHeapAllocator<U> const &)478     PrivateHeapAllocator(PrivateHeapAllocator<U> const&) {}
479 
allocate(size_type size,allocator<void>::const_pointer hint=0)480     pointer allocate(size_type size, allocator<void>::const_pointer hint = 0) {
481         if (g_heap == nullptr) {
482             g_heap = HeapCreate(0, 0, 0);
483         }
484         auto mem = HeapAlloc(g_heap, 0, size * sizeof(T));
485         return static_cast<pointer>(mem);
486     }
487 
deallocate(pointer p,size_type n)488     void deallocate(pointer p, size_type n) {
489         HeapFree(g_heap, 0, p);
490     }
491 
max_size() const492     size_type max_size() const {
493         return (std::numeric_limits<size_type>::max)() / sizeof(T);
494     }
495 
construct(pointer p,const T & t)496     void construct(pointer p, const T& t) {
497         new(p) T(t);
498     }
499 
destroy(pointer p)500     void destroy(pointer p) {
501         p->~T();
502     }
503 };
504 
505 typedef unordered_map<DWORD, HANDLE, std::hash<DWORD>, std::equal_to<DWORD>, PrivateHeapAllocator<pair<DWORD, HANDLE>>> ThreadMap;
506 
ResumeThreads(ThreadMap & suspendedThreads)507 void ResumeThreads(ThreadMap &suspendedThreads) {
508     for (auto start = suspendedThreads.begin();  start != suspendedThreads.end(); start++) {
509         ResumeThread((*start).second);
510         CloseHandle((*start).second);
511     }
512     suspendedThreads.clear();
513 }
514 
515 // Suspends all threads ensuring that they are not currently in a call to Py_AddPendingCall.
SuspendThreads(ThreadMap & suspendedThreads,Py_AddPendingCall * addPendingCall,PyEval_ThreadsInitialized * threadsInited)516 void SuspendThreads(ThreadMap &suspendedThreads, Py_AddPendingCall* addPendingCall, PyEval_ThreadsInitialized* threadsInited) {
517     DWORD curThreadId = GetCurrentThreadId();
518     DWORD curProcess = GetCurrentProcessId();
519     // suspend all the threads in the process so we can do things safely...
520     bool suspended;
521 
522     do {
523         suspended = false;
524         HANDLE h = CreateToolhelp32Snapshot(TH32CS_SNAPTHREAD, 0);
525         if (h != INVALID_HANDLE_VALUE) {
526 
527             THREADENTRY32 te;
528             te.dwSize = sizeof(te);
529             if (Thread32First(h, &te)) {
530                 do {
531                     if (te.dwSize >= FIELD_OFFSET(THREADENTRY32, th32OwnerProcessID) + sizeof(te.th32OwnerProcessID) && te.th32OwnerProcessID == curProcess) {
532 
533 
534                         if (te.th32ThreadID != curThreadId && suspendedThreads.find(te.th32ThreadID) == suspendedThreads.end()) {
535                             auto hThread = OpenThread(THREAD_ALL_ACCESS, FALSE, te.th32ThreadID);
536                             if (hThread != nullptr) {
537                                 SuspendThread(hThread);
538 
539                                 bool addingPendingCall = false;
540 
541                                 CONTEXT context;
542                                 memset(&context, 0x00, sizeof(CONTEXT));
543                                 context.ContextFlags = CONTEXT_ALL;
544                                 GetThreadContext(hThread, &context);
545 
546 #if defined(_X86_)
547                                 if(context.Eip >= *((DWORD*)addPendingCall) && context.Eip <= (*((DWORD*)addPendingCall)) + 0x100) {
548                                     addingPendingCall = true;
549                                 }
550 #elif defined(_AMD64_)
551                                 if (context.Rip >= *((DWORD64*)addPendingCall) && context.Rip <= *((DWORD64*)addPendingCall + 0x100)) {
552                                     addingPendingCall = true;
553                                 }
554 #endif
555 
556                                 if (addingPendingCall) {
557                                     // we appear to be adding a pending call via this thread - wait for this to finish so we can add our own pending call...
558                                     ResumeThread(hThread);
559                                     SwitchToThread();   // yield to the resumed thread if it's on our CPU...
560                                     CloseHandle(hThread);
561                                 } else {
562                                     suspendedThreads[te.th32ThreadID] = hThread;
563                                 }
564                                 suspended = true;
565                             }
566                         }
567                     }
568 
569                     te.dwSize = sizeof(te);
570                 } while (Thread32Next(h, &te) && !threadsInited());
571             }
572             CloseHandle(h);
573         }
574     } while (suspended && !threadsInited());
575 }
576 
GetPyObjectPointerNoDebugInfo(bool isDebug,PyObject * object)577 PyObject* GetPyObjectPointerNoDebugInfo(bool isDebug, PyObject* object) {
578     if (object != nullptr && isDebug) {
579         // debug builds have 2 extra pointers at the front that we don't care about
580         return (PyObject*)((size_t*)object + 2);
581     }
582     return object;
583 }
584 
DecRef(PyObject * object,bool isDebug)585 void DecRef(PyObject* object, bool isDebug) {
586     auto noDebug = GetPyObjectPointerNoDebugInfo(isDebug, object);
587 
588     if (noDebug != nullptr && --noDebug->ob_refcnt == 0) {
589         ((PyTypeObject*)GetPyObjectPointerNoDebugInfo(isDebug, noDebug->ob_type))->tp_dealloc(object);
590     }
591 }
592 
IncRef(PyObject * object)593 void IncRef(PyObject* object) {
594     object->ob_refcnt++;
595 }
596 
597 
598 // Ensures handles are closed when they go out of scope
599 class HandleHolder {
600     HANDLE _handle;
601 public:
HandleHolder(HANDLE handle)602     HandleHolder(HANDLE handle) : _handle(handle) {
603     }
604 
~HandleHolder()605     ~HandleHolder() {
606         CloseHandle(_handle);
607     }
608 };
609 
GetPythonThreadId(PythonVersion version,PyThreadState * curThread)610 long GetPythonThreadId(PythonVersion version, PyThreadState* curThread) {
611     long threadId = 0;
612     if (PyThreadState_25_27::IsFor(version)) {
613         threadId = ((PyThreadState_25_27*)curThread)->thread_id;
614     } else if (PyThreadState_30_33::IsFor(version)) {
615         threadId = ((PyThreadState_30_33*)curThread)->thread_id;
616     } else if (PyThreadState_34_36::IsFor(version)) {
617         threadId = ((PyThreadState_34_36*)curThread)->thread_id;
618     }
619     return threadId;
620 }
621 
622 // holder to ensure we release the GIL even in error conditions
623 class GilHolder {
624     PyGILState_STATE _gilState;
625     PyGILState_Release* _release;
626 public:
GilHolder(PyGILState_Ensure * acquire,PyGILState_Release * release)627     GilHolder(PyGILState_Ensure* acquire, PyGILState_Release* release) {
628         _gilState = acquire();
629         _release = release;
630     }
631 
~GilHolder()632     ~GilHolder() {
633         _release(_gilState);
634     }
635 };
636 
LoadAndEvaluateCode(wchar_t * filePath,const char * fileName,bool isDebug,PyObject * globalsDict,Py_CompileString * pyCompileString,PyDict_SetItemString * dictSetItem,PyEval_EvalCode * pyEvalCode,PyString_FromString * strFromString,PyEval_GetBuiltins * getBuiltins,PyErr_Print pyErrPrint)637 bool LoadAndEvaluateCode(
638     wchar_t* filePath, const char* fileName, bool isDebug, PyObject* globalsDict,
639     Py_CompileString* pyCompileString, PyDict_SetItemString* dictSetItem,
640     PyEval_EvalCode* pyEvalCode, PyString_FromString* strFromString, PyEval_GetBuiltins* getBuiltins,
641     PyErr_Print pyErrPrint
642  ) {
643     auto debuggerCode = ReadCodeFromFile(filePath);
644     if (debuggerCode == nullptr) {
645         return false;
646     }
647 
648     auto code = PyObjectHolder(isDebug, pyCompileString(debuggerCode, fileName, 257 /*Py_file_input*/));
649     delete[] debuggerCode;
650 
651     if (*code == nullptr) {
652         return false;
653     }
654 
655     dictSetItem(globalsDict, "__builtins__", getBuiltins());
656     auto size = WideCharToMultiByte(CP_UTF8, 0, filePath, (DWORD)wcslen(filePath), NULL, 0, NULL, NULL);
657     char* filenameBuffer = new char[size];
658     if (WideCharToMultiByte(CP_UTF8, 0, filePath, (DWORD)wcslen(filePath), filenameBuffer, size, NULL, NULL) != 0) {
659         filenameBuffer[size] = 0;
660         dictSetItem(globalsDict, "__file__", strFromString(filenameBuffer));
661     }
662 
663     auto evalResult = PyObjectHolder(isDebug, pyEvalCode(code.ToPython(), globalsDict, globalsDict));
664 #if !NDEBUG
665     if (*evalResult == nullptr) {
666         pyErrPrint();
667     }
668 #endif
669 
670     return true;
671 }
672 
673 // Checks to see if the specified module is likely a Python interpreter.
IsPythonModule(HMODULE module,bool & isDebug)674 bool IsPythonModule(HMODULE module, bool &isDebug) {
675     wchar_t mod_name[MAX_PATH];
676     isDebug = false;
677     if (GetModuleBaseName(GetCurrentProcess(), module, mod_name, MAX_PATH)) {
678         if (_wcsnicmp(mod_name, L"python", 6) == 0) {
679             if (wcslen(mod_name) >= 10 && _wcsnicmp(mod_name + 8, L"_d", 2) == 0) {
680                 isDebug = true;
681             }
682             return true;
683         }
684     }
685     return false;
686 }
687 
688 extern "C"
689 {
690 
691     /**
692      * The returned value signals the error that happened!
693      *
694      * Return codes:
695      * 0 = all OK.
696      * 1 = Py_IsInitialized not found
697      * 2 = Py_IsInitialized returned false
698      * 3 = Missing Python API
699      * 4 = Interpreter not initialized
700      * 5 = Python version unknown
701      * 6 = Connect timeout
702      **/
DoAttach(HMODULE module,bool isDebug,const char * command,bool showDebugInfo)703 	int DoAttach(HMODULE module, bool isDebug, const char *command, bool showDebugInfo )
704 	{
705         auto isInit = (Py_IsInitialized*)GetProcAddress(module, "Py_IsInitialized");
706 
707         if (isInit == nullptr) {
708             if(showDebugInfo){
709                 std::cout << "Py_IsInitialized not found. " << std::endl << std::flush;
710             }
711             return 1;
712         }
713         if (!isInit()) {
714             if(showDebugInfo){
715                 std::cout << "Py_IsInitialized returned false. " << std::endl << std::flush;
716             }
717             return 2;
718         }
719 
720         auto version = GetPythonVersion(module);
721 
722         // found initialized Python runtime, gather and check the APIs we need for a successful attach...
723         auto addPendingCall = (Py_AddPendingCall*)GetProcAddress(module, "Py_AddPendingCall");
724         auto curPythonThread = (PyThreadState**)(void*)GetProcAddress(module, "_PyThreadState_Current");
725         auto interpHead = (PyInterpreterState_Head*)GetProcAddress(module, "PyInterpreterState_Head");
726         auto gilEnsure = (PyGILState_Ensure*)GetProcAddress(module, "PyGILState_Ensure");
727         auto gilRelease = (PyGILState_Release*)GetProcAddress(module, "PyGILState_Release");
728         auto threadHead = (PyInterpreterState_ThreadHead*)GetProcAddress(module, "PyInterpreterState_ThreadHead");
729         auto initThreads = (PyEval_Lock*)GetProcAddress(module, "PyEval_InitThreads");
730         auto acquireLock = (PyEval_Lock*)GetProcAddress(module, "PyEval_AcquireLock");
731         auto releaseLock = (PyEval_Lock*)GetProcAddress(module, "PyEval_ReleaseLock");
732         auto threadsInited = (PyEval_ThreadsInitialized*)GetProcAddress(module, "PyEval_ThreadsInitialized");
733         auto threadNext = (PyThreadState_Next*)GetProcAddress(module, "PyThreadState_Next");
734         auto threadSwap = (PyThreadState_Swap*)GetProcAddress(module, "PyThreadState_Swap");
735         auto pyDictNew = (PyDict_New*)GetProcAddress(module, "PyDict_New");
736         auto pyModuleNew = (PyModule_New*)GetProcAddress(module, "PyModule_New");
737         auto pyModuleGetDict = (PyModule_GetDict*)GetProcAddress(module, "PyModule_GetDict");
738         auto pyCompileString = (Py_CompileString*)GetProcAddress(module, "Py_CompileString");
739         auto pyEvalCode = (PyEval_EvalCode*)GetProcAddress(module, "PyEval_EvalCode");
740         auto getDictItem = (PyDict_GetItemString*)GetProcAddress(module, "PyDict_GetItemString");
741         auto call = (PyObject_CallFunctionObjArgs*)GetProcAddress(module, "PyObject_CallFunctionObjArgs");
742         auto getBuiltins = (PyEval_GetBuiltins*)GetProcAddress(module, "PyEval_GetBuiltins");
743         auto dictSetItem = (PyDict_SetItemString*)GetProcAddress(module, "PyDict_SetItemString");
744         PyInt_FromLong* intFromLong;
745         PyString_FromString* strFromString;
746         PyInt_FromSize_t* intFromSizeT;
747         if (version >= PythonVersion_30) {
748             intFromLong = (PyInt_FromLong*)GetProcAddress(module, "PyLong_FromLong");
749             intFromSizeT = (PyInt_FromSize_t*)GetProcAddress(module, "PyLong_FromSize_t");
750             if (version >= PythonVersion_33) {
751                 strFromString = (PyString_FromString*)GetProcAddress(module, "PyUnicode_FromString");
752             } else {
753                 strFromString = (PyString_FromString*)GetProcAddress(module, "PyUnicodeUCS2_FromString");
754             }
755         } else {
756             intFromLong = (PyInt_FromLong*)GetProcAddress(module, "PyInt_FromLong");
757             strFromString = (PyString_FromString*)GetProcAddress(module, "PyString_FromString");
758             intFromSizeT = (PyInt_FromSize_t*)GetProcAddress(module, "PyInt_FromSize_t");
759         }
760         auto intervalCheck = (int*)GetProcAddress(module, "_Py_CheckInterval");
761         auto errOccurred = (PyErr_Occurred*)GetProcAddress(module, "PyErr_Occurred");
762         auto pyErrFetch = (PyErr_Fetch*)GetProcAddress(module, "PyErr_Fetch");
763         auto pyErrRestore = (PyErr_Restore*)GetProcAddress(module, "PyErr_Restore");
764         auto pyErrPrint = (PyErr_Print*)GetProcAddress(module, "PyErr_Print");
765         auto pyImportMod = (PyImport_ImportModule*) GetProcAddress(module, "PyImport_ImportModule");
766         auto pyGetAttr = (PyObject_GetAttrString*)GetProcAddress(module, "PyObject_GetAttrString");
767         auto pySetAttr = (PyObject_SetAttrString*)GetProcAddress(module, "PyObject_SetAttrString");
768         auto pyNone = (PyObject*)GetProcAddress(module, "_Py_NoneStruct");
769         auto getSwitchInterval = (_PyEval_GetSwitchInterval*)GetProcAddress(module, "_PyEval_GetSwitchInterval");
770         auto setSwitchInterval = (_PyEval_SetSwitchInterval*)GetProcAddress(module, "_PyEval_SetSwitchInterval");
771         auto boolFromLong = (PyBool_FromLong*)GetProcAddress(module, "PyBool_FromLong");
772         auto getThreadTls = (PyThread_get_key_value*)GetProcAddress(module, "PyThread_get_key_value");
773         auto setThreadTls = (PyThread_set_key_value*)GetProcAddress(module, "PyThread_set_key_value");
774         auto delThreadTls = (PyThread_delete_key_value*)GetProcAddress(module, "PyThread_delete_key_value");
775         auto pyGilStateEnsure = (PyGILState_EnsureFunc*)GetProcAddress(module, "PyGILState_Ensure");
776         auto pyGilStateRelease = (PyGILState_ReleaseFunc*)GetProcAddress(module, "PyGILState_Release");
777         auto PyCFrame_Type = (PyTypeObject*)GetProcAddress(module, "PyCFrame_Type");
778         auto pyRun_SimpleString = (PyRun_SimpleString*)GetProcAddress(module, "PyRun_SimpleString");
779 
780         if (addPendingCall == nullptr || curPythonThread == nullptr || interpHead == nullptr || gilEnsure == nullptr || gilRelease == nullptr || threadHead == nullptr ||
781             initThreads == nullptr || releaseLock == nullptr || threadsInited == nullptr || threadNext == nullptr || threadSwap == nullptr ||
782             pyDictNew == nullptr || pyCompileString == nullptr || pyEvalCode == nullptr || getDictItem == nullptr || call == nullptr ||
783             getBuiltins == nullptr || dictSetItem == nullptr || intFromLong == nullptr || pyErrRestore == nullptr || pyErrFetch == nullptr ||
784             errOccurred == nullptr || pyImportMod == nullptr || pyGetAttr == nullptr || pyNone == nullptr || pySetAttr == nullptr || boolFromLong == nullptr ||
785             getThreadTls == nullptr || setThreadTls == nullptr || delThreadTls == nullptr || releaseLock == nullptr ||
786             pyGilStateEnsure == nullptr || pyGilStateRelease == nullptr || pyRun_SimpleString == nullptr) {
787                 // we're missing some APIs, we cannot attach.
788                 if(showDebugInfo){
789                     std::cout << "Error, missing Python API!! " << std::endl << std::flush;
790                 }
791                 return 3;
792         }
793 
794         auto head = interpHead();
795         if (head == nullptr) {
796             // this interpreter is loaded but not initialized.
797             if(showDebugInfo){
798                 std::cout << "Interpreter not initialized! " << std::endl << std::flush;
799             }
800             return 4;
801         }
802 
803         bool threadSafeAddPendingCall = false;
804 
805         // check that we're a supported version
806         if (version == PythonVersion_Unknown) {
807             if(showDebugInfo){
808                 std::cout << "Python version unknown! " << std::endl << std::flush;
809             }
810             return 5;
811         } else if (version >= PythonVersion_27 && version != PythonVersion_30) {
812             threadSafeAddPendingCall = true;
813         }
814 
815 
816 
817 
818 
819 
820         if (!threadsInited()) {
821              int saveIntervalCheck;
822              unsigned long saveLongIntervalCheck;
823              if (intervalCheck != nullptr) {
824                  // not available on 3.2
825                  saveIntervalCheck = *intervalCheck;
826                  *intervalCheck = -1;    // lower the interval check so pending calls are processed faster
827              } else if (getSwitchInterval != nullptr && setSwitchInterval != nullptr) {
828                  saveLongIntervalCheck = getSwitchInterval();
829                  setSwitchInterval(0);
830              }
831 
832              //
833              // Multiple thread support has not been initialized in the interpreter.   We need multi threading support
834              // to block any actively running threads and setup the debugger attach state.
835              //
836              // We need to initialize multiple threading support but we need to do so safely.  One option is to call
837              // Py_AddPendingCall and have our callback then initialize multi threading.  This is completely safe on 2.7
838              // and up.  Unfortunately that doesn't work if we're not actively running code on the main thread (blocked on a lock
839              // or reading input).  It's also not thread safe pre-2.7 so we need to make sure it's safe to call on down-level
840              // interpreters.
841              //
842              // Another option is to make sure no code is running - if there is no active thread then we can safely call
843              // PyEval_InitThreads and we're in business.  But to know this is safe we need to first suspend all the other
844              // threads in the process and then inspect if any code is running.
845              //
846              // Finally if code is running after we've suspended the threads then we can go ahead and do Py_AddPendingCall
847              // on down-level interpreters as long as we're sure no one else is making a call to Py_AddPendingCall at the same
848              // time.
849              //
850              // Therefore our strategy becomes: Make the Py_AddPendingCall on interpreters where it's thread safe.  Then suspend
851              // all threads - if a threads IP is in Py_AddPendingCall resume and try again.  Once we've got all of the threads
852              // stopped and not in Py_AddPendingCall (which calls no functions its self, you can see this and it's size in the
853              // debugger) then see if we have a current thread.   If not go ahead and initialize multiple threading (it's now safe,
854              // no Python code is running).  Otherwise add the pending call and repeat.  If at any point during this process
855              // threading becomes initialized (due to our pending call or the Python code creating a new thread)  then we're done
856              // and we just resume all of the presently suspended threads.
857 
858              ThreadMap suspendedThreads;
859 
860              g_initedEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
861              HandleHolder holder(g_initedEvent);
862 
863              bool addedPendingCall = false;
864              if (addPendingCall != nullptr && threadSafeAddPendingCall) {
865                  // we're on a thread safe Python version, go ahead and pend our call to initialize threading.
866                  addPendingCall(&AttachCallback, initThreads);
867                  addedPendingCall = true;
868              }
869 
870  #define TICKS_DIFF(prev, cur) ((cur) >= (prev)) ? ((cur)-(prev)) : ((0xFFFFFFFF-(prev))+(cur))
871              const DWORD ticksPerSecond = 1000;
872 
873             DWORD startTickCount = GetTickCount();
874             do {
875                 SuspendThreads(suspendedThreads, addPendingCall, threadsInited);
876 
877                  if (!threadsInited()) {
878                     if (*curPythonThread == nullptr) {
879                          // no threads are currently running, it is safe to initialize multi threading.
880                          PyGILState_STATE gilState;
881                          if (version >= PythonVersion_34) {
882                              // in 3.4 due to http://bugs.python.org/issue20891,
883                              // we need to create our thread state manually
884                              // before we can call PyGILState_Ensure() before we
885                              // can call PyEval_InitThreads().
886 
887                              // Don't require this function unless we need it.
888                              auto threadNew = (PyThreadState_NewFunc*)GetProcAddress(module, "PyThreadState_New");
889                              if (threadNew != nullptr) {
890                                  threadNew(head);
891                              }
892                          }
893 
894                          if (version >= PythonVersion_32) {
895                              // in 3.2 due to the new GIL and later we can't call Py_InitThreads
896                              // without a thread being initialized.
897                              // So we use PyGilState_Ensure here to first
898                              // initialize the current thread, and then we use
899                              // Py_InitThreads to bring up multi-threading.
900                              // Some context here: http://bugs.python.org/issue11329
901                              // http://pytools.codeplex.com/workitem/834
902                              gilState = pyGilStateEnsure();
903                          }
904                          initThreads();
905 
906                          if (version >= PythonVersion_32) {
907                              // we will release the GIL here
908                              pyGilStateRelease(gilState);
909                          } else {
910                              releaseLock();
911                          }
912                     } else if (!addedPendingCall) {
913                         // someone holds the GIL but no one is actively adding any pending calls.  We can pend our call
914                         // and initialize threads.
915                         addPendingCall(&AttachCallback, initThreads);
916                         addedPendingCall = true;
917                     }
918                 }
919                 ResumeThreads(suspendedThreads);
920             } while (!threadsInited() &&
921                 (TICKS_DIFF(startTickCount, GetTickCount())) < (ticksPerSecond * 20) &&
922                 !addedPendingCall);
923 
924             if (!threadsInited()) {
925                 if (addedPendingCall) {
926                     // we've added our call to initialize multi-threading, we can now wait
927                     // until Python code actually starts running.
928                     if(showDebugInfo){
929                         std::cout << "Waiting for threads to be initialized! " << std::endl << std::flush;
930                     }
931 
932                     ::WaitForSingleObject(g_initedEvent, INFINITE);
933                 } else {
934                     if(showDebugInfo){
935                         std::cout << "Connect timeout! " << std::endl << std::flush;
936                     }
937                     return 6;
938                 }
939             } else {
940                 if(showDebugInfo){
941                     std::cout << "Threads initialized! " << std::endl << std::flush;
942                 }
943             }
944 
945              if (intervalCheck != nullptr) {
946                  *intervalCheck = saveIntervalCheck;
947              } else if (setSwitchInterval != nullptr) {
948                  setSwitchInterval(saveLongIntervalCheck);
949              }
950         } else {
951             if(showDebugInfo){
952                 std::cout << "Threads already initialized! " << std::endl << std::flush;
953             }
954         }
955 
956         if (g_heap != nullptr) {
957             HeapDestroy(g_heap);
958             g_heap = nullptr;
959         }
960 
961 
962         GilHolder gilLock(gilEnsure, gilRelease);   // acquire and hold the GIL until done...
963 
964         pyRun_SimpleString(command);
965         return 0;
966 
967     }
968 
969 
970 
971 
SetSysTraceFunc(HMODULE module,bool isDebug,bool showDebugInfo)972     int SetSysTraceFunc(HMODULE module, bool isDebug, bool showDebugInfo)
973     {
974 
975         if(showDebugInfo){
976             std::cout << "SetSysTraceFunc started. " << std::endl << std::flush;
977         }
978         auto isInit = (Py_IsInitialized*)GetProcAddress(module, "Py_IsInitialized");
979 
980         if (isInit == nullptr) {
981             if(showDebugInfo){
982                 std::cout << "Py_IsInitialized not found. " << std::endl << std::flush;
983             }
984             return 1;
985         }
986         if (!isInit()) {
987             if(showDebugInfo){
988                 std::cout << "Py_IsInitialized returned false. " << std::endl << std::flush;
989             }
990             return 2;
991         }
992 
993         auto version = GetPythonVersion(module);
994 
995         // found initialized Python runtime, gather and check the APIs we need for a successful attach...
996         auto addPendingCall = (Py_AddPendingCall*)GetProcAddress(module, "Py_AddPendingCall");
997         auto curPythonThread = (PyThreadState**)(void*)GetProcAddress(module, "_PyThreadState_Current");
998         auto interpHead = (PyInterpreterState_Head*)GetProcAddress(module, "PyInterpreterState_Head");
999         auto gilEnsure = (PyGILState_Ensure*)GetProcAddress(module, "PyGILState_Ensure");
1000         auto gilRelease = (PyGILState_Release*)GetProcAddress(module, "PyGILState_Release");
1001         auto threadHead = (PyInterpreterState_ThreadHead*)GetProcAddress(module, "PyInterpreterState_ThreadHead");
1002         auto initThreads = (PyEval_Lock*)GetProcAddress(module, "PyEval_InitThreads");
1003         auto acquireLock = (PyEval_Lock*)GetProcAddress(module, "PyEval_AcquireLock");
1004         auto releaseLock = (PyEval_Lock*)GetProcAddress(module, "PyEval_ReleaseLock");
1005         auto threadsInited = (PyEval_ThreadsInitialized*)GetProcAddress(module, "PyEval_ThreadsInitialized");
1006         auto threadNext = (PyThreadState_Next*)GetProcAddress(module, "PyThreadState_Next");
1007         auto threadSwap = (PyThreadState_Swap*)GetProcAddress(module, "PyThreadState_Swap");
1008         auto pyDictNew = (PyDict_New*)GetProcAddress(module, "PyDict_New");
1009         auto pyModuleNew = (PyModule_New*)GetProcAddress(module, "PyModule_New");
1010         auto pyModuleGetDict = (PyModule_GetDict*)GetProcAddress(module, "PyModule_GetDict");
1011         auto pyCompileString = (Py_CompileString*)GetProcAddress(module, "Py_CompileString");
1012         auto pyEvalCode = (PyEval_EvalCode*)GetProcAddress(module, "PyEval_EvalCode");
1013         auto getDictItem = (PyDict_GetItemString*)GetProcAddress(module, "PyDict_GetItemString");
1014         auto call = (PyObject_CallFunctionObjArgs*)GetProcAddress(module, "PyObject_CallFunctionObjArgs");
1015         auto getBuiltins = (PyEval_GetBuiltins*)GetProcAddress(module, "PyEval_GetBuiltins");
1016         auto dictSetItem = (PyDict_SetItemString*)GetProcAddress(module, "PyDict_SetItemString");
1017         PyInt_FromLong* intFromLong;
1018         PyString_FromString* strFromString;
1019         PyInt_FromSize_t* intFromSizeT;
1020         if (version >= PythonVersion_30) {
1021             intFromLong = (PyInt_FromLong*)GetProcAddress(module, "PyLong_FromLong");
1022             intFromSizeT = (PyInt_FromSize_t*)GetProcAddress(module, "PyLong_FromSize_t");
1023             if (version >= PythonVersion_33) {
1024                 strFromString = (PyString_FromString*)GetProcAddress(module, "PyUnicode_FromString");
1025             } else {
1026                 strFromString = (PyString_FromString*)GetProcAddress(module, "PyUnicodeUCS2_FromString");
1027             }
1028         } else {
1029             intFromLong = (PyInt_FromLong*)GetProcAddress(module, "PyInt_FromLong");
1030             strFromString = (PyString_FromString*)GetProcAddress(module, "PyString_FromString");
1031             intFromSizeT = (PyInt_FromSize_t*)GetProcAddress(module, "PyInt_FromSize_t");
1032         }
1033         auto intervalCheck = (int*)GetProcAddress(module, "_Py_CheckInterval");
1034         auto errOccurred = (PyErr_Occurred*)GetProcAddress(module, "PyErr_Occurred");
1035         auto pyErrFetch = (PyErr_Fetch*)GetProcAddress(module, "PyErr_Fetch");
1036         auto pyErrRestore = (PyErr_Restore*)GetProcAddress(module, "PyErr_Restore");
1037         auto pyErrPrint = (PyErr_Print*)GetProcAddress(module, "PyErr_Print");
1038         auto pyImportMod = (PyImport_ImportModule*) GetProcAddress(module, "PyImport_ImportModule");
1039         auto pyGetAttr = (PyObject_GetAttrString*)GetProcAddress(module, "PyObject_GetAttrString");
1040         auto pySetAttr = (PyObject_SetAttrString*)GetProcAddress(module, "PyObject_SetAttrString");
1041         auto pyHasAttr = (PyObject_HasAttrString*)GetProcAddress(module, "PyObject_HasAttrString");
1042         auto pyNone = (PyObject*)GetProcAddress(module, "_Py_NoneStruct");
1043         auto getSwitchInterval = (_PyEval_GetSwitchInterval*)GetProcAddress(module, "_PyEval_GetSwitchInterval");
1044         auto setSwitchInterval = (_PyEval_SetSwitchInterval*)GetProcAddress(module, "_PyEval_SetSwitchInterval");
1045         auto boolFromLong = (PyBool_FromLong*)GetProcAddress(module, "PyBool_FromLong");
1046         auto getThreadTls = (PyThread_get_key_value*)GetProcAddress(module, "PyThread_get_key_value");
1047         auto setThreadTls = (PyThread_set_key_value*)GetProcAddress(module, "PyThread_set_key_value");
1048         auto delThreadTls = (PyThread_delete_key_value*)GetProcAddress(module, "PyThread_delete_key_value");
1049         auto pyGilStateEnsure = (PyGILState_EnsureFunc*)GetProcAddress(module, "PyGILState_Ensure");
1050         auto pyGilStateRelease = (PyGILState_ReleaseFunc*)GetProcAddress(module, "PyGILState_Release");
1051         auto PyCFrame_Type = (PyTypeObject*)GetProcAddress(module, "PyCFrame_Type");
1052         auto pyRun_SimpleString = (PyRun_SimpleString*)GetProcAddress(module, "PyRun_SimpleString");
1053 
1054         if (addPendingCall == nullptr || curPythonThread == nullptr || interpHead == nullptr || gilEnsure == nullptr || gilRelease == nullptr || threadHead == nullptr ||
1055             initThreads == nullptr || releaseLock == nullptr || threadsInited == nullptr || threadNext == nullptr || threadSwap == nullptr ||
1056             pyDictNew == nullptr || pyCompileString == nullptr || pyEvalCode == nullptr || getDictItem == nullptr || call == nullptr ||
1057             getBuiltins == nullptr || dictSetItem == nullptr || intFromLong == nullptr || pyErrRestore == nullptr || pyErrFetch == nullptr ||
1058             errOccurred == nullptr || pyImportMod == nullptr || pyGetAttr == nullptr || pyNone == nullptr || pySetAttr == nullptr || boolFromLong == nullptr ||
1059             getThreadTls == nullptr || setThreadTls == nullptr || delThreadTls == nullptr || releaseLock == nullptr ||
1060             pyGilStateEnsure == nullptr || pyGilStateRelease == nullptr || pyRun_SimpleString == nullptr) {
1061                 // we're missing some APIs, we cannot attach.
1062                 if(showDebugInfo){
1063                     std::cout << "Error, missing Python API!! " << std::endl << std::flush;
1064                 }
1065                 return 3;
1066         }
1067 
1068         auto head = interpHead();
1069         if (head == nullptr) {
1070             // this interpreter is loaded but not initialized.
1071             if(showDebugInfo){
1072                 std::cout << "Interpreter not initialized! " << std::endl << std::flush;
1073             }
1074             return 4;
1075         }
1076 
1077         GilHolder gilLock(gilEnsure, gilRelease);   // acquire and hold the GIL until done...
1078 
1079         auto pyTrue = boolFromLong(1);
1080         auto pyFalse = boolFromLong(0);
1081 
1082 
1083         auto pydevdTracingMod = PyObjectHolder(isDebug, pyImportMod("pydevd_tracing"));
1084         if (*pydevdTracingMod == nullptr) {
1085             if(showDebugInfo){
1086                 std::cout << "pydevd_tracing module null! " << std::endl << std::flush;
1087             }
1088             return 7;
1089         }
1090 
1091         if(!pyHasAttr(pydevdTracingMod.ToPython(), "_original_settrace")){
1092             if(showDebugInfo){
1093                 std::cout << "pydevd_tracing module has no _original_settrace! " << std::endl << std::flush;
1094             }
1095             return 8;
1096         }
1097 
1098         auto settrace = PyObjectHolder(isDebug, pyGetAttr(pydevdTracingMod.ToPython(), "_original_settrace"));
1099         if (*settrace == nullptr) {
1100             if(showDebugInfo){
1101                 std::cout << "pydevd_tracing._original_settrace null! " << std::endl << std::flush;
1102             }
1103             return 9;
1104         }
1105 
1106         auto pydevdMod = PyObjectHolder(isDebug, pyImportMod("pydevd"));
1107         if (*pydevdMod == nullptr) {
1108             if(showDebugInfo){
1109                 std::cout << "pydevd module null! " << std::endl << std::flush;
1110             }
1111             return 10;
1112         }
1113 
1114         auto getGlobalDebugger = PyObjectHolder(isDebug, pyGetAttr(pydevdMod.ToPython(), "GetGlobalDebugger"));
1115         if (*getGlobalDebugger == nullptr) {
1116             if(showDebugInfo){
1117                 std::cout << "pydevd.GetGlobalDebugger null! " << std::endl << std::flush;
1118             }
1119             return 11;
1120         }
1121 
1122         auto globalDbg = PyObjectHolder(isDebug, call(getGlobalDebugger.ToPython(), NULL));
1123         if (*globalDbg == nullptr) {
1124             if(showDebugInfo){
1125                 std::cout << "pydevd.GetGlobalDebugger() returned null! " << std::endl << std::flush;
1126             }
1127             return 12;
1128         }
1129 
1130         if(!pyHasAttr(globalDbg.ToPython(), "trace_dispatch")){
1131             if(showDebugInfo){
1132                 std::cout << "pydevd.GetGlobalDebugger() has no attribute trace_dispatch! " << std::endl << std::flush;
1133             }
1134             return 13;
1135         }
1136 
1137         auto traceFunc = PyObjectHolder(isDebug, pyGetAttr(globalDbg.ToPython(), "trace_dispatch"));
1138         if (*traceFunc == nullptr) {
1139             if(showDebugInfo){
1140                 std::cout << "pydevd.GetGlobalDebugger().trace_dispatch returned null! " << std::endl << std::flush;
1141             }
1142             return 14;
1143         }
1144 
1145 
1146 
1147         // we need to walk the thread list each time after we've initialized a thread so that we are always
1148         // dealing w/ a valid thread list (threads can exit when we run code and therefore the current thread
1149         // could be corrupt).  We also don't care about newly created threads as our start_new_thread wrapper
1150         // will handle those.  So we collect the initial set of threads first here so that we don't keep iterating
1151         // if the program is spawning large numbers of threads.
1152         unordered_set<PyThreadState*> initialThreads;
1153         for (auto curThread = threadHead(head); curThread != nullptr; curThread = threadNext(curThread)) {
1154             initialThreads.insert(curThread);
1155         }
1156 
1157         int retVal = 0;
1158         unordered_set<PyThreadState*> seenThreads;
1159         {
1160             // find what index is holding onto the thread state...
1161             auto curPyThread = *curPythonThread;
1162             int threadStateIndex = -1;
1163             for (int i = 0; i < 100000; i++) {
1164                 void* value = getThreadTls(i);
1165                 if (value == curPyThread) {
1166                     threadStateIndex = i;
1167                     break;
1168                 }
1169             }
1170 
1171             bool foundThread;
1172             int processedThreads = 0;
1173             do {
1174                 foundThread = false;
1175                 for (auto curThread = threadHead(head); curThread != nullptr; curThread = threadNext(curThread)) {
1176                     if (initialThreads.find(curThread) == initialThreads.end() ||
1177                         seenThreads.insert(curThread).second == false) {
1178                             continue;
1179                     }
1180                     foundThread = true;
1181                     processedThreads++;
1182 
1183                     long threadId = GetPythonThreadId(version, curThread);
1184                     // skip this thread - it doesn't really have any Python code on it...
1185                     if (threadId != GetCurrentThreadId()) {
1186                         // create new debugger Thread object on our injected thread
1187                         auto pyThreadId = PyObjectHolder(isDebug, intFromLong(threadId));
1188                         PyFrameObject* frame;
1189                         // update all of the frames so they have our trace func
1190                         if (PyThreadState_25_27::IsFor(version)) {
1191                             frame = ((PyThreadState_25_27*)curThread)->frame;
1192                         } else if (PyThreadState_30_33::IsFor(version)) {
1193                             frame = ((PyThreadState_30_33*)curThread)->frame;
1194                         } else if (PyThreadState_34_36::IsFor(version)) {
1195                             frame = ((PyThreadState_34_36*)curThread)->frame;
1196                         }else{
1197                             if(showDebugInfo){
1198                                 std::cout << "Python version not handled! " << version << std::endl << std::flush;
1199                             }
1200                             retVal = 15;
1201                             break;
1202                         }
1203 
1204                         // switch to our new thread so we can call sys.settrace on it...
1205                         // all of the work here needs to be minimal - in particular we shouldn't
1206                         // ever evaluate user defined code as we could end up switching to this
1207                         // thread on the main thread and corrupting state.
1208                         auto prevThreadState = getThreadTls(threadStateIndex);
1209                         delThreadTls(threadStateIndex);
1210                         setThreadTls(threadStateIndex, curThread);
1211                         auto prevThread = threadSwap(curThread);
1212 
1213                         // save and restore the error in case something funky happens...
1214                         auto errOccured = errOccurred();
1215                         PyObject *type, *value, *traceback;
1216                         if (errOccured) {
1217                             pyErrFetch(&type, &value, &traceback);
1218                         }
1219 
1220                         if(showDebugInfo){
1221                             std::cout << "setting trace for thread: " << threadId << std::endl << std::flush;
1222                         }
1223 
1224                         DecRef(call(settrace.ToPython(), traceFunc.ToPython(), NULL), isDebug);
1225 
1226                         if (errOccured) {
1227                             pyErrRestore(type, value, traceback);
1228                         }
1229 
1230                         // update all of the frames so they have our trace func
1231                         auto curFrame = (PyFrameObject*)GetPyObjectPointerNoDebugInfo(isDebug, frame);
1232                         while (curFrame != nullptr) {
1233                             // Special case for CFrame objects
1234                             // Stackless CFrame does not have a trace function
1235                             // This will just prevent a crash on attach.
1236                             if (((PyObject*)curFrame)->ob_type != PyCFrame_Type) {
1237                                 DecRef(curFrame->f_trace, isDebug);
1238                                 IncRef(*traceFunc);
1239                                 curFrame->f_trace = traceFunc.ToPython();
1240                             }
1241                             curFrame = (PyFrameObject*)GetPyObjectPointerNoDebugInfo(isDebug, curFrame->f_back);
1242                         }
1243 
1244                         delThreadTls(threadStateIndex);
1245                         setThreadTls(threadStateIndex, prevThread);
1246                         threadSwap(prevThread);
1247                     }
1248                     break;
1249                 }
1250             } while (foundThread);
1251         }
1252 
1253 
1254 
1255         return retVal;
1256 
1257 	}
1258 
1259 
1260 
1261     /**
1262      * Return codes:
1263      *
1264      * -2 = could not allocate memory
1265      * -3 = could not allocate memory to enumerate processes
1266      *
1267      * 0 = all OK.
1268      * 1 = Py_IsInitialized not found
1269      * 2 = Py_IsInitialized returned false
1270      * 3 = Missing Python API
1271      * 4 = Interpreter not initialized
1272      * 5 = Python version unknown
1273      * 6 = Connect timeout
1274      *
1275      * result[0] should have the same result from the return function
1276      * result[0] is also used to set the startup info (on whether to show debug info
1277      * and if the debugger tracing should be set).
1278      **/
AttachAndRunPythonCode(const char * command,int * result)1279     DECLDIR int AttachAndRunPythonCode(const char *command, int *result )
1280     {
1281 
1282         int SHOW_DEBUG_INFO = 1;
1283         int CONNECT_DEBUGGER = 2;
1284 
1285         bool showDebugInfo = (result[0] & SHOW_DEBUG_INFO) != 0;
1286 
1287         if(showDebugInfo){
1288             std::cout << "AttachAndRunPythonCode started (showing debug info). " << std::endl << std::flush;
1289         }
1290 
1291         bool connectDebuggerTracing = (result[0] & CONNECT_DEBUGGER) != 0;
1292         if(showDebugInfo){
1293             std::cout << "connectDebuggerTracing: " << connectDebuggerTracing << std::endl << std::flush;
1294         }
1295 
1296         HANDLE hProcess = GetCurrentProcess();
1297         DWORD modSize = sizeof(HMODULE) * 1024;
1298         HMODULE* hMods = (HMODULE*)_malloca(modSize);
1299         if (hMods == nullptr) {
1300             result[0] = -2;
1301             return result[0];
1302         }
1303 
1304         DWORD modsNeeded;
1305         while (!EnumProcessModules(hProcess, hMods, modSize, &modsNeeded)) {
1306             // try again w/ more space...
1307             _freea(hMods);
1308             hMods = (HMODULE*)_malloca(modsNeeded);
1309             if (hMods == nullptr) {
1310                 result[0] = -3;
1311                 return result[0];
1312             }
1313             modSize = modsNeeded;
1314         }
1315         int attached = -1;
1316         {
1317              bool pythonFound = false;
1318              for (size_t i = 0; i < modsNeeded / sizeof(HMODULE); i++) {
1319                  bool isDebug;
1320                  if (IsPythonModule(hMods[i], isDebug)) {
1321                      pythonFound = true;
1322                      int temp = DoAttach(hMods[i], isDebug, command, showDebugInfo);
1323                      if (temp == 0) {
1324                          // we've successfully attached the debugger
1325                          attached = 0;
1326                          if(connectDebuggerTracing){
1327                             if(showDebugInfo){
1328                                 std::cout << "SetSysTraceFunc " << std::endl << std::flush;
1329                             }
1330                             attached = SetSysTraceFunc(hMods[i], isDebug, showDebugInfo);
1331                          }
1332                          break;
1333                      }else{
1334                         if(temp > attached){
1335                             //I.e.: the higher the value the more significant it is.
1336                             attached = temp;
1337                          }
1338                      }
1339                  }
1340              }
1341         }
1342 
1343         if(showDebugInfo){
1344             std::cout << "Result: " << attached << std::endl << std::flush;
1345         }
1346         result[0] = attached;
1347         return result[0];
1348     }
1349 
1350 
1351 
1352 
1353 
1354     /**
1355      *
1356      *
1357      *
1358      *
1359      *
1360      **/
AttachDebuggerTracing(bool showDebugInfo)1361     DECLDIR int AttachDebuggerTracing(bool showDebugInfo)
1362     {
1363         HANDLE hProcess = GetCurrentProcess();
1364         DWORD modSize = sizeof(HMODULE) * 1024;
1365         HMODULE* hMods = (HMODULE*)_malloca(modSize);
1366         if (hMods == nullptr) {
1367             if(showDebugInfo){
1368                 std::cout << "hmods not allocated! " << std::endl << std::flush;
1369             }
1370             return -2;
1371         }
1372 
1373         DWORD modsNeeded;
1374         while (!EnumProcessModules(hProcess, hMods, modSize, &modsNeeded)) {
1375             // try again w/ more space...
1376             _freea(hMods);
1377             hMods = (HMODULE*)_malloca(modsNeeded);
1378             if (hMods == nullptr) {
1379                 if(showDebugInfo){
1380                     std::cout << "hmods not allocated (2)! " << std::endl << std::flush;
1381                 }
1382                 return -3;
1383             }
1384             modSize = modsNeeded;
1385         }
1386         int attached = -1;
1387         {
1388             bool pythonFound = false;
1389             for (size_t i = 0; i < modsNeeded / sizeof(HMODULE); i++) {
1390                 bool isDebug;
1391                 if (IsPythonModule(hMods[i], isDebug)) {
1392                     pythonFound = true;
1393                     if(showDebugInfo){
1394                         std::cout << "setting sys trace! " << std::endl << std::flush;
1395                     }
1396                     int temp = SetSysTraceFunc(hMods[i], isDebug, showDebugInfo);
1397                     if (temp == 0) {
1398                         // we've successfully attached the debugger
1399                         attached = 0;
1400                         break;
1401                     }else{
1402                        if(temp > attached){
1403                            //I.e.: the higher the value the more significant it is.
1404                            attached = temp;
1405                         }
1406                     }
1407                 }
1408             }
1409         }
1410 
1411 
1412         return attached;
1413     }
1414 
1415 }